private RemotingCommand getAllTopicConfig(ChannelHandlerContext ctx, RemotingCommand request) {
    final RemotingCommand response =
        RemotingCommand.createResponseCommand(GetAllTopicConfigResponseHeader.class);
    final GetAllTopicConfigResponseHeader responseHeader =
        (GetAllTopicConfigResponseHeader) response.getCustomHeader();

    String content = this.brokerController.getTopicConfigManager().encode();
    if (content != null && content.length() > 0) {
      try {
        response.setBody(content.getBytes(MixAll.DEFAULT_CHARSET));
      } catch (UnsupportedEncodingException e) {
        log.error("", e);

        response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
        response.setRemark("UnsupportedEncodingException " + e);
        return response;
      }
    } else {
      log.error("No topic in this broker, client: " + ctx.channel().remoteAddress());
      response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
      response.setRemark("No topic in this broker");
      return response;
    }

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);

    return response;
  }
  public void unregisterBroker( //
      final String namesrvAddr, //
      final String clusterName, // 1
      final String brokerAddr, // 2
      final String brokerName, // 3
      final long brokerId // 4
      )
      throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
          InterruptedException, MQBrokerException {
    UnRegisterBrokerRequestHeader requestHeader = new UnRegisterBrokerRequestHeader();
    requestHeader.setBrokerAddr(brokerAddr);
    requestHeader.setBrokerId(brokerId);
    requestHeader.setBrokerName(brokerName);
    requestHeader.setClusterName(clusterName);
    RemotingCommand request =
        RemotingCommand.createRequestCommand(MQRequestCode.UNREGISTER_BROKER_VALUE, requestHeader);

    RemotingCommand response = this.remotingClient.invokeSync(namesrvAddr, request, 3000);
    assert response != null;
    switch (response.getCode()) {
      case ResponseCode.SUCCESS_VALUE:
        {
          return;
        }
      default:
        break;
    }

    throw new MQBrokerException(response.getCode(), response.getRemark());
  }
  private RemotingCommand getAllDelayOffset(ChannelHandlerContext ctx, RemotingCommand request) {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);

    String content =
        ((DefaultMessageStore) this.brokerController.getMessageStore())
            .getScheduleMessageService()
            .encode();
    if (content != null && content.length() > 0) {
      try {
        response.setBody(content.getBytes(MixAll.DEFAULT_CHARSET));
      } catch (UnsupportedEncodingException e) {
        log.error("get all delay offset from master error.", e);

        response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
        response.setRemark("UnsupportedEncodingException " + e);
        return response;
      }
    } else {
      log.error("No delay offset in this broker, client: " + ctx.channel().remoteAddress());
      response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
      response.setRemark("No delay offset in this broker");
      return response;
    }

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);

    return response;
  }
  private void returnResponse(
      final String group,
      final String topic,
      ChannelHandlerContext ctx,
      final RemotingCommand response,
      final List<MessageExt> msgList) {
    if (null != msgList) {
      ByteBuffer[] msgBufferList = new ByteBuffer[msgList.size()];
      int bodyTotalSize = 0;
      for (int i = 0; i < msgList.size(); i++) {
        try {
          msgBufferList[i] = messageToByteBuffer(msgList.get(i));
          bodyTotalSize += msgBufferList[i].capacity();
        } catch (Exception e) {
          log.error("messageToByteBuffer UnsupportedEncodingException", e);
        }
      }

      ByteBuffer body = ByteBuffer.allocate(bodyTotalSize);
      for (ByteBuffer bb : msgBufferList) {
        bb.flip();
        body.put(bb);
      }

      response.setBody(body.array());

      // 统计
      this.filtersrvController
          .getFilterServerStatsManager()
          .incGroupGetNums(group, topic, msgList.size());

      this.filtersrvController
          .getFilterServerStatsManager()
          .incGroupGetSize(group, topic, bodyTotalSize);
    }

    try {
      ctx.writeAndFlush(response)
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                  if (!future.isSuccess()) {
                    log.error(
                        "FilterServer response to " + future.channel().remoteAddress() + " failed",
                        future.cause());
                    log.error(response.toString());
                  }
                }
              });
    } catch (Throwable e) {
      log.error("FilterServer process request over, but response failed", e);
      log.error(response.toString());
    }
  }
  private RemotingCommand getAllSubscriptionGroup(
      ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    String content = this.brokerController.getSubscriptionGroupManager().encode();
    if (content != null && content.length() > 0) {
      try {
        response.setBody(content.getBytes(MixAll.DEFAULT_CHARSET));
      } catch (UnsupportedEncodingException e) {
        log.error("", e);

        response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
        response.setRemark("UnsupportedEncodingException " + e);
        return response;
      }
    } else {
      log.error("No subscription group in this broker, client: " + ctx.channel().remoteAddress());
      response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
      response.setRemark("No subscription group in this broker");
      return response;
    }

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);

    return response;
  }
  public void processResponseCommand(ChannelHandlerContext ctx, RemotingCommand cmd) {
    final ResponseFuture responseFuture = responseTable.get(cmd.getOpaque());
    if (responseFuture != null) {
      responseFuture.setResponseCommand(cmd);

      responseFuture.release();

      // 异步调用
      if (responseFuture.getInvokeCallback() != null) {
        boolean runInThisThread = false;
        ExecutorService executor = this.getCallbackExecutor();
        if (executor != null) {
          try {
            executor.submit(
                new Runnable() {
                  @Override
                  public void run() {
                    try {
                      responseFuture.executeInvokeCallback();
                    } catch (Throwable e) {
                      plog.warn("excute callback in executor exception, and callback throw", e);
                    }
                  }
                });
          } catch (Exception e) {
            runInThisThread = true;
            plog.warn("excute callback in executor exception, maybe executor busy", e);
          }
        } else {
          runInThisThread = true;
        }

        if (runInThisThread) {
          try {
            responseFuture.executeInvokeCallback();
          } catch (Throwable e) {
            plog.warn("executeInvokeCallback Exception", e);
          }
        }
      }
      // 同步调用
      else {
        responseFuture.putResponse(cmd);
      }
    } else {
      plog.warn(
          "receive response, but not matched any request, "
              + RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
      plog.warn(cmd.toString());
    }

    responseTable.remove(cmd.getOpaque());
  }
  public RemotingCommand invokeSyncImpl(
      final Channel channel, final RemotingCommand request, final long timeoutMillis)
      throws InterruptedException, RemotingSendRequestException, RemotingTimeoutException {
    try {
      final ResponseFuture responseFuture =
          new ResponseFuture(request.getOpaque(), timeoutMillis, null, null);
      this.responseTable.put(request.getOpaque(), responseFuture);
      channel
          .writeAndFlush(request)
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture f) throws Exception {
                  if (f.isSuccess()) {
                    responseFuture.setSendRequestOK(true);
                    return;
                  } else {
                    responseFuture.setSendRequestOK(false);
                  }

                  responseTable.remove(request.getOpaque());
                  responseFuture.setCause(f.cause());
                  responseFuture.putResponse(null);
                  plog.warn(
                      "send a request command to channel <"
                          + channel.remoteAddress()
                          + "> failed.");
                  plog.warn(request.toString());
                }
              });

      RemotingCommand responseCommand = responseFuture.waitResponse(timeoutMillis);
      if (null == responseCommand) {
        // 发送请求成功,读取应答超时
        if (responseFuture.isSendRequestOK()) {
          throw new RemotingTimeoutException(
              RemotingHelper.parseChannelRemoteAddr(channel),
              timeoutMillis,
              responseFuture.getCause());
        }
        // 发送请求失败
        else {
          throw new RemotingSendRequestException(
              RemotingHelper.parseChannelRemoteAddr(channel), responseFuture.getCause());
        }
      }

      return responseCommand;
    } finally {
      this.responseTable.remove(request.getOpaque());
    }
  }
  private RemotingCommand getBrokerRuntimeInfo(ChannelHandlerContext ctx, RemotingCommand request) {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);

    HashMap<String, String> runtimeInfo = this.prepareRuntimeInfo();
    KVTable kvTable = new KVTable();
    kvTable.setTable(runtimeInfo);

    byte[] body = kvTable.encode();
    response.setBody(body);
    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  private RemotingCommand getBrokerConfig(ChannelHandlerContext ctx, RemotingCommand request) {

    final RemotingCommand response =
        RemotingCommand.createResponseCommand(GetBrokerConfigResponseHeader.class);
    final GetBrokerConfigResponseHeader responseHeader =
        (GetBrokerConfigResponseHeader) response.getCustomHeader();

    String content = this.brokerController.encodeAllConfig();
    if (content != null && content.length() > 0) {
      try {
        response.setBody(content.getBytes(MixAll.DEFAULT_CHARSET));
      } catch (UnsupportedEncodingException e) {
        log.error("", e);

        response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
        response.setRemark("UnsupportedEncodingException " + e);
        return response;
      }
    }

    responseHeader.setVersion(this.brokerController.getConfigDataVersion());

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  private RemotingCommand registerMessageFilterClass(
      ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    final RegisterMessageFilterClassRequestHeader requestHeader =
        (RegisterMessageFilterClassRequestHeader)
            request.decodeCommandCustomHeader(RegisterMessageFilterClassRequestHeader.class);

    try {
      boolean ok =
          this.filtersrvController
              .getFilterClassManager()
              .registerFilterClass(
                  requestHeader.getConsumerGroup(), //
                  requestHeader.getTopic(), //
                  requestHeader.getClassName(), //
                  requestHeader.getClassCRC(), //
                  request.getBody()); // Body传输的是Java Source,必须UTF-8编码
      if (!ok) {
        throw new Exception("registerFilterClass error");
      }
    } catch (Exception e) {
      response.setCode(ResponseCode.SYSTEM_ERROR);
      response.setRemark(RemotingHelper.exceptionSimpleDesc(e));
      return response;
    }

    response.setCode(ResponseCode.SUCCESS);
    response.setRemark(null);
    return response;
  }
  private RemotingCommand deleteTopic(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    DeleteTopicRequestHeader requestHeader =
        (DeleteTopicRequestHeader)
            request.decodeCommandCustomHeader(DeleteTopicRequestHeader.class);

    log.info("deleteTopic called by {}", RemotingHelper.parseChannelRemoteAddr(ctx.channel()));

    this.brokerController.getTopicConfigManager().deleteTopicConfig(requestHeader.getTopic());

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
 public void invokeOnewayImpl(
     final Channel channel, final RemotingCommand request, final long timeoutMillis)
     throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
         RemotingSendRequestException {
   request.markOnewayRPC();
   boolean acquired = this.semaphoreOneway.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
   if (acquired) {
     final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreOneway);
     try {
       channel
           .writeAndFlush(request)
           .addListener(
               new ChannelFutureListener() {
                 @Override
                 public void operationComplete(ChannelFuture f) throws Exception {
                   once.release();
                   if (!f.isSuccess()) {
                     plog.warn(
                         "send a request command to channel <"
                             + channel.remoteAddress()
                             + "> failed.");
                     plog.warn(request.toString());
                   }
                 }
               });
     } catch (Exception e) {
       once.release();
       plog.warn(
           "write send a request command to channel <" + channel.remoteAddress() + "> failed.");
       throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel), e);
     }
   } else {
     if (timeoutMillis <= 0) {
       throw new RemotingTooMuchRequestException("invokeOnewayImpl invoke too fast");
     } else {
       String info =
           String.format(
               "invokeOnewayImpl tryAcquire semaphore timeout, %dms, waiting thread nums: %d semaphoreAsyncValue: %d", //
               timeoutMillis, //
               this.semaphoreAsync.getQueueLength(), //
               this.semaphoreAsync.availablePermits() //
               );
       plog.warn(info);
       plog.warn(request.toString());
       throw new RemotingTimeoutException(info);
     }
   }
 }
 public void processMessageReceived(ChannelHandlerContext ctx, RemotingCommand msg)
     throws Exception {
   final RemotingCommand cmd = msg;
   if (cmd != null) {
     switch (cmd.getType()) {
       case REQUEST_COMMAND:
         processRequestCommand(ctx, cmd);
         break;
       case RESPONSE_COMMAND:
         processResponseCommand(ctx, cmd);
         break;
       default:
         break;
     }
   }
 }
  private RemotingCommand unlockBatchMQ(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    UnlockBatchRequestBody requestBody =
        UnlockBatchRequestBody.decode(request.getBody(), UnlockBatchRequestBody.class);

    this.brokerController
        .getRebalanceLockManager()
        .unlockBatch( //
            requestBody.getConsumerGroup(), //
            requestBody.getMqSet(), //
            requestBody.getClientId());

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  private RemotingCommand updateAndCreateTopic(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    final CreateTopicRequestHeader requestHeader =
        (CreateTopicRequestHeader)
            request.decodeCommandCustomHeader(CreateTopicRequestHeader.class);
    log.info(
        "updateAndCreateTopic called by {}", RemotingHelper.parseChannelRemoteAddr(ctx.channel()));

    // Topic名字是否与保留字段冲突
    if (requestHeader
        .getTopic()
        .equals(this.brokerController.getBrokerConfig().getBrokerClusterName())) {
      String errorMsg =
          "the topic[" + requestHeader.getTopic() + "] is conflict with system reserved words.";
      log.warn(errorMsg);
      response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
      response.setRemark(errorMsg);
      return response;
    }

    TopicConfig topicConfig = new TopicConfig(requestHeader.getTopic());
    topicConfig.setReadQueueNums(requestHeader.getReadQueueNums());
    topicConfig.setWriteQueueNums(requestHeader.getWriteQueueNums());
    topicConfig.setTopicFilterType(requestHeader.getTopicFilterTypeEnum());
    topicConfig.setPerm(requestHeader.getPerm());

    this.brokerController.getTopicConfigManager().updateTopicConfig(topicConfig);

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  private RemotingCommand updateAndCreateSubscriptionGroup(
      ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);

    log.info(
        "updateAndCreateSubscriptionGroup called by {}",
        RemotingHelper.parseChannelRemoteAddr(ctx.channel()));

    SubscriptionGroupConfig config =
        RemotingSerializable.decode(request.getBody(), SubscriptionGroupConfig.class);
    if (config != null) {
      this.brokerController.getSubscriptionGroupManager().updateSubscriptionGroupConfig(config);
    }

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  @Override
  public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
      throws Exception {
    if (log.isDebugEnabled()) {
      log.debug(
          "receive request, {} {} {}", //
          request.getCode(), //
          RemotingHelper.parseChannelRemoteAddr(ctx.channel()), //
          request);
    }

    switch (request.getCode()) {
      case RequestCode.REGISTER_MESSAGE_FILTER_CLASS:
        return registerMessageFilterClass(ctx, request);
      case RequestCode.PULL_MESSAGE:
        return pullMessageForward(ctx, request);
    }

    return null;
  }
  public RegisterFilterServerResponseHeader registerFilterServerToBroker( //
      final String brokerAddr, // 1
      final String filterServerAddr // 2
      )
      throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException,
          RemotingTimeoutException, InterruptedException, MQBrokerException {
    RegisterFilterServerRequestHeader requestHeader = new RegisterFilterServerRequestHeader();
    requestHeader.setFilterServerAddr(filterServerAddr);
    RemotingCommand request =
        RemotingCommand.createRequestCommand(RequestCode.REGISTER_FILTER_SERVER, requestHeader);

    RemotingCommand response = this.remotingClient.invokeSync(brokerAddr, request, 3000);
    assert response != null;
    switch (response.getCode()) {
      case ResponseCode.SUCCESS:
        {
          RegisterFilterServerResponseHeader responseHeader =
              (RegisterFilterServerResponseHeader)
                  response.decodeCommandCustomHeader(RegisterFilterServerResponseHeader.class);

          return responseHeader;
        }
      default:
        break;
    }

    throw new MQBrokerException(response.getCode(), response.getRemark());
  }
  private RemotingCommand getTopicStatsInfo(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    final GetTopicStatsInfoRequestHeader requestHeader =
        (GetTopicStatsInfoRequestHeader)
            request.decodeCommandCustomHeader(GetTopicStatsInfoRequestHeader.class);

    final String topic = requestHeader.getTopic();
    TopicConfig topicConfig =
        this.brokerController.getTopicConfigManager().selectTopicConfig(topic);
    if (null == topicConfig) {
      response.setCode(MQResponseCode.TOPIC_NOT_EXIST_VALUE);
      response.setRemark("topic[" + topic + "] not exist");
      return response;
    }

    TopicStatsTable topicStatsTable = new TopicStatsTable();
    for (int i = 0; i < topicConfig.getWriteQueueNums(); i++) {
      MessageQueue mq = new MessageQueue();
      mq.setTopic(topic);
      mq.setBrokerName(this.brokerController.getBrokerConfig().getBrokerName());
      mq.setQueueId(i);

      TopicOffset topicOffset = new TopicOffset();
      long min = this.brokerController.getMessageStore().getMinOffsetInQuque(topic, i);
      if (min < 0) min = 0;

      long max = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, i);
      if (max < 0) max = 0;

      long timestamp = 0;
      if (max > 0) {
        timestamp =
            this.brokerController.getMessageStore().getMessageStoreTimeStamp(topic, i, (max - 1));
      }

      topicOffset.setMinOffset(min);
      topicOffset.setMaxOffset(max);
      topicOffset.setLastUpdateTimestamp(timestamp);

      topicStatsTable.getOffsetTable().put(mq, topicOffset);
    }

    byte[] body = topicStatsTable.encode();
    response.setBody(body);
    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
 @Override
 public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
     throws RemotingCommandException {
   switch (request.getCode()) {
     case RequestCode.HEART_BEAT:
       return this.heartBeat(ctx, request);
     case RequestCode.UNREGISTER_CLIENT:
       return this.unregisterClient(ctx, request);
     case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
       return this.getConsumerListByGroup(ctx, request);
     default:
       break;
   }
   return null;
 }
  private RemotingCommand getConsumerConnectionList(
      ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    final GetConsumerConnectionListRequestHeader requestHeader =
        (GetConsumerConnectionListRequestHeader)
            request.decodeCommandCustomHeader(GetConsumerConnectionListRequestHeader.class);

    ConsumerGroupInfo consumerGroupInfo =
        this.brokerController
            .getConsumerManager()
            .getConsumerGroupInfo(requestHeader.getConsumerGroup());
    if (consumerGroupInfo != null) {
      ConsumerConnection bodydata = new ConsumerConnection();
      bodydata.setConsumeFromWhere(consumerGroupInfo.getConsumeFromWhere());
      bodydata.setConsumeType(consumerGroupInfo.getConsumeType());
      bodydata.setMessageModel(consumerGroupInfo.getMessageModel());
      bodydata.getSubscriptionTable().putAll(consumerGroupInfo.getSubscriptionTable());

      Iterator<Map.Entry<Channel, ClientChannelInfo>> it =
          consumerGroupInfo.getChannelInfoTable().entrySet().iterator();
      while (it.hasNext()) {
        ClientChannelInfo info = it.next().getValue();
        Connection connection = new Connection();
        connection.setClientId(info.getClientId());
        connection.setLanguage(info.getLanguage());
        connection.setVersion(info.getVersion());
        connection.setClientAddr(RemotingHelper.parseChannelRemoteAddr(info.getChannel()));

        bodydata.getConnectionSet().add(connection);
      }

      byte[] body = bodydata.encode();
      response.setBody(body);
      response.setCode(ResponseCode.SUCCESS_VALUE);
      response.setRemark(null);

      return response;
    }

    response.setCode(MQResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST_VALUE);
    response.setRemark("the consumer group[" + requestHeader.getConsumerGroup() + "] not online");
    return response;
  }
  private RemotingCommand updateBrokerConfig(ChannelHandlerContext ctx, RemotingCommand request) {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);

    log.info(
        "updateBrokerConfig called by {}", RemotingHelper.parseChannelRemoteAddr(ctx.channel()));

    byte[] body = request.getBody();
    if (body != null) {
      try {
        String bodyStr = new String(body, MixAll.DEFAULT_CHARSET);
        Properties properties = MixAll.string2Properties(bodyStr);
        if (properties != null) {
          log.info(
              "updateBrokerConfig, new config: "
                  + properties
                  + " client: "
                  + ctx.channel().remoteAddress());
          this.brokerController.updateAllConfig(properties);
        } else {
          log.error("string2Properties error");
          response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
          response.setRemark("string2Properties error");
          return response;
        }
      } catch (UnsupportedEncodingException e) {
        log.error("", e);
        response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
        response.setRemark("UnsupportedEncodingException " + e);
        return response;
      }
    }

    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  private RegisterBrokerResult registerBroker( //
      final String namesrvAddr, //
      final String clusterName, // 1
      final String brokerAddr, // 2
      final String brokerName, // 3
      final long brokerId, // 4
      final String haServerAddr, // 5
      final TopicConfigSerializeWrapper topicConfigWrapper // 6
      )
      throws RemotingCommandException, MQBrokerException, RemotingConnectException,
          RemotingSendRequestException, RemotingTimeoutException, InterruptedException {
    RegisterBrokerRequestHeader requestHeader = new RegisterBrokerRequestHeader();
    requestHeader.setBrokerAddr(brokerAddr);
    requestHeader.setBrokerId(brokerId);
    requestHeader.setBrokerName(brokerName);
    requestHeader.setClusterName(clusterName);
    requestHeader.setHaServerAddr(haServerAddr);
    RemotingCommand request =
        RemotingCommand.createRequestCommand(MQRequestCode.REGISTER_BROKER_VALUE, requestHeader);
    request.setBody(topicConfigWrapper.encode());

    RemotingCommand response = this.remotingClient.invokeSync(namesrvAddr, request, 3000);
    assert response != null;
    switch (response.getCode()) {
      case ResponseCode.SUCCESS_VALUE:
        {
          RegisterBrokerResponseHeader responseHeader =
              (RegisterBrokerResponseHeader)
                  response.decodeCommandCustomHeader(RegisterBrokerResponseHeader.class);
          RegisterBrokerResult result = new RegisterBrokerResult();
          result.setMasterAddr(responseHeader.getMasterAddr());
          result.setHaServerAddr(responseHeader.getHaServerAddr());
          return result;
        }
      default:
        break;
    }

    throw new MQBrokerException(response.getCode(), response.getRemark());
  }
  public RemotingCommand getConsumerListByGroup(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response =
        RemotingCommand.createResponseCommand(GetConsumerListByGroupResponseHeader.class);
    final GetConsumerListByGroupRequestHeader requestHeader =
        (GetConsumerListByGroupRequestHeader)
            request.decodeCommandCustomHeader(GetConsumerListByGroupRequestHeader.class);

    ConsumerGroupInfo consumerGroupInfo =
        this.brokerController
            .getConsumerManager()
            .getConsumerGroupInfo(requestHeader.getConsumerGroup());
    if (consumerGroupInfo != null) {
      List<String> clientIds = consumerGroupInfo.getAllClientId();
      if (!clientIds.isEmpty()) {
        GetConsumerListByGroupResponseBody body = new GetConsumerListByGroupResponseBody();
        body.setConsumerIdList(clientIds);
        response.setBody(body.encode());
        response.setCode(ResponseCode.SUCCESS);
        response.setRemark(null);
        return response;
      } else {
        log.warn(
            "getAllClientId failed, {} {}",
            requestHeader.getConsumerGroup(),
            RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
      }
    } else {
      log.warn(
          "getConsumerGroupInfo failed, {} {}",
          requestHeader.getConsumerGroup(),
          RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
    }

    response.setCode(ResponseCode.SYSTEM_ERROR);
    response.setRemark("no consumer for this group, " + requestHeader.getConsumerGroup());
    return response;
  }
  // @Test
  public void test_idle_event()
      throws InterruptedException, RemotingConnectException, RemotingSendRequestException,
          RemotingTimeoutException {
    RemotingServer server = createRemotingServer();
    RemotingClient client = createRemotingClient();

    for (int i = 0; i < 10; i++) {
      RemotingCommand request = RemotingCommand.createRequestCommand(0, null);
      RemotingCommand response = client.invokeSync("localhost:8888", request, 1000 * 3);
      System.out.println(i + " invoke result = " + response);
      assertTrue(response != null);

      Thread.sleep(1000 * 10);
    }

    Thread.sleep(1000 * 60);

    client.shutdown();
    server.shutdown();
    System.out.println("-----------------------------------------------------------------");
  }
  private RemotingCommand getProducerConnectionList(
      ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
    final RemotingCommand response = RemotingCommand.createResponseCommand(null);
    final GetProducerConnectionListRequestHeader requestHeader =
        (GetProducerConnectionListRequestHeader)
            request.decodeCommandCustomHeader(GetProducerConnectionListRequestHeader.class);

    ConsumerConnection bodydata = new ConsumerConnection();
    HashMap<Channel, ClientChannelInfo> channelInfoHashMap =
        this.brokerController
            .getProducerManager()
            .getGroupChannelTable()
            .get(requestHeader.getProducerGroup());
    if (channelInfoHashMap != null) {
      Iterator<Map.Entry<Channel, ClientChannelInfo>> it = channelInfoHashMap.entrySet().iterator();
      while (it.hasNext()) {
        ClientChannelInfo info = it.next().getValue();
        Connection connection = new Connection();
        connection.setClientId(info.getClientId());
        connection.setLanguage(info.getLanguage());
        connection.setVersion(info.getVersion());
        connection.setClientAddr(RemotingHelper.parseChannelRemoteAddr(info.getChannel()));

        bodydata.getConnectionSet().add(connection);
      }

      byte[] body = bodydata.encode();
      response.setBody(body);
      response.setCode(ResponseCode.SUCCESS_VALUE);
      response.setRemark(null);
      return response;
    }

    response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
    response.setRemark("the producer group[" + requestHeader.getProducerGroup() + "] not exist");
    return response;
  }
  public TopicConfigSerializeWrapper getAllTopicConfig(final String addr)
      throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
          InterruptedException, MQBrokerException {
    RemotingCommand request =
        RemotingCommand.createRequestCommand(MQRequestCode.GET_ALL_TOPIC_CONFIG_VALUE, null);

    RemotingCommand response = this.remotingClient.invokeSync(addr, request, 3000);
    assert response != null;
    switch (response.getCode()) {
      case ResponseCode.SUCCESS_VALUE:
        {
          return TopicConfigSerializeWrapper.decode(
              response.getBody(), TopicConfigSerializeWrapper.class);
        }
      default:
        break;
    }

    throw new MQBrokerException(response.getCode(), response.getRemark());
  }
  private RemotingCommand getEarliestMsgStoretime(
      ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
    final RemotingCommand response =
        RemotingCommand.createResponseCommand(GetEarliestMsgStoretimeResponseHeader.class);
    final GetEarliestMsgStoretimeResponseHeader responseHeader =
        (GetEarliestMsgStoretimeResponseHeader) response.getCustomHeader();
    final GetEarliestMsgStoretimeRequestHeader requestHeader =
        (GetEarliestMsgStoretimeRequestHeader)
            request.decodeCommandCustomHeader(GetEarliestMsgStoretimeRequestHeader.class);

    long timestamp =
        this.brokerController
            .getMessageStore()
            .getEarliestMessageTime(requestHeader.getTopic(), requestHeader.getQueueId());

    responseHeader.setTimestamp(timestamp);
    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }
  public RemotingCommand unregisterClient(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response =
        RemotingCommand.createResponseCommand(UnregisterClientResponseHeader.class);
    final UnregisterClientRequestHeader requestHeader =
        (UnregisterClientRequestHeader)
            request.decodeCommandCustomHeader(UnregisterClientRequestHeader.class);

    ClientChannelInfo clientChannelInfo =
        new ClientChannelInfo( //
            ctx.channel(), //
            requestHeader.getClientID(), //
            request.getLanguage(), //
            request.getVersion() //
            );

    // 注销Producer
    {
      final String group = requestHeader.getProducerGroup();
      if (group != null) {
        this.brokerController.getProducerManager().unregisterProducer(group, clientChannelInfo);
      }
    }

    // 注销Consumer
    {
      final String group = requestHeader.getConsumerGroup();
      if (group != null) {
        this.brokerController.getConsumerManager().unregisterConsumer(group, clientChannelInfo);
      }
    }

    response.setCode(ResponseCode.SUCCESS);
    response.setRemark(null);
    return response;
  }
  private RemotingCommand updateConsumerOffset(ChannelHandlerContext ctx, RemotingCommand request)
      throws RemotingCommandException {
    final RemotingCommand response =
        RemotingCommand.createResponseCommand(UpdateConsumerOffsetResponseHeader.class);
    final UpdateConsumerOffsetResponseHeader responseHeader =
        (UpdateConsumerOffsetResponseHeader) response.getCustomHeader();
    final UpdateConsumerOffsetRequestHeader requestHeader =
        (UpdateConsumerOffsetRequestHeader)
            request.decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class);

    this.brokerController
        .getConsumerOffsetManager()
        .commitOffset(
            requestHeader.getConsumerGroup(),
            requestHeader.getTopic(),
            requestHeader.getQueueId(),
            requestHeader.getCommitOffset());
    UpdateCommitOffsetMoniter.printUpdatecommit(ctx.channel(), requestHeader);
    response.setCode(ResponseCode.SUCCESS_VALUE);
    response.setRemark(null);
    return response;
  }