/**
   * Routes the messages if the next hop has been set up.
   *
   * <p>Note, this once lived in the RouteMessaage
   *
   * @param localId the node id of the local node.
   * @return true if the message got routed, false otherwise.
   */
  public boolean routeMessage(RouteMessage rm) {
    if (logger.level <= Logger.FINER) logger.log("routeMessage(" + rm + ")");
    if (rm.getNextHop() == null) return false;
    rm.setSender(thePastryNode.getLocalHandle());

    NodeHandle handle = rm.getNextHop();
    rm.setNextHop(null);
    rm.setPrevNode(thePastryNode.getLocalHandle());

    if (thePastryNode.getLocalHandle().equals(handle)) {
      // the local node is the closest node to the id
      if (rm.getDestinationHandle() != null
          && !rm.getDestinationHandle().equals(thePastryNode.getLocalHandle())) {
        // no idea how to contact the destination, drop
        if (logger.level <= Logger.FINE)
          logger.log(
              "Message "
                  + rm
                  + " has destination "
                  + rm.getDestinationHandle()
                  + " but I'm the root of the id.  Dropping.  This could happen if the destination has died while the route message was in transit, or if the local node does not yet have logging state because it is boostrapping.");

        rm.sendFailed(new NoRouteToHostException(rm.getDestinationHandle().toString()));
        return true;
      }
      thePastryNode.receiveMessage(rm.internalMsg);
      rm.sendSuccess(thePastryNode.getLocalHandle());
    } else {
      sendTheMessage(rm, handle);
    }
    return true;
  }
  /**
   * Receive and process a route message. Sets a nextHop.
   *
   * @param msg the message.
   */
  private void receiveRouteMessage(RouteMessage msg) {
    if (logger.level <= Logger.FINER) logger.log("receiveRouteMessage(" + msg + ")");
    Id target = msg.getTarget();

    if (target == null) target = thePastryNode.getNodeId();

    int cwSize = thePastryNode.getLeafSet().cwSize();
    int ccwSize = thePastryNode.getLeafSet().ccwSize();

    int lsPos = thePastryNode.getLeafSet().mostSimilar(target);

    if (lsPos == 0) {
      // message is for the local node so deliver it
      msg.setNextHop(thePastryNode.getLocalHandle());

      // don't return, we want to check for routing table hole
    } else {
      msg.getOptions().setRerouteIfSuspected(true);
      Iterator<NodeHandle> i = getBestRoutingCandidates(target);

      // the next hop
      NodeHandle nextHop = routerStrategy.pickNextHop(msg, i);
      if (nextHop == null) {
        msg.sendFailed(new NoLegalRouteToMakeProgressException(target));
        return;
      }
      msg.setNextHop(nextHop);
    }

    // this wasn't being called often enough in its previous location, moved here Aug 11, 2006
    checkForRouteTableHole(msg, msg.getNextHop());
    msg.setPrevNode(thePastryNode.getLocalHandle());

    // here, we need to deliver the msg to the proper app
    deliverToApplication(msg);
  }