log.error ("From node missing (msg ignored): " +msgString);
log.error ("AckBackend: From node missing (msg ignored): " +msgString);
  public MessageAttributes deliverMessage (AttributedMessage msg, MessageAddress dest) throws MisdeliveredMessageException  {    //  Special Case:  Local messages are completely excluded from acking    if (MessageUtils.isLocalMessage (msg)) return super.deliverMessage (msg, dest);    //  Sanity Check:  The dest argument appears vestigial and is not supported    if (!msg.getTarget().equals(dest))    {      log.error ("Message target ["+msg.getTarget()+"] != dest ["+dest+"]");      throw new MisdeliveredMessageException (msg);    }    //  Sanity Check: Message must have some kind of ack in it!    Ack ack = MessageUtils.getAck (msg);    String msgString = MessageUtils.toString (msg);    if (ack == null)    {      log.error ("Message has no ack in it! : " +msgString);      throw new MisdeliveredMessageException (msg);    }    //  Get started    ack.setReceiveTime (now());  // establish our own message reception time    ack.setMsg (msg);            // reset transient msg field    if (true) // MessageAckingAspect.showTraffic)    {      if (log.isInfoEnabled())      {        StringBuffer buf = new StringBuffer();        buf.append ("\n\n<");        buf.append (AdaptiveLinkSelectionPolicy.getLinkLetter(ack.getSendLink()));        buf.append (" ");        buf.append (MessageUtils.getMessageNumber(msg));        buf.append (".");        buf.append (ack.getSendCount());        buf.append (" ");        buf.append (MessageUtils.getMessageTypeLetter(msg));        buf.append (" ");        buf.append (MessageUtils.getFromAgent(msg).toShortString());        buf.append (" to ");        buf.append (MessageUtils.getToAgent(msg).toShortString());        buf.append ("\n");        log.info (buf.toString());      }      else if (log.isDebugEnabled())      {        StringBuffer buf = new StringBuffer();        buf.append ("\n\n");        String hdr = "Received " + MessageUtils.toShortString (msg);        buf.append (hdr);        buf.append (" via ");        buf.append (MessageAckingAspect.getLinkType (ack.getSendLink()));        buf.append (" of ");        buf.append (MessageUtils.getAckingSequenceID (msg));        buf.append ("\n");        buf.append (hdr);        buf.append (" contains acks: \n");        AckList.printAcks (buf, "specific", ack.getSpecificAcks());        AckList.printAcks (buf, "  latest", ack.getLatestAcks());        // System.err.println ("Inbound roundtrip time: " + ack.getSenderRoundtripTime());        log.info (buf.toString());               }    }    //  We do a series of integrity checks on the received message.  Who knows where    //  this "message" really came from, where it has been, and what happened on    //  the way...  These are only some basic checks; other entites such as message     //  security (if activated) may have done or do other checks.      //    //  NOTE:  For now we return success even if we find the message mal-formed and    //  reject it (ignore it).  If the message came from a legimate source it will    //  resend it, and perhaps this time be well-formed.    try    {      if (ack.getSpecificAcks() != null)      {        for (Enumeration a=ack.getSpecificAcks().elements(); a.hasMoreElements(); )        {          NumberList.checkListValidity ((AckList) a.nextElement());        }      }      if (ack.getLatestAcks() != null)      {        for (Enumeration a=ack.getLatestAcks().elements(); a.hasMoreElements(); )        {          NumberList.checkListValidity ((AckList) a.nextElement());        }      }    }    catch (Exception e)    {      log.error ("Msg contains invalid acks (msg ignored): " +msgString);      return success;    }/*    Can't do this integrity check yet - msg system architecture wrong for it    if (getLinkType (ack.getSendLink()) != actual receive link type)    {      if (MessageAckingAspect.debug)       {        log.error ("ALERT msg came in on wrong link - msg ignored: " +msgString);         return success;      }    }*/    int msgNum = MessageUtils.getMessageNumber (msg);    if (ack.isAck() && msgNum < 0)    {      if (!MessageUtils.isPingMessage (msg))  // pings are an exception      {        log.error ("Invalid msg number (msg ignored): " +msgString);        return success;      }    }    if (ack.isPureAck() && msgNum >= 0)    {      log.error ("Invalid msg number (pure ack msg ignored): " +msgString);      return success;    }    if (ack.isPureAckAck() && msgNum >= 0)    {      log.error ("Invalid msg number (pure ack-ack msg ignored): " +msgString);      return success;    }    String fromNode = MessageUtils.getFromAgentNode (msg);    if (fromNode == null || fromNode.equals(""))    {      log.error ("From node missing (msg ignored): " +msgString);      return success;    }    if (ack.getSendTime() < now() - MessageAckingAspect.messageAgeWindowInMinutes*60*1000)    {      //  Kind of a hack, but the start of something.  May want to do things like set      //  max age based on transport type ...            log.error ("Msg too old (msg ignored): " +msgString);      return success;    }    if (ack.getSendTime() > now() + MessageAckingAspect.messageAgeWindowInMinutes*60*1000)    {      //  Kind of a hack, but the start of something.  May want to do things like set      //  max age based on transport type ...            log.error ("Msg too far in the future (msg ignored): " +msgString);      return success;    }    if (ack.getSendCount() < 1)    {      int sendCount = ack.getSendCount();      log.error ("Msg has bad sendCount (" +sendCount+ ") (msg ignored): " +msgString);      return success;    }    if (ack.isAck() && ack.getResendMultiplier() < 1)    {      log.error ("Msg has bad resendMultiplier (msg ignored): " +msgString);      return success;    }    //  Handle messages from out-of-date senders or to out-of-date receivers    //  NOTE:  May want to send NACKs back for these messages.// if (regular msg)  not pure ack, ack ack, ping, etc// if (not a duplicate) // only send once?//   send it or schedule it//   if sched, need nack vs. pure nack//   a pure nack has no msg num - it is not acked?    if (!isLatestAgentIncarnation (MessageUtils.getFromAgent (msg), MessageUtils.getOriginatorAgent (msg)))    {      if (log.isWarnEnabled()) log.warn ("Msg has out of date (or unknown) sender (msg ignored): " +msgString);      return success;    }    if (!isLatestAgentIncarnation (MessageUtils.getToAgent (msg), MessageUtils.getTargetAgent (msg)))    {      if (log.isWarnEnabled()) log.warn ("Msg has out of date (or unknown) recipient (msg ignored): " +msgString);      return success;    }    //  At this point we feel the received message is legitimate, so now we deliver    //  it and record its reception while making sure that it is not a message we have     //  already received and delivered.  Note that there is also checking for duplicate    //  messages in the MessageOrderingAspect, but that is ok because message ordering     //  is orthogonal to acking and is not required to be active.    synchronized (this)    {      if (!MessageAckingAspect.wasSuccessfulReceive (msg))      {        //  Actually deliver the message.  Mis-deliveries throw an exception.        if (ack.isAck()) super.deliverMessage (msg, dest);        //  Add the message to our list of received messages.  We don't do this        //  for non-acked msgs like heartbeats & traffic masking messages.        if (msgNum != 0) MessageAckingAspect.addSuccessfulReceive (msg);      }      else      {        //  A duplicate message - right now we just drop them cold                if (false) //  HACK make new method -> (MessageAckingAspect.isExcludedLink (link))        {          //  A self-acking link should not be sending us duplicate messages          log.error ("ERROR! Duplicate msg over excluded link! Msg ignored: " +msgString);          return success;        }        else if (log.isWarnEnabled()) log.warn ("Duplicate msg ignored: " +msgString);// HACK - if right kind of message perhaps strip out stuff and let proceed below// to kick off another pure ack.  Slow things down if sendCount high enough.        return success;      }    }    //  Disburse the acks contained in the message    MessageAckingAspect.addReceivedAcks (fromNode, ack.getLatestAcks());  // all have latest acks    long ackSendableTime = 0;    if (ack.isAck())    {      //  Record the specific acks contained within this message.  Used to acknowledge       //  sent messages waiting for acks.  This call also dings the ack waiter to announce       //  new ack data has arrived for those waiting messages.      MessageAckingAspect.addReceivedAcks (fromNode, ack.getSpecificAcks());      if (msgNum != 0)      {        //  Add the message data to our outbound acks list (we send back acks for        //  these messages we've received, until those acks are acked).  We record        //  the time that this is set, so that we know any message sent back to the         //  source node after this time will include this ack (as long as needed).            MessageAckingAspect.addAckToSend (msg);        ackSendableTime = now();      }    }    else if (ack.isPureAck())    {      //  Pure acks only have the latest acks, already dealt with above    }    else if (ack.isPureAckAck())    {      //  Remove the specific acks contained within this pure ack-ack message       //  from our ack sending list as those acks are now officially acked.      MessageAckingAspect.removeAcksToSend (fromNode, ack.getSpecificAcks());    }    //  Handle setting up possible return messages for the message received.    //  For regular messages we send back pure ack messages, and for pure ack     //  messages we send back pure ack-ack messages.  Howecer, if the link    //  the received message came in on is excluded from acking, then we won't    //  send back any kind of pure ack messages.    if (!MessageAckingAspect.isExcludedLink (ack.getSendLink()))    {      if (ack.isAck() && msgNum != 0)      {        //  Create a pure ack for this message add it to our pure ack sender.  The sender ensures        //  pure acks for received  messages get sent if there is not enough regular message         //  traffic back to the originating node to piggyback acks on.        PureAck pureAck = new PureAck();        pureAck.setAckSendableTime (ackSendableTime);        float myTimeout = (float)(ack.getMsgResendTimeout() - ack.getRTT());        int firstAck = (int)(myTimeout * MessageAckingAspect.firstAckPlacingFactor);        pureAck.setSendDeadline (ack.getReceiveTime() + firstAck);//pureAck.setSendDeadline (ack.getReceiveTime() + 15);  // testing        PureAckMessage pureAckMsg = new PureAckMessage (msg, pureAck);        MessageAckingAspect.pureAckSender.add (pureAckMsg);      }      else if (ack.isPureAck())      {        //  Create an ack-ack for this ack message and add it to our pure ack-ack sender.          //  The sender ensures acks-acks for received acks get sent if there is not         //  enough regular message traffic back to the originating node to let it know        //  that its ack has been received.  Only one ack-ack at most is sent in return        //  for any and all the acks that one message can potentially generate.        PureAckAck pureAckAck = new PureAckAck ((PureAck)ack);        float rtt = (float) ack.getRTT();        int onlyAckAck = (int)(rtt * MessageAckingAspect.ackAckPlacingFactor);        pureAckAck.setSendDeadline (ack.getReceiveTime() + onlyAckAck);//pureAckAck.setSendDeadline (ack.getReceiveTime() + 5);  // testing        PureAckAckMessage pureAckAckMsg = new PureAckAckMessage ((PureAckMessage)msg, pureAckAck);        MessageAckingAspect.pureAckAckSender.add (pureAckAckMsg);      }    }    //  We don't send pure acks et al on, but they were successfully delivered to us    return success;  }