@Override
  public void sendMulticastMessage(Message message, Priority priority) {
    if (!isEnabled()) {
      return;
    }

    ClusterChannel clusterChannel = getChannel(priority);

    clusterChannel.sendMulticastMessage(message);
  }
  @Override
  public void sendUnicastMessage(Address address, Message message, Priority priority) {

    if (!isEnabled()) {
      return;
    }

    if (_localAddresses.contains(address)) {
      sendLocalMessage(message);

      return;
    }

    ClusterChannel clusterChannel = getChannel(priority);

    clusterChannel.sendUnicastMessage(message, address);
  }
  @Deactivate
  protected void deactivate() {
    if (_clusterChannels != null) {
      for (ClusterChannel clusterChannel : _clusterChannels) {
        clusterChannel.close();
      }
    }

    _localAddresses = null;
    _clusterChannels = null;
    _clusterReceivers = null;

    if (_executorService != null) {
      _executorService.shutdownNow();
    }

    _executorService = null;
  }
  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();
    }
  }