/**
   * Start topology event receiver thread.
   *
   * @param executorService executor service instance
   * @param topologyProvider topology provider instance
   */
  private void startTopologyEventReceiver(
      ExecutorService executorService, TopologyProvider topologyProvider) {
    // Enforcing the listener order in order execute extension listener later
    topologyEventReceiver = new LoadBalancerCommonTopologyEventReceiver(topologyProvider, false);
    // Add load-balancer extension event listener
    addTopologyEventListeners(topologyEventReceiver);
    // Add default topology provider event listeners
    topologyEventReceiver.addEventListeners();
    topologyEventReceiver.setExecutorService(executorService);
    topologyEventReceiver.execute();
    if (log.isInfoEnabled()) {
      log.info("Topology receiver thread started");
    }

    if (log.isInfoEnabled()) {
      if (TopologyServiceFilter.getInstance().isActive()) {
        log.info(
            String.format(
                "Service filter activated: [filter] %s",
                TopologyServiceFilter.getInstance().toString()));
      }

      if (TopologyClusterFilter.getInstance().isActive()) {
        log.info(
            String.format(
                "Cluster filter activated: [filter] %s",
                TopologyClusterFilter.getInstance().toString()));
      }

      if (TopologyMemberFilter.getInstance().isActive()) {
        log.info(
            String.format(
                "Member filter activated: [filter] %s",
                TopologyMemberFilter.getInstance().toString()));
      }
    }
  }
  @Override
  public boolean process(String type, String message, Object object) {
    Topology topology = (Topology) object;

    if (MemberTerminatedEvent.class.getName().equals(type)) {
      // Return if topology has not been initialized
      if (!topology.isInitialized()) return false;

      // Parse complete message and build event
      MemberTerminatedEvent event =
          (MemberTerminatedEvent) Util.jsonToObject(message, MemberTerminatedEvent.class);

      // Apply service filter
      if (TopologyServiceFilter.getInstance().isActive()) {
        if (TopologyServiceFilter.getInstance().serviceNameExcluded(event.getServiceName())) {
          // Service is excluded, do not update topology or fire event
          if (log.isDebugEnabled()) {
            log.debug(String.format("Service is excluded: [service] %s", event.getServiceName()));
          }
          return false;
        }
      }

      // Apply cluster filter
      if (TopologyClusterFilter.getInstance().isActive()) {
        if (TopologyClusterFilter.getInstance().clusterIdExcluded(event.getClusterId())) {
          // Cluster is excluded, do not update topology or fire event
          if (log.isDebugEnabled()) {
            log.debug(String.format("Cluster is excluded: [cluster] %s", event.getClusterId()));
          }
          return false;
        }
      }

      // Validate event against the existing topology
      Service service = topology.getService(event.getServiceName());
      if (service == null) {
        if (log.isWarnEnabled()) {
          log.warn(String.format("Service does not exist: [service] %s", event.getServiceName()));
        }
        return false;
      }
      Cluster cluster = service.getCluster(event.getClusterId());
      if (cluster == null) {
        if (log.isWarnEnabled()) {
          log.warn(
              String.format(
                  "Cluster does not exist: [service] %s [cluster] %s",
                  event.getServiceName(), event.getClusterId()));
        }
        return false;
      }
      Member member = cluster.getMember(event.getMemberId());
      if (member == null) {
        if (log.isWarnEnabled()) {
          log.warn(
              String.format(
                  "Member does not exist: [service] %s [cluster] %s [member] %s",
                  event.getServiceName(), event.getClusterId(), event.getMemberId()));
        }
        return false;
      }

      // Apply member filter
      if (TopologyMemberFilter.getInstance().isActive()) {
        if (TopologyMemberFilter.getInstance().lbClusterIdExcluded(member.getLbClusterId())) {
          if (log.isDebugEnabled()) {
            log.debug(
                String.format("Member is excluded: [lb-cluster-id] %s", member.getLbClusterId()));
          }
          return false;
        }
      }

      if (member.getStatus() == MemberStatus.Terminated) {
        if (log.isWarnEnabled()) {
          log.warn(
              String.format(
                  "Member already terminated: [service] %s [cluster] %s [member] %s",
                  event.getServiceName(), event.getClusterId(), event.getMemberId()));
        }
      } else {

        // Apply changes to the topology
        member.setStatus(MemberStatus.Terminated);
        // removing the member from the cluster
        cluster.removeMember(member);

        if (log.isInfoEnabled()) {
          log.info(
              String.format(
                  "Member terminated: [service] %s [cluster] %s [member] %s",
                  event.getServiceName(), event.getClusterId(), event.getMemberId()));
        }
      }

      notifyEventListeners(event);
      return true;

    } else {
      if (nextProcessor != null) {
        // ask the next processor to take care of the message.
        return nextProcessor.process(type, message, topology);
      } else {
        throw new RuntimeException(
            String.format(
                "Failed to process message using available message processors: [type] %s [body] %s",
                type, message));
      }
    }
  }