CombinedChannelDuplexHandler extends ChannelDuplexHandler { public final void removeOutboundHandler() { checkAdded(); outboundCtx.remove(); } protected  CombinedChannelDuplexHandler();  CombinedChannelDuplexHandler(I inboundHandler, O outboundHandler); final void removeInboundHandler(); final void removeOutboundHandler(); @Override void handlerAdded(ChannelHandlerContext ctx); @Override void handlerRemoved(ChannelHandlerContext ctx); @Override void channelRegistered(ChannelHandlerContext ctx); @Override void channelUnregistered(ChannelHandlerContext ctx); @Override void channelActive(ChannelHandlerContext ctx); @Override void channelInactive(ChannelHandlerContext ctx); @Override void exceptionCaught(ChannelHandlerContext ctx, Throwable cause); @Override void userEventTriggered(ChannelHandlerContext ctx, Object evt); @Override void channelRead(ChannelHandlerContext ctx, Object msg); @Override void channelReadComplete(ChannelHandlerContext ctx); @Override void channelWritabilityChanged(ChannelHandlerContext ctx); @Override void bind(
            ChannelHandlerContext ctx,
            SocketAddress localAddress, ChannelPromise promise); @Override void connect(
            ChannelHandlerContext ctx,
            SocketAddress remoteAddress, SocketAddress localAddress,
            ChannelPromise promise); @Override void disconnect(ChannelHandlerContext ctx, ChannelPromise promise); @Override void close(ChannelHandlerContext ctx, ChannelPromise promise); @Override void deregister(ChannelHandlerContext ctx, ChannelPromise promise); @Override void read(ChannelHandlerContext ctx); @Override void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise); @Override void flush(ChannelHandlerContext ctx);  }
@Test(expected = IllegalStateException.class) public void testOutboundRemoveBeforeAdded() { CombinedChannelDuplexHandler<ChannelInboundHandler, ChannelOutboundHandler> handler = new CombinedChannelDuplexHandler<ChannelInboundHandler, ChannelOutboundHandler>( new ChannelInboundHandlerAdapter(), new ChannelOutboundHandlerAdapter()); handler.removeOutboundHandler(); }
@Test public void testOutboundEvents() { final Queue<Event> queue = new ArrayDeque<Event>(); ChannelInboundHandler inboundHandler = new ChannelInboundHandlerAdapter(); ChannelOutboundHandler outboundHandler = new ChannelOutboundHandlerAdapter() { @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { queue.add(Event.HANDLER_ADDED); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { queue.add(Event.HANDLER_REMOVED); } @Override public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { queue.add(Event.BIND); } @Override public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { queue.add(Event.CONNECT); } @Override public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { queue.add(Event.DISCONNECT); } @Override public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { queue.add(Event.CLOSE); } @Override public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { queue.add(Event.DEREGISTER); } @Override public void read(ChannelHandlerContext ctx) throws Exception { queue.add(Event.READ); } @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { queue.add(Event.WRITE); } @Override public void flush(ChannelHandlerContext ctx) throws Exception { queue.add(Event.FLUSH); } }; CombinedChannelDuplexHandler<ChannelInboundHandler, ChannelOutboundHandler> handler = new CombinedChannelDuplexHandler<ChannelInboundHandler, ChannelOutboundHandler>( inboundHandler, outboundHandler); EmbeddedChannel channel = new EmbeddedChannel(); channel.pipeline().addFirst(handler); doOutboundOperations(channel); assertEquals(Event.HANDLER_ADDED, queue.poll()); assertEquals(Event.BIND, queue.poll()); assertEquals(Event.CONNECT, queue.poll()); assertEquals(Event.WRITE, queue.poll()); assertEquals(Event.FLUSH, queue.poll()); assertEquals(Event.READ, queue.poll()); assertEquals(Event.CLOSE, queue.poll()); assertEquals(Event.CLOSE, queue.poll()); assertEquals(Event.DEREGISTER, queue.poll()); handler.removeOutboundHandler(); assertEquals(Event.HANDLER_REMOVED, queue.poll()); doOutboundOperations(channel); assertTrue(queue.isEmpty()); assertTrue(channel.finish()); assertTrue(queue.isEmpty()); }