CombinedChannelDuplexHandler extends ChannelDuplexHandler { @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { if (inboundHandler == null) { throw new IllegalStateException( "init() must be invoked before being added to a " + ChannelPipeline.class.getSimpleName() + " if " + CombinedChannelDuplexHandler.class.getSimpleName() + " was constructed with the default constructor."); } outboundCtx = new DelegatingChannelHandlerContext(ctx, outboundHandler); inboundCtx = new DelegatingChannelHandlerContext(ctx, inboundHandler) { @SuppressWarnings("deprecation") @Override public ChannelHandlerContext fireExceptionCaught(Throwable cause) { if (!outboundCtx.removed) { try { outboundHandler.exceptionCaught(outboundCtx, cause); } catch (Throwable error) { if (logger.isDebugEnabled()) { logger.debug( "An exception {}" + "was thrown by a user handler's exceptionCaught() " + "method while handling the following exception:", ThrowableUtil.stackTraceToString(error), cause); } else if (logger.isWarnEnabled()) { logger.warn( "An exception '{}' [enable DEBUG level for full stacktrace] " + "was thrown by a user handler's exceptionCaught() " + "method while handling the following exception:", error, cause); } } } else { super.fireExceptionCaught(cause); } return this; } }; handlerAdded = true; try { inboundHandler.handlerAdded(inboundCtx); } finally { outboundHandler.handlerAdded(outboundCtx); } } 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 testInitNotCalledBeforeAdded() throws Exception { CombinedChannelDuplexHandler<ChannelInboundHandler, ChannelOutboundHandler> handler = new CombinedChannelDuplexHandler<ChannelInboundHandler, ChannelOutboundHandler>() { }; handler.handlerAdded(null); }