@Test
	public void testReadingCallable() throws Exception {

		// Exit gracefully on close

		Pipe pipe = Pipe.open();

		final SourceChannel sourceChannel = pipe.source();
		SinkChannel sinkChannel = pipe.sink();

		try {
			MockRegistrationReference mockRegistrationReference =
				new MockRegistrationReference(_executorIntraband);

			ChannelContext channelContext = new ChannelContext(
				new LinkedList<Datagram>());

			channelContext.setRegistrationReference(mockRegistrationReference);

			ReadingCallable readingCallable =
				_executorIntraband.new ReadingCallable(
					sourceChannel, channelContext);

			SyncThrowableThread<Void> syncThrowableThread =
				new SyncThrowableThread<>(
					new Callable<Void>() {

						@Override
						public Void call() throws Exception {
							sleep(100);

							sourceChannel.close();

							return null;
						}

					});

			syncThrowableThread.start();

			readingCallable.openLatch();

			Void result = readingCallable.call();

			syncThrowableThread.sync();

			Assert.assertNull(result);
			Assert.assertFalse(mockRegistrationReference.isValid());
		}
		finally {
			sourceChannel.close();
			sinkChannel.close();
		}
	}
  @Test
  public void testRegisterChannelReadWrite() throws Exception {

    // Scattering byte channel is null

    try {
      _selectorIntraband.registerChannel(null, null);

      Assert.fail();
    } catch (NullPointerException npe) {
      Assert.assertEquals("Scattering byte channel is null", npe.getMessage());
    }

    // Gathering byte channel is null

    try {
      _selectorIntraband.registerChannel(
          IntrabandTestUtil.<ScatteringByteChannel>createProxy(ScatteringByteChannel.class), null);

      Assert.fail();
    } catch (NullPointerException npe) {
      Assert.assertEquals("Gathering byte channel is null", npe.getMessage());
    }

    // Scattering byte channel is not of type SelectableChannel

    try {
      _selectorIntraband.registerChannel(
          IntrabandTestUtil.<ScatteringByteChannel>createProxy(ScatteringByteChannel.class),
          IntrabandTestUtil.<GatheringByteChannel>createProxy(GatheringByteChannel.class));

      Assert.fail();
    } catch (IllegalArgumentException iae) {
      Assert.assertEquals(
          "Scattering byte channel is not of type SelectableChannel", iae.getMessage());
    }

    // Gathering byte channel is not of type SelectableChannel

    try {
      _selectorIntraband.registerChannel(
          new MockDuplexSelectableChannel(false, false),
          IntrabandTestUtil.<GatheringByteChannel>createProxy(GatheringByteChannel.class));

      Assert.fail();
    } catch (IllegalArgumentException iae) {
      Assert.assertEquals(
          "Gathering byte channel is not of type SelectableChannel", iae.getMessage());
    }

    // Scattering byte channel is not valid for reading

    try {
      _selectorIntraband.registerChannel(
          new MockDuplexSelectableChannel(false, true),
          new MockDuplexSelectableChannel(true, true));

      Assert.fail();
    } catch (IllegalArgumentException iae) {
      Assert.assertEquals("Scattering byte channel is not valid for reading", iae.getMessage());
    }

    // Gathering byte channel is not valid for writing

    try {
      _selectorIntraband.registerChannel(
          new MockDuplexSelectableChannel(true, true),
          new MockDuplexSelectableChannel(true, false));

      Assert.fail();
    } catch (IllegalArgumentException iae) {
      Assert.assertEquals("Gathering byte channel is not valid for writing", iae.getMessage());
    }

    // Interruptted on register

    Pipe pipe = Pipe.open();

    SourceChannel sourceChannel = pipe.source();
    SinkChannel sinkChannel = pipe.sink();

    final Thread mainThread = Thread.currentThread();

    Thread wakeUpThread = new Thread(new WakeUpRunnable(_selectorIntraband));

    Thread interruptThread =
        new Thread() {

          @Override
          public void run() {
            while (mainThread.getState() != Thread.State.WAITING) ;

            mainThread.interrupt();
          }
        };

    wakeUpThread.start();

    Selector selector = _selectorIntraband.selector;

    synchronized (selector) {
      wakeUpThread.interrupt();
      wakeUpThread.join();

      interruptThread.start();

      try {
        _selectorIntraband.registerChannel(sourceChannel, sinkChannel);

        Assert.fail();
      } catch (IOException ioe) {
        Throwable cause = ioe.getCause();

        Assert.assertTrue(cause instanceof InterruptedException);
      }

      interruptThread.join();
    }

    _selectorIntraband.close();

    // Normal register

    _selectorIntraband = new SelectorIntraband(_DEFAULT_TIMEOUT);

    SelectionKeyRegistrationReference selectionKeyRegistrationReference =
        (SelectionKeyRegistrationReference)
            _selectorIntraband.registerChannel(sourceChannel, sinkChannel);

    Assert.assertNotNull(selectionKeyRegistrationReference);

    SelectionKey readSelectionKey = selectionKeyRegistrationReference.readSelectionKey;

    Assert.assertTrue(readSelectionKey.isValid());
    Assert.assertEquals(SelectionKey.OP_READ, readSelectionKey.interestOps());
    Assert.assertNotNull(readSelectionKey.attachment());

    SelectionKey writeSelectionKey = selectionKeyRegistrationReference.writeSelectionKey;

    Assert.assertTrue(writeSelectionKey.isValid());
    Assert.assertEquals(0, writeSelectionKey.interestOps());
    Assert.assertNotNull(writeSelectionKey.attachment());
    Assert.assertSame(readSelectionKey.attachment(), writeSelectionKey.attachment());

    writeSelectionKey.interestOps(SelectionKey.OP_WRITE);

    selector = _selectorIntraband.selector;

    selector.wakeup();

    while (writeSelectionKey.interestOps() != 0) ;

    unregisterChannels(selectionKeyRegistrationReference);

    // Register after close

    _selectorIntraband.close();

    try {
      _selectorIntraband.registerChannel(sourceChannel, sinkChannel);

      Assert.fail();
    } catch (ClosedIntrabandException cibe) {
    }

    sourceChannel.close();
    sinkChannel.close();
  }