protected void initChannels(
      Map<String, String> channelPropertiesStrings, Map<String, String> channelNames)
      throws Exception {

    _channelCount = channelPropertiesStrings.size();

    if ((_channelCount <= 0) || (_channelCount > MAX_CHANNEL_COUNT)) {
      throw new IllegalArgumentException(
          "Channel count must be between 1 and " + MAX_CHANNEL_COUNT);
    }

    _localAddresses = new ArrayList<>(_channelCount);
    _clusterChannels = new ArrayList<>(_channelCount);
    _clusterReceivers = new ArrayList<>(_channelCount);

    List<String> keys = new ArrayList<>(channelPropertiesStrings.keySet());

    Collections.sort(keys);

    for (String key : keys) {
      String channelPropertiesString = channelPropertiesStrings.get(key);
      String channelName = channelNames.get(key);

      if (Validator.isNull(channelPropertiesString) || Validator.isNull(channelName)) {

        continue;
      }

      ClusterReceiver clusterReceiver = new ClusterForwardReceiver(this);

      ClusterChannel clusterChannel =
          _clusterChannelFactory.createClusterChannel(
              channelPropertiesString, channelName, clusterReceiver);

      _clusterChannels.add(clusterChannel);
      _clusterReceivers.add(clusterReceiver);
      _localAddresses.add(clusterChannel.getLocalAddress());
    }
  }
  @Override
  protected void doReceive(Object messagePayload, Address srcAddress) {
    ClusterChannel clusterChannel = _clusterExecutorImpl.getClusterChannel();

    if (srcAddress.equals(clusterChannel.getLocalAddress())) {
      return;
    }

    try {
      if (messagePayload instanceof ClusterRequest) {
        ClusterRequest clusterRequest = (ClusterRequest) messagePayload;

        Serializable responsePayload =
            _clusterExecutorImpl.handleReceivedClusterRequest(clusterRequest);

        if (clusterRequest.isFireAndForget()) {
          return;
        }

        try {
          clusterChannel.sendUnicastMessage(responsePayload, srcAddress);
        } catch (Throwable t) {
          _log.error("Unable to send message " + responsePayload, t);
        }
      } else if (messagePayload instanceof ClusterNodeResponse) {
        _clusterExecutorImpl.handleReceivedClusterNodeResponse(
            (ClusterNodeResponse) messagePayload);
      } else if (_log.isWarnEnabled()) {
        _log.warn("Unable to process message content of type " + messagePayload.getClass());
      }
    } finally {
      ThreadLocalCacheManager.clearAll(Lifecycle.REQUEST);

      CentralizedThreadLocal.clearShortLivedThreadLocals();
    }
  }