//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
 //ORIGINAL LINE: @Override public void doProcess(final RemotingContext ctx, RemotingCommand msg)
 public override void doProcess(RemotingContext ctx, RemotingCommand msg)
 {
     if (msg is HeartbeatCommand)
     { // process the heartbeat
       //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
       //ORIGINAL LINE: final int id = msg.getId();
         int id = msg.Id;
         if (logger.IsEnabled(LogLevel.Debug))
         {
             logger.LogDebug("Heartbeat received! Id=" + id + ", from " + ctx.ChannelContext.Channel.RemoteAddress.ToString());
         }
         HeartbeatAckCommand ack = new HeartbeatAckCommand();
         ack.Id = id;
         var writeFlushTask = ctx.writeAndFlush(ack);
         writeFlushTask.ContinueWith((task) =>
         {
             if (task.IsCompletedSuccessfully)
             {
                 if (logger.IsEnabled(LogLevel.Debug))
                 {
                     logger.LogDebug("Send heartbeat ack done! Id={}, to remoteAddr={}", id, ctx.ChannelContext.Channel.RemoteAddress.ToString());
                 }
             }
             else
             {
                 logger.LogError("Send heartbeat ack failed! Id={}, to remoteAddr={}", id, ctx.ChannelContext.Channel.RemoteAddress.ToString());
             }
         });
         //.addListener(new ChannelFutureListenerAnonymousInnerClass(this, ctx, id));
     }
     else if (msg is HeartbeatAckCommand)
     {
         Connection   conn   = (Connection)ctx.ChannelContext.Channel.GetAttribute(Connection.CONNECTION).Get();
         InvokeFuture future = conn.removeInvokeFuture(msg.Id);
         if (future != null)
         {
             future.putResponse(msg);
             future.cancelTimeout();
             try
             {
                 future.executeInvokeCallback();
             }
             catch (Exception e)
             {
                 logger.LogError("Exception caught when executing heartbeat invoke callback. From {}", ctx.ChannelContext.Channel.RemoteAddress.ToString(), e);
             }
         }
         else
         {
             logger.LogWarning("Cannot find heartbeat InvokeFuture, maybe already timeout. Id={}, From {}", msg.Id, ctx.ChannelContext.Channel.RemoteAddress.ToString());
         }
     }
     else
     {
         //JAVA TO C# CONVERTER WARNING: The .NET Type.FullName property will not always yield results identical to the Java Class.getName method:
         throw new Exception("Cannot process command: " + msg.GetType().FullName);
     }
 }
        /// <seealso cref= CommandDecoder#decode(IChannelHandlerContext, IByteBuffer, List<object>) </seealso>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: @Override public void decode(io.netty.channel.IChannelHandlerContext ctx, io.netty.buffer.IByteBuffer in, java.util.List<object><Object> out) throws Exception
        public virtual void decode(IChannelHandlerContext ctx, IByteBuffer @in, List <object> @out)
        {
            // the less length between response header and request header
            if (@in.ReadableBytes >= lessLen)
            {
                @in.MarkReaderIndex();
                byte protocol = @in.ReadByte();
                @in.ResetReaderIndex();
                if (protocol == RpcProtocolV2.PROTOCOL_CODE)
                {
                    /*
                     * ver: version for protocol
                     * type: request/response/request oneway
                     * cmdcode: code for remoting command
                     * ver2:version for remoting command
                     * requestId: id of request
                     * codec: code for codec
                     * switch: function switch
                     * (req)timeout: request timeout
                     * (resp)respStatus: response status
                     * classLen: length of request or response class name
                     * headerLen: length of header
                     * contentLen: length of content
                     * className
                     * header
                     * content
                     */
                    if (@in.ReadableBytes > 2 + 1)
                    {
                        int startIndex = @in.ReaderIndex;
                        @in.MarkReaderIndex();
                        @in.ReadByte();                         //protocol code
                        byte version = @in.ReadByte();          //protocol version
                        byte type    = @in.ReadByte();          //type
                        if (type == RpcCommandType.REQUEST || type == RpcCommandType.REQUEST_ONEWAY)
                        {
                            //decode request
                            if (@in.ReadableBytes >= RpcProtocolV2.RequestHeaderLength - 3)
                            {
                                short  cmdCode             = @in.ReadShort();
                                byte   ver2                = @in.ReadByte();
                                int    requestId           = @in.ReadInt();
                                byte   serializer          = @in.ReadByte();
                                byte   protocolSwitchValue = @in.ReadByte();
                                int    timeout             = @in.ReadInt();
                                short  classLen            = @in.ReadShort();
                                short  headerLen           = @in.ReadShort();
                                int    contentLen          = @in.ReadInt();
                                byte[] clazz               = null;
                                byte[] header              = null;
                                byte[] content             = null;

                                // decide the at-least bytes length for each version
                                int  lengthAtLeastForV1 = classLen + headerLen + contentLen;
                                bool crcSwitchOn        = ProtocolSwitch.isOn(ProtocolSwitch.CRC_SWITCH_INDEX, protocolSwitchValue);
                                int  lengthAtLeastForV2 = classLen + headerLen + contentLen;
                                if (crcSwitchOn)
                                {
                                    lengthAtLeastForV2 += 4;                                     // crc int
                                }

                                // continue read
                                if ((version == RpcProtocolV2.PROTOCOL_VERSION_1 && @in.ReadableBytes >= lengthAtLeastForV1) || (version == RpcProtocolV2.PROTOCOL_VERSION_2 && @in.ReadableBytes >= lengthAtLeastForV2))
                                {
                                    if (classLen > 0)
                                    {
                                        clazz = new byte[classLen];
                                        @in.ReadBytes(clazz);
                                    }
                                    if (headerLen > 0)
                                    {
                                        header = new byte[headerLen];
                                        @in.ReadBytes(header);
                                    }
                                    if (contentLen > 0)
                                    {
                                        content = new byte[contentLen];
                                        @in.ReadBytes(content);
                                    }
                                    if (version == RpcProtocolV2.PROTOCOL_VERSION_2 && crcSwitchOn)
                                    {
                                        checkCRC(@in, startIndex);
                                    }
                                }
                                else
                                {                                 // not enough data
                                    @in.ResetReaderIndex();
                                    return;
                                }
                                RequestCommand command;
                                if (cmdCode == CommandCode_Fields.HEARTBEAT_VALUE)
                                {
                                    command = new HeartbeatCommand();
                                }
                                else
                                {
                                    command = createRequestCommand(cmdCode);
                                }
                                command.Type           = type;
                                command.Version        = ver2;
                                command.Id             = requestId;
                                command.Serializer     = serializer;
                                command.ProtocolSwitch = ProtocolSwitch.create(protocolSwitchValue);
                                command.Timeout        = timeout;
                                command.Clazz          = clazz;
                                command.Header         = header;
                                command.Content        = content;

                                @out.Add(command);
                            }
                            else
                            {
                                @in.ResetReaderIndex();
                            }
                        }
                        else if (type == RpcCommandType.RESPONSE)
                        {
                            //decode response
                            if (@in.ReadableBytes >= RpcProtocolV2.ResponseHeaderLength - 3)
                            {
                                short  cmdCode             = @in.ReadShort();
                                byte   ver2                = @in.ReadByte();
                                int    requestId           = @in.ReadInt();
                                byte   serializer          = @in.ReadByte();
                                byte   protocolSwitchValue = @in.ReadByte();
                                short  status              = @in.ReadShort();
                                short  classLen            = @in.ReadShort();
                                short  headerLen           = @in.ReadShort();
                                int    contentLen          = @in.ReadInt();
                                byte[] clazz               = null;
                                byte[] header              = null;
                                byte[] content             = null;

                                // decide the at-least bytes length for each version
                                int  lengthAtLeastForV1 = classLen + headerLen + contentLen;
                                bool crcSwitchOn        = ProtocolSwitch.isOn(ProtocolSwitch.CRC_SWITCH_INDEX, protocolSwitchValue);
                                int  lengthAtLeastForV2 = classLen + headerLen + contentLen;
                                if (crcSwitchOn)
                                {
                                    lengthAtLeastForV2 += 4;                                     // crc int
                                }

                                // continue read
                                if ((version == RpcProtocolV2.PROTOCOL_VERSION_1 && @in.ReadableBytes >= lengthAtLeastForV1) || (version == RpcProtocolV2.PROTOCOL_VERSION_2 && @in.ReadableBytes >= lengthAtLeastForV2))
                                {
                                    if (classLen > 0)
                                    {
                                        clazz = new byte[classLen];
                                        @in.ReadBytes(clazz);
                                    }
                                    if (headerLen > 0)
                                    {
                                        header = new byte[headerLen];
                                        @in.ReadBytes(header);
                                    }
                                    if (contentLen > 0)
                                    {
                                        content = new byte[contentLen];
                                        @in.ReadBytes(content);
                                    }
                                    if (version == RpcProtocolV2.PROTOCOL_VERSION_2 && crcSwitchOn)
                                    {
                                        checkCRC(@in, startIndex);
                                    }
                                }
                                else
                                {                                 // not enough data
                                    @in.ResetReaderIndex();
                                    return;
                                }
                                ResponseCommand command;
                                if (cmdCode == CommandCode_Fields.HEARTBEAT_VALUE)
                                {
                                    command = new HeartbeatAckCommand();
                                }
                                else
                                {
                                    command = createResponseCommand(cmdCode);
                                }
                                command.Type               = type;
                                command.Version            = ver2;
                                command.Id                 = requestId;
                                command.Serializer         = serializer;
                                command.ProtocolSwitch     = ProtocolSwitch.create(protocolSwitchValue);
                                command.ResponseStatus     = (ResponseStatus)status;
                                command.Clazz              = clazz;
                                command.Header             = header;
                                command.Content            = content;
                                command.ResponseTimeMillis = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
                                command.ResponseHost       = (IPEndPoint)ctx.Channel.RemoteAddress;

                                @out.Add(command);
                            }
                            else
                            {
                                @in.ResetReaderIndex();
                            }
                        }
                        else
                        {
                            string emsg = "Unknown command type: " + type;
                            logger.LogError(emsg);
                            throw new Exception(emsg);
                        }
                    }
                }
                else
                {
                    string emsg = "Unknown protocol: " + protocol;
                    logger.LogError(emsg);
                    throw new Exception(emsg);
                }
            }
        }
 /// <seealso cref= CommandDecoder#decode(io.netty.channel.IChannelHandlerContext, io.netty.buffer.IByteBuffer, java.util.List<object>) </seealso>
 //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
 //ORIGINAL LINE: @Override public void decode(io.netty.channel.IChannelHandlerContext ctx, io.netty.buffer.IByteBuffer in, java.util.List<object><Object> out) throws Exception
 public virtual void decode(IChannelHandlerContext ctx, IByteBuffer @in, List <object> @out)
 {
     // the less length between response header and request header
     if (@in.ReadableBytes >= lessLen)
     {
         @in.MarkReaderIndex();
         byte protocol = @in.ReadByte();
         @in.ResetReaderIndex();
         if (protocol == RpcProtocol.PROTOCOL_CODE)
         {
             /*
              * ver: version for protocol
              * type: request/response/request oneway
              * cmdcode: code for remoting command
              * ver2:version for remoting command
              * requestId: id of request
              * codec: code for codec
              * (req)timeout: request timeout
              * (resp)respStatus: response status
              * classLen: length of request or response class name
              * headerLen: length of header
              * contentLen: length of content
              * className
              * header
              * content
              */
             if (@in.ReadableBytes > 2)
             {
                 @in.MarkReaderIndex();
                 @in.ReadByte();             //version
                 byte type = @in.ReadByte(); //type
                 if (type == RpcCommandType.REQUEST || type == RpcCommandType.REQUEST_ONEWAY)
                 {
                     //decode request
                     if (@in.ReadableBytes >= RpcProtocol.RequestHeaderLength - 2)
                     {
                         short  cmdCode    = @in.ReadShort();
                         byte   ver2       = @in.ReadByte();
                         int    requestId  = @in.ReadInt();
                         byte   serializer = @in.ReadByte();
                         int    timeout    = @in.ReadInt();
                         short  classLen   = @in.ReadShort();
                         short  headerLen  = @in.ReadShort();
                         int    contentLen = @in.ReadInt();
                         byte[] clazz      = null;
                         byte[] header     = null;
                         byte[] content    = null;
                         if (@in.ReadableBytes >= classLen + headerLen + contentLen)
                         {
                             if (classLen > 0)
                             {
                                 clazz = new byte[classLen];
                                 @in.ReadBytes(clazz);
                             }
                             if (headerLen > 0)
                             {
                                 header = new byte[headerLen];
                                 @in.ReadBytes(header);
                             }
                             if (contentLen > 0)
                             {
                                 content = new byte[contentLen];
                                 @in.ReadBytes(content);
                             }
                         }
                         else
                         { // not enough data
                             @in.ResetReaderIndex();
                             return;
                         }
                         RequestCommand command;
                         if (cmdCode == (short)CommonCommandCode.__Enum.HEARTBEAT)
                         {
                             command = new HeartbeatCommand();
                         }
                         else
                         {
                             command = createRequestCommand(cmdCode);
                         }
                         command.Type       = type;
                         command.Version    = ver2;
                         command.Id         = requestId;
                         command.Serializer = serializer;
                         command.Timeout    = timeout;
                         command.Clazz      = clazz;
                         command.Header     = header;
                         command.Content    = content;
                         @out.Add(command);
                     }
                     else
                     {
                         @in.ResetReaderIndex();
                     }
                 }
                 else if (type == RpcCommandType.RESPONSE)
                 {
                     //decode response
                     if (@in.ReadableBytes >= RpcProtocol.ResponseHeaderLength - 2)
                     {
                         short  cmdCode    = @in.ReadShort();
                         byte   ver2       = @in.ReadByte();
                         int    requestId  = @in.ReadInt();
                         byte   serializer = @in.ReadByte();
                         short  status     = @in.ReadShort();
                         short  classLen   = @in.ReadShort();
                         short  headerLen  = @in.ReadShort();
                         int    contentLen = @in.ReadInt();
                         byte[] clazz      = null;
                         byte[] header     = null;
                         byte[] content    = null;
                         if (@in.ReadableBytes >= classLen + headerLen + contentLen)
                         {
                             if (classLen > 0)
                             {
                                 clazz = new byte[classLen];
                                 @in.ReadBytes(clazz);
                             }
                             if (headerLen > 0)
                             {
                                 header = new byte[headerLen];
                                 @in.ReadBytes(header);
                             }
                             if (contentLen > 0)
                             {
                                 content = new byte[contentLen];
                                 @in.ReadBytes(content);
                             }
                         }
                         else
                         { // not enough data
                             @in.ResetReaderIndex();
                             return;
                         }
                         ResponseCommand command;
                         if (cmdCode == (short)CommonCommandCode.__Enum.HEARTBEAT)
                         {
                             command = new HeartbeatAckCommand();
                         }
                         else
                         {
                             command = createResponseCommand(cmdCode);
                         }
                         command.Type               = type;
                         command.Version            = ver2;
                         command.Id                 = requestId;
                         command.Serializer         = serializer;
                         command.ResponseStatus     = (ResponseStatus)status;
                         command.Clazz              = clazz;
                         command.Header             = header;
                         command.Content            = content;
                         command.ResponseTimeMillis = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
                         command.ResponseHost       = (IPEndPoint)ctx.Channel.RemoteAddress;
                         @out.Add(command);
                     }
                     else
                     {
                         @in.ResetReaderIndex();
                     }
                 }
                 else
                 {
                     string emsg = "Unknown command type: " + type;
                     logger.LogError(emsg);
                     throw new Exception(emsg);
                 }
             }
         }
         else
         {
             string emsg = "Unknown protocol: " + protocol;
             logger.LogError(emsg);
             throw new Exception(emsg);
         }
     }
 }