Package jade.core.messaging

Source Code of jade.core.messaging.OutBox$Box

package jade.core.messaging;

//import java.util.Hashtable;

import jade.util.leap.List;
import jade.util.leap.LinkedList;
import jade.util.leap.RoundList;
import jade.util.leap.Map;
import jade.util.leap.HashMap;
import jade.core.AID;
import jade.core.messaging.MessageManager.PendingMsg;
import jade.core.messaging.MessageManager.Channel;
import jade.lang.acl.ACLMessage;

import jade.util.Logger;

/**
* Object to mantain message to send and
* to preserve the order for sending.
*
* @author Elisabetta Cortese - TILAB
*/

class OutBox {
  private int size = 0;
  private int maxSize;
  private boolean overMaxSize = false;
 
  // The massages to be delivered organized as an hashtable that maps
  // a receiver AID into the Box of messages to be delivered to that receiver
  private final Map messagesByReceiver = new HashMap();
  // The messages to be delivered organized as a round list of the Boxes of
  // messages for the currently addressed receivers
  private final RoundList messagesByOrder = new RoundList();
   
  // For debugging purposes
  private long submittedCnt = 0;
  private long servedCnt = 0;

  private Logger myLogger;
 
  OutBox(int s) {
    maxSize = s;
    myLogger = Logger.getMyLogger(getClass().getName());
  }
 
 
  /**
   * Add a message to the tail of the Box of messages for the indicated
   * receiver. If a Box for the indicated receiver is not yet present, a
   * new one is created.
   * This method is executed by an agent's thread requesting to deliver
   * a new message.
   */
  void addLast(AID receiverID, GenericMessage msg, Channel ch) {
    boolean logActivated = myLogger.isLoggable(Logger.FINER);
    if (logActivated)
      myLogger.log(Logger.FINER,"Entering addLast for receiver "+receiverID.getName());
    if (msg.getPayload() != null && msg.isModifiable()) {
      ACLMessage acl = msg.getACLMessage();
      if (acl != null) {
        acl.setContent(null);
      }
    }
   
    // This must fall outside the synchronized block because the method calls Thread.sleep
    increaseSize(msg.length());
   
    synchronized (this) {
      Box b = (Box) messagesByReceiver.get(receiverID);
      if (logActivated) {
        String msgDebug = (b==null)? "No box for receiver "+receiverID.getName():"Box for receiver "+receiverID.getName()+" busy ?  "+b.isBusy();
        myLogger.log(Logger.FINER,msgDebug);
      }
      if (b == null){
        // There is no Box of messages for this receiver yet. Create a new one
        b = new Box(receiverID);
        messagesByReceiver.put(receiverID, b);
        messagesByOrder.add(b);
        if (logActivated)
          myLogger.log(Logger.FINER,"Box created for receiver "+receiverID.getName());
      }
      if (logActivated)
        myLogger.log(Logger.FINER,"Message entered in box for receiver "+receiverID.getName());
      b.addLast(new PendingMsg(msg, receiverID, ch, -1));
      submittedCnt++;
      // Wakes up all deliverers
      notifyAll();
    }
    if (logActivated)
      myLogger.log(Logger.FINER,"Exiting addLast for receiver "+receiverID.getName());
  }

  /**
   * Add a message to the head of the Box of messages for the indicated
   * receiver.
   * This method is executed by the TimerDispatcher Thread when a
   * retransmission timer expires. Therefore a Box of messages for the
   * indicated receiver must already exist. Moreover the busy flag of
   * this Box must be reset to allow deliverers to handle messages in it
   *
  synchronized void addFirst(PendingMsg pm){
    Box b = (Box) messagesByReceiver.get(pm.getReceiver());
    b.addFirst(pm);
    b.setBusy(false);
    // Wakes up all deliverers
    notifyAll();
  }*/
 


  /**
   * Get the first message for the first idle (i.e. not busy) receiver.
   * This is executed by a Deliverer thread just before delivering
   * a message.
   */
  synchronized final PendingMsg get(){
    Box b = null;
    // Wait until an idle (i.e. not busy) receiver is found
    while( (b = getNextIdle()) == null ){
      try{
        if (myLogger.isLoggable(Logger.FINER)) {
          myLogger.log(Logger.FINER, "Deliverer "+Thread.currentThread()+" go to sleep...");
        }
        wait();
        if (myLogger.isLoggable(Logger.FINER)) {
          myLogger.log(Logger.FINER, "Deliverer "+Thread.currentThread()+" wake up");
        }
      }
      catch (InterruptedException ie) {
        // Just do nothing
      }
    }
     PendingMsg pm = b.removeFirst();
     decreaseSize(pm.getMessage().length());
     return pm;
  }
 
 

