@Override
 protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
   RequestWrapper request = (RequestWrapper) msg;
   long beginTime = System.currentTimeMillis();
   ResponseWrapper responseWrapper =
       ProtocolFactory.getServerHandler(request.getProtocolType()).handleRequest(request);
   final int id = request.getId();
   // already timeout,so not return
   if ((System.currentTimeMillis() - beginTime) >= request.getTimeout()) {
     LOGGER.warn(
         "timeout,so give up send response to client,requestId is:"
             + id
             + ",client is:"
             + ctx.channel().remoteAddress()
             + ",consumetime is:"
             + (System.currentTimeMillis() - beginTime)
             + ",timeout is:"
             + request.getTimeout());
     return;
   }
   ChannelFuture wf = ctx.channel().writeAndFlush(responseWrapper);
   wf.addListener(
       new ChannelFutureListener() {
         public void operationComplete(ChannelFuture future) throws Exception {
           if (!future.isSuccess()) {
             LOGGER.error("server write response error,request id is: " + id);
           }
         }
       });
 }
 @SuppressWarnings("rawtypes")
 public void run() {
   // pipeline
   if (message instanceof List) {
     List messages = (List) message;
     for (Object messageObject : messages) {
       threadPool.execute(new HandlerRunnable(session, messageObject, threadPool));
     }
   } else {
     RequestWrapper request = (RequestWrapper) message;
     long beginTime = System.currentTimeMillis();
     ResponseWrapper responseWrapper =
         ProtocolFactory.getServerHandler(request.getProtocolType()).handleRequest(request);
     final int id = request.getId();
     // already timeout,so not return
     if ((System.currentTimeMillis() - beginTime) >= request.getTimeout()) {
       LOGGER.warn(
           "timeout,so give up send response to client,requestId is:"
               + id
               + ",client is:"
               + session.getRemoteAddress()
               + ",consumetime is:"
               + (System.currentTimeMillis() - beginTime)
               + ",timeout is:"
               + request.getTimeout());
       return;
     }
     WriteFuture wf = session.write(responseWrapper);
     wf.addListener(
         new IoFutureListener() {
           public void operationComplete(IoFuture future) {
             if (!((WriteFuture) future).isWritten()) {
               LOGGER.error("server write response error,request id is: " + id);
             }
           }
         });
   }
 }
 public ByteBufferWrapper encode(Object message, ByteBufferWrapper bytebufferWrapper)
     throws Exception {
   if (!(message instanceof RequestWrapper) && !(message instanceof ResponseWrapper)) {
     throw new Exception("only support send RequestWrapper && ResponseWrapper");
   }
   int id = 0;
   byte type = REQUEST;
   byte[] body = null;
   int timeout = 0;
   int codecType = 0;
   byte[] className = null;
   if (message instanceof RequestWrapper) {
     try {
       RequestWrapper wrapper = (RequestWrapper) message;
       codecType = wrapper.getCodecType();
       body = Codecs.getEncoder(codecType).encode(wrapper.getMessage());
       id = wrapper.getId();
       timeout = wrapper.getTimeout();
       if (codecType == Codecs.PB_CODEC)
         className = wrapper.getMessage().getClass().getName().getBytes();
     } catch (Exception e) {
       LOGGER.error("encode request object error", e);
       throw e;
     }
   } else {
     ResponseWrapper wrapper = (ResponseWrapper) message;
     try {
       codecType = wrapper.getCodecType();
       body = Codecs.getEncoder(codecType).encode(wrapper.getResponse());
       id = wrapper.getRequestId();
       if (codecType == Codecs.PB_CODEC)
         className = wrapper.getResponse().getClass().getName().getBytes();
     } catch (Exception e) {
       LOGGER.error("encode response object error", e);
       // still create response,so client can get it
       wrapper.setResponse(new Exception("encode response object error", e));
       if (codecType == Codecs.PB_CODEC) className = Exception.class.getName().getBytes();
       body = Codecs.getEncoder(wrapper.getCodecType()).encode(wrapper.getResponse());
     }
     type = RESPONSE;
   }
   int capacity = ProtocolUtils.HEADER_LEN + CUSTOMPROTOCOL_HEADER_LEN + body.length;
   if (codecType == Codecs.PB_CODEC) {
     capacity += className.length;
   }
   ByteBufferWrapper byteBuffer = bytebufferWrapper.get(capacity);
   byteBuffer.writeByte(ProtocolUtils.CURRENT_VERSION);
   byteBuffer.writeByte((byte) TYPE);
   byteBuffer.writeByte(VERSION);
   byteBuffer.writeByte(type);
   byteBuffer.writeByte((byte) codecType);
   byteBuffer.writeByte((byte) 0);
   byteBuffer.writeByte((byte) 0);
   byteBuffer.writeByte((byte) 0);
   byteBuffer.writeInt(id);
   byteBuffer.writeInt(timeout);
   if (codecType == Codecs.PB_CODEC) {
     byteBuffer.writeInt(className.length);
   } else {
     byteBuffer.writeInt(0);
   }
   byteBuffer.writeInt(body.length);
   if (codecType == Codecs.PB_CODEC) byteBuffer.writeBytes(className);
   byteBuffer.writeBytes(body);
   return byteBuffer;
 }