//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);
     }
 }
        /// <summary>
        /// Send response using remoting context if necessary.<br>
        /// If request type is oneway, no need to send any response nor exception.
        /// </summary>
        /// <param name="ctx"> remoting context </param>
        /// <param name="type"> type code </param>
        /// <param name="response"> remoting command </param>
        //JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
        //ORIGINAL LINE: public void sendResponseIfNecessary(final RemotingContext ctx, byte type, final RemotingCommand response)
        public virtual void sendResponseIfNecessary(RemotingContext ctx, byte type, RemotingCommand response)
        {
            //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
            //ORIGINAL LINE: final int id = response.getId();
            int id = response.Id;

            if (type != RpcCommandType.REQUEST_ONEWAY)
            {
                RemotingCommand serializedResponse = response;
                try
                {
                    response.serialize();
                }
                catch (SerializationException e)
                {
                    string errMsg = "SerializationException occurred when sendResponseIfNecessary in RpcRequestProcessor, id=" + id;
                    logger.LogError(errMsg, e);
                    serializedResponse = CommandFactory.createExceptionResponse(id, ResponseStatus.SERVER_SERIAL_EXCEPTION, e);
                    try
                    {
                        serializedResponse.serialize(); // serialize again for exception response
                    }
                    catch (SerializationException)
                    {
                        // should not happen
                        logger.LogError("serialize SerializationException response failed!");
                    }
                }
                catch (System.Exception t)
                {
                    string errMsg = "Serialize RpcResponseCommand failed when sendResponseIfNecessary in RpcRequestProcessor, id=" + id;
                    logger.LogError(errMsg, t);
                    serializedResponse = CommandFactory.createExceptionResponse(id, t, errMsg);
                }

                var writeFlushTask = ctx.writeAndFlush(serializedResponse);
                writeFlushTask.ContinueWith((task) =>
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.LogDebug("Rpc response sent! requestId=" + id + ". The address is " + ctx.ChannelContext.Channel.RemoteAddress.ToString());
                    }
                    if (!task.IsCompletedSuccessfully)
                    {
                        logger.LogError("Rpc response send failed! id=" + id + ". The address is " + ctx.ChannelContext.Channel.RemoteAddress.ToString(), task.Exception);
                    }
                });
                //.addListener(new ChannelFutureListenerAnonymousInnerClass(this, ctx, id));
            }
            else
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.LogDebug("Oneway rpc request received, do not send response, id=" + id + ", the address is " + ctx.ChannelContext.Channel.RemoteAddress.ToString());
                }
            }
        }