private void publishFailureDetected(String broker) {
    try {
      String pubStr =
          "[class,"
              + HeartbeatSubscriber.MESSAGE_CLASS
              + "],"
              + "[detectorID,'"
              + m_BrokerCore.getBrokerID()
              + "'],"
              + "[detectedID,'"
              + broker
              + "'],"
              + "[type,'FAILURE_DETECTED']";
      Publication pub = MessageFactory.createPublicationFromString(pubStr);
      PublicationMessage pubMsg =
          new PublicationMessage(
              pub, m_BrokerCore.getNewMessageID(), MessageDestination.HEARTBEAT_MANAGER);

      Map<MessageDestination, LinkInfo> statisticTable =
          m_BrokerCore.getOverlayManager().getORT().getStatisticTable();
      MessageDestination failureBroker = new MessageDestination(broker, DestinationType.BROKER);
      if (statisticTable.containsKey(failureBroker)) {
        LinkInfo link = statisticTable.get(failureBroker);
        link.setStatus();
      }

      heartbeatLogger.info("Sending failure of " + broker + " detected messsage.");
      m_BrokerCore.routeMessage(pubMsg, MessageDestination.INPUTQUEUE);
    } catch (ParseException e) {
      heartbeatLogger.error(e.getMessage());
      exceptionLogger.error(e.getMessage());
    }
  }
 private void advertiseHeartbeat() {
   String advStr =
       "[class,eq,"
           + HeartbeatSubscriber.MESSAGE_CLASS
           + "],"
           + "[brokerID,isPresent,'TEXT'],"
           + "[fromID,eq,'"
           + m_BrokerCore.getBrokerID()
           + "'],"
           + "[type,isPresent,'TEXT'],"
           + "[handle,isPresent,'TEXT']";
   Advertisement adv;
   try {
     adv = MessageFactory.createAdvertisementFromString(advStr);
   } catch (ParseException e) {
     exceptionLogger.error(e.getMessage());
     return;
   }
   AdvertisementMessage msg =
       new AdvertisementMessage(
           adv, m_BrokerCore.getNewMessageID(), MessageDestination.HEARTBEAT_MANAGER);
   msg.setTTL(1);
   heartbeatLogger.debug("Sending initial advertisement for heartbeat.");
   m_BrokerCore.routeMessage(msg, MessageDestination.INPUTQUEUE);
 }
  private void publishHeartbeats() {
    try {
      Map<MessageDestination, OutputQueue> neighbors =
          m_BrokerCore.getOverlayManager().getORT().getBrokerQueues();
      synchronized (neighbors) {
        for (MessageDestination md : neighbors.keySet()) {
          String brokerID = md.getDestinationID();

          // create and set a timer event for the heartbeat request
          TimerEvent event = new TimerEvent(this, m_HeartbeatTimeout, HEARTBEAT_TIMEOUT_TIMER);
          event.setAttachment(brokerID);
          int handle = m_TimerThread.setTimer(event);

          // publish the heartbeat request
          String pubStr =
              "[class,"
                  + HeartbeatSubscriber.MESSAGE_CLASS
                  + "],"
                  + "[brokerID,'"
                  + brokerID
                  + "'],"
                  + "[fromID,'"
                  + m_BrokerCore.getBrokerID()
                  + "'],"
                  + "[type,'HEARTBEAT_REQ'],"
                  + "[handle,'"
                  + handle
                  + "']";
          Publication pub = MessageFactory.createPublicationFromString(pubStr);
          PublicationMessage pubMsg =
              new PublicationMessage(
                  pub, m_BrokerCore.getNewMessageID(), MessageDestination.HEARTBEAT_MANAGER);
          heartbeatLogger.info(
              "Broker "
                  + m_BrokerCore.getBrokerID()
                  + " is sending heartbeat REQ to broker "
                  + brokerID
                  + " with handle "
                  + handle);
          m_BrokerCore.routeMessage(pubMsg, MessageDestination.INPUTQUEUE);
          // add by shuang for testing
          currentHandle = handle;
        }
      }
    } catch (ParseException e) {
      heartbeatLogger.error(e.getMessage());
      exceptionLogger.error(e.getMessage());
    }
  }
  public void run() {
    synchronized (started_lock) {
      m_TimerThread = m_BrokerCore.getTimerThread();

      // advertise that we will be publishing heartbeat related messages
      advertiseHeartbeat();
      advertiseFailureDetected();

      // set the initial heartbeat timer
      m_TimerThread.setTimer(new TimerEvent(this, m_HeartbeatInterval, HEARTBEAT_INTERVAL_TIMER));

      // wake up threads waiting for HeartbeatPublisher to start
      started = true;
      started_lock.notifyAll();
    }

    while (started) {
      try {
        sleep(DEFAULT_SLEEP_TIME);
      } catch (InterruptedException ignored) {
      }

      if (!started) break;

      synchronized (this) {
        // check if neighbor list changed
        if (m_NeighborListChanged) {
          // TODO: process changed neighbor list
          m_NeighborListChanged = false;
        }

        // check for expired events
        while (m_ReturnedEventsQ != null) {
          TimerEvent event = m_ReturnedEventsQ;

          // process the event
          if (event.getStatus() == TimerEvent.TIMER_STATUS_EXPIRED) {
            if (event.getType() == HEARTBEAT_INTERVAL_TIMER) {
              // send the next batch of heartbeats
              if (m_PublishHeartbeats) publishHeartbeats();
              // reset the interval timer
              m_TimerThread.setTimer(
                  new TimerEvent(this, m_HeartbeatInterval, HEARTBEAT_INTERVAL_TIMER));
            } else if (event.getType() == HEARTBEAT_TIMEOUT_TIMER) {
              heartbeatLogger.info(
                  "Broker " + event.getAttachment() + " did not reply to a heartbeat");

              // get the name of the offending broker
              String broker = (String) event.getAttachment();

              // a broker heartbeat timed out, increment the fail count
              Map<MessageDestination, OutputQueue> neighbors1 =
                  m_BrokerCore.getOverlayManager().getORT().getBrokerQueues();
              synchronized (neighbors1) {
                for (MessageDestination md : neighbors1.keySet()) {
                  if (md.getDestinationID().equals(broker)) {
                    int failCount = md.incrementFailCount();
                    if (failCount >= m_FailureThreshold) {
                      publishFailureDetected(broker);
                      break;
                    }
                  }
                }
              }
            }
          }
          m_ReturnedEventsQ = event.getNext();
        }
      }
    }
  }