  /**
   * Get the Box of messages for the first idle (i.e. not busy) receiver.
   * @return null if all receivers are currently busy
   * This method does not need to be synchronized as it is only executed
   * inside a synchronized block.
   */
  private final Box getNextIdle(){
    for (int i = 0; i < messagesByOrder.size(); ++i) {
      Box b = (Box) messagesByOrder.get();
      if (!b.isBusy()) {
        b.setBusy(true);
        if( myLogger.isLoggable(Logger.FINER) )
          myLogger.log(Logger.FINER,"Setting box busy for receiver "+b.getReceiver().getName());
        return b;
      }
    }
    return null
  }
 
  /**
   * A message for the receiver receiverID has been served
   * If the Box of messages for that receiver is now empty --> remove it.
   * Otherwise just mark it as idel (not busy).
   */
  synchronized final void handleServed( AID receiverID ){
    servedCnt++;
    boolean logActivated = myLogger.isLoggable(Logger.FINER);
    if (logActivated)
      myLogger.log(Logger.FINER,"Entering handleServed for "+receiverID.getName());
    Box b = (Box) messagesByReceiver.get(receiverID);
    if (b.isEmpty()) {
      messagesByReceiver.remove(receiverID);
      messagesByOrder.remove(b);
      if (logActivated)
        myLogger.log(Logger.FINER,"Removed box for receiver "+receiverID.getName());
    }
    else {
      b.setBusy(false);
      if (logActivated)
        myLogger.log(Logger.FINER,"Freeing box for receiver "+receiverID.getName());
    }
    if (logActivated)
      myLogger.log(Logger.FINER,"Exiting handleServed for "+receiverID.getName());
  }

  private void increaseSize(int k) {
    long sleepTime = 0;
    synchronized (this) {
      size += k;
      if (size > maxSize) {
        if (!overMaxSize) {
          myLogger.log(Logger.WARNING, "MessageManager queue size > "+maxSize);
          overMaxSize = true;
        }
        sleepTime = (1 + ((size - maxSize) / 1000000)) * 100;
      }
    }
      if (sleepTime > 0) {
        try { // delay a bit this Thread because the queue is becoming too big
          Thread.sleep(sleepTime);
        }
        catch (InterruptedException ie) {}
      }
    }

  /**
   * The method decreases the value of size and, eventually,
   * set to false the value of overMaxSize.
   * <p>
   * This method should have been declared synchronized.
   * For possible better peformance, it is not declared synchronized because
   * it is a private method and it is called only
   * by the method get() which is already synchronized.
   * @param k the value by which size must be decremented
   */
  private void decreaseSize(int k) {
    size -= k;
    if (size < maxSize) {
      if (overMaxSize) {
        myLogger.log(Logger.INFO, "MessageManager queue size < "+maxSize);
        overMaxSize = false;
      }
    }
  }
 
  /**
   * This class represents a Box of messages to be delivered to
   * a single receiver
   */
  private class Box {
      private final AID receiver;
      private boolean busy;
      private String owner;
      private final List messages;
   
    public Box(AID r) {
      receiver = r;
      busy = false;
      messages = new LinkedList();
    }
   
    private AID getReceiver() {
      return receiver;
    }

    private void setBusy(boolean b){
      busy = b;
      //#J2ME_EXCLUDE_BEGIN
      owner = (busy ? Thread.currentThread().getName() : null);
      //#J2ME_EXCLUDE_END
    }
   
    private boolean isBusy(){
      return busy;
    }
   
    private void addLast(PendingMsg pm) {
      messages.add(pm);
    }
   
    private PendingMsg removeFirst() {
      return (PendingMsg) messages.remove(0);
    }
   
    private boolean isEmpty() {
      return messages.isEmpty();
   
   
    // For debugging purpose
    public String toString() {
      return "("+receiver.getName()+" :busy "+busy+ (owner != null ? " :owner "+owner : "") + " :message-cnt "+messages.size()+")";
    }
  } // END of inner class Box
 
 
  // For debugging purpose
  synchronized String[] getStatus() {
    Object[] boxes = messagesByOrder.toArray();
    String[] status = new String[boxes.length];
    for (int i = 0; i < boxes.length; ++i) {
      status[i] = boxes[i].toString();
    }
    return status;
 
 
  // For debugging purpose
  int getSize() {
    return size;
  }
 
  long getSubmittedCnt() {
    return submittedCnt;
  }
 
  long getServedCnt() {
    return servedCnt;
  }
}
TOP

Related Classes of jade.core.messaging.OutBox$Box

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.