@Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

      Channel channel = new NettyChannel(ctx);

      final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(channel);
      LOGGER.warn("CLIENT : exceptionCaught {}", remoteAddress);
      LOGGER.warn("CLIENT : exceptionCaught exception.", cause);
      closeChannel(channel);
      if (channelEventListener != null) {
        putRemotingEvent(new RemotingEvent(RemotingEventType.EXCEPTION, remoteAddress, channel));
      }
    }
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
      if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;

        Channel channel = new NettyChannel(ctx);

        final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(channel);

        if (event.state().equals(io.netty.handler.timeout.IdleState.ALL_IDLE)) {
          LOGGER.warn("CLIENT : IDLE [{}]", remoteAddress);
          closeChannel(channel);
        }

        if (channelEventListener != null) {
          RemotingEventType remotingEventType = RemotingEventType.valueOf(event.state().name());
          putRemotingEvent(new RemotingEvent(remotingEventType, remoteAddress, channel));
        }
      }

      ctx.fireUserEventTriggered(evt);
    }