Package jade.core.behaviours

Source Code of jade.core.behaviours.OntologyServer

package jade.core.behaviours;

//#J2ME_EXCLUDE_FILE

import jade.core.behaviours.CyclicBehaviour;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import jade.content.AgentAction;
import jade.content.ContentElement;
import jade.content.ContentException;
import jade.content.ContentManager;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.content.onto.basic.Done;
import jade.content.onto.basic.Result;
import jade.core.Agent;
import jade.domain.FIPAAgentManagement.ExceptionVocabulary;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.ConversationList;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.MessageTemplate.MatchExpression;
import jade.util.Logger;

/**
* Ready made behaviour that for each incoming message automatically invoke a corresponding method of the form<br>
* <code>
* public void serveCcccPppp(Cccc c, ACLMessage msg) throws Exception
* </code>
* <br>
* where c represents the key content-element referenced by the incoming message msg.<br>
* ContentElement-s representing SL0 operators action, done and result are automatically managed
* so that for instance if an incoming REQUEST message is received carrying a content of type<br>
* ((action (actor ...) (Sell ...)))<br>
* a serving method with signature<br>
* <code>
* public void serveSellRequest(Sell s, ACLMessage msg) throws Exception
* </code>
* <br>
* will be searched.<br>
* Serving methods are responsible for sending back responses if any. 
*/
public class OntologyServer extends CyclicBehaviour {
  private static final long serialVersionUID = -2997404961058073783L;

  private static final String[] performativeNames = new String[22];
  static {
    performativeNames[ACLMessage.ACCEPT_PROPOSAL]="AcceptProposal";
    performativeNames[ACLMessage.AGREE]="Agree";
    performativeNames[ACLMessage.CANCEL]="Cancel";
    performativeNames[ACLMessage.CFP]="Cfp";
    performativeNames[ACLMessage.CONFIRM]="Confirm";
    performativeNames[ACLMessage.DISCONFIRM]="Disconfirm";
    performativeNames[ACLMessage.FAILURE]="Failure";
    performativeNames[ACLMessage.INFORM]="Inform";
    performativeNames[ACLMessage.INFORM_IF]="InformIf";
    performativeNames[ACLMessage.INFORM_REF]="InformRef";
    performativeNames[ACLMessage.NOT_UNDERSTOOD]="NotUNderstood";
    performativeNames[ACLMessage.PROPOSE]="Propose";
    performativeNames[ACLMessage.QUERY_IF]="QueryIf";
    performativeNames[ACLMessage.QUERY_REF]="QueryRef";
    performativeNames[ACLMessage.REFUSE]="Refuse";
    performativeNames[ACLMessage.REJECT_PROPOSAL]="RejectProposal";
    performativeNames[ACLMessage.REQUEST]="Request";
    performativeNames[ACLMessage.REQUEST_WHEN]="RequestWhen";
    performativeNames[ACLMessage.REQUEST_WHENEVER]="RequestWhenever";
    performativeNames[ACLMessage.SUBSCRIBE]="Subscribe";
    performativeNames[ACLMessage.PROXY]="Proxy";
    performativeNames[ACLMessage.PROPAGATE]="Propagate";
  }
 
  private Object serverDelegate;
  private Ontology onto;
  private Codec codec;
  private int[] servedPerformatives;
 
  private ConversationList ignoredConversations;
  private MessageTemplate template;
 
  private Map<String, Method> cachedMethods = new HashMap<String, Method>();
  private ContentElement receivedContentElement;
 
  protected Logger myLogger = Logger.getMyLogger(getClass().getName());
 
  public OntologyServer(Agent a, Ontology onto, int performative) {
    this(a, onto, new int[]{performative}, null);
  }
 
  public OntologyServer(Agent a, Ontology onto, int[] performatives) {
    this(a, onto, performatives, null);
  }
 
  public OntologyServer(Agent a, Ontology onto, int performative, Object serverDelegate) {
    this(a, onto, new int[]{performative}, serverDelegate);
  }
 
  public OntologyServer(Agent a, Ontology onto, int[] performatives, Object serverDelegate) {
    super(a);
   
    this.onto = onto;
    servedPerformatives = performatives;
    this.serverDelegate = (serverDelegate != null ? serverDelegate : this);
    if (servedPerformatives != null) {
      if (servedPerformatives.length == 1) {
        // E.g. XXX-Ontology-Request-Server
        setBehaviourName(onto.getName()+"-"+performativeNames[servedPerformatives[0]]+"-Serever");
      }
      else {
        // E.g. XXX-Ontology-Request...-Server
        setBehaviourName(onto.getName()+"-"+performativeNames[servedPerformatives[0]]+"...-Serever");
      }
    }
    else {
      // E.g. XXX-Ontology-Server
      setBehaviourName(onto.getName()+"-Serever");
    }
  }
 
  public void setLanguage(Codec codec) {
    this.codec = codec;
  }
 
  public void setMessageTemplate(MessageTemplate template) {
    this.template = template;
  }
 
  public void onStart() {
    ignoredConversations = new ConversationList(myAgent);
   
    // Unless a template is explicitly set, we get messages matching the ontology, the served performatives.
    if (template == null) {
      if (servedPerformatives != null) {
        template = MessageTemplate.and(
            MessageTemplate.MatchOntology(onto.getName()),
              new MessageTemplate(new MatchExpression() {
                public boolean match(ACLMessage msg) {
                  int perf = msg.getPerformative();
                  for (int p : servedPerformatives) {
                    if (p == perf) {
                      return true;
                    }
                  }
                  return false;
                }
              })
            );
      }
      else {
        // No performative specified --> Match all
        template = MessageTemplate.MatchOntology(onto.getName());
      }
    }
    // Whatever template is used we avoid intercepting messages belonging to external conversations
    template  = MessageTemplate.and(template, ignoredConversations.getMessageTemplate());
 
    // Register Ontology and Language
    ContentManager cm = myAgent.getContentManager();
    if (cm.lookupOntology(onto.getName()) == null) {
      cm.registerOntology(onto);
    }
    this.codec = (codec != null ? codec : new SLCodec());
    if (cm.lookupLanguage(codec.getName()) == null) {
      cm.registerLanguage(codec);
    }
  }

  public final void action() {
    ACLMessage msg = myAgent.receive(template);
    if (msg != null) {
      if (myLogger.isLoggable(Logger.FINER)) {
        myLogger.log(Logger.FINER, "Agent "+myAgent.getName()+" - Serving incoming message "+msg);
      }
      handleMessage(msg);
    }
    else {
      block();
    }
  }
 
  protected void handleMessage(ACLMessage msg) {
    try {
      receivedContentElement = myAgent.getContentManager().extractContent(msg);
      ContentElement keyCel = extractKeyContentElement(receivedContentElement);
         
      if (myLogger.isLoggable(Logger.FINE)) {
        myLogger.log(Logger.FINE, "Agent "+myAgent.getName()+" - Serving "+keyCel.getClass().getName()+" "+ACLMessage.getPerformative(msg.getPerformative()));
      }
      Method m = findServerMethod(keyCel, msg.getPerformative());
      if (m != null) {
        try {
          m.invoke(serverDelegate, new Object[]{keyCel, msg});
        }
        catch (InvocationTargetException ite) {
          handleServingFailure(ite.getCause(), keyCel, msg);
        }
        catch (Exception e) {
          // Since we only use public methods with proper arguments this can only happen if the serverDelegate class is not accessible
          handleServingFailure(e, keyCel, msg);
        }
      }
      else {
        handleUnsupported(keyCel, msg);
      }
    }
    catch (ContentException ce) {
      handleNotUnderstood(ce, msg);
    }
  }
 
  /**
   * Allows subclasses to retrieve the actually received content element e.g. Action, Done, Result
   * @return
   */
  public final ContentElement getReceivedContentElement() {
    return receivedContentElement;
  }
 
  protected ContentElement extractKeyContentElement(ContentElement ce) {
    // Properly handle the SL action, done and result operators
    if (ce instanceof Action) {
      return (AgentAction) ((Action) ce).getAction();
    }
    else if (ce instanceof Done) {
      AgentAction act = (AgentAction) ((Done) ce).getAction();
      if (act instanceof Action) {
        return (AgentAction) ((Action) act).getAction();
      }
      else {
        return act;
      }
    }
    else if (ce instanceof Result) {
      AgentAction act = (AgentAction) ((Result) ce).getAction();
      if (act instanceof Action) {
        return (AgentAction) ((Action) act).getAction();
      }
      else {
        return act;
      }
    }
    else {
      return ce;
    }
  }
 
  protected void handleUnsupported(ContentElement keyCel, ACLMessage msg) {
    myLogger.log(Logger.WARNING, "Agent "+myAgent.getName()+" - Unsupported content-element "+keyCel.getClass().getName()+". Sender is "+msg.getSender().getName());
    ACLMessage reply = msg.createReply();
    reply.setPerformative(ACLMessage.REFUSE);
    reply.setContent("(("+ExceptionVocabulary.UNSUPPORTEDACT+" "+keyCel.getClass().getName()+"))");
    myAgent.send(reply);
  }
 
  protected void handleServingFailure(Throwable t, ContentElement cel, ACLMessage msg) {
    myLogger.log(Logger.SEVERE, "Agent "+myAgent.getName()+" - Unexpected error serving content-element "+cel.getClass().getName()+". Sender is "+msg.getSender().getName(), t);
    ACLMessage reply = msg.createReply();
    reply.setPerformative(ACLMessage.FAILURE);
    reply.setContent("(("+ExceptionVocabulary.INTERNALERROR+" \""+t+"\"))");
    myAgent.send(reply);
  }
 
  protected void handleNotUnderstood(ContentException ce, ACLMessage msg) {
    myLogger.log(Logger.WARNING, "Agent "+myAgent.getName()+" - Error decoding "+ACLMessage.getPerformative(msg.getPerformative())+" message. Sender is "+msg.getSender().getName(), ce);
    ACLMessage reply = msg.createReply();
    reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
    myAgent.send(reply);
  }
 
  private Method findServerMethod(ContentElement cel, int performative) {
    Class c = cel.getClass();
    String performativeName = performativeNames[performative];
    String key = c.getSimpleName()+performativeName;
    Method m = (Method) cachedMethods.get(key);
    if (m != null) {
      // Cache hit!
      return m;
    }
    // Note that we may have received a ContentElement that extends another one --> Possibly there is no serving
    // method for the received ContentElement, but there is one for the parent ContentElement
    while (!c.equals(Object.class)) {
      String methodName = "serve"+c.getSimpleName()+performativeName;
      Class[] methodParamTypes = new Class[]{c, ACLMessage.class};
      try {
        m = serverDelegate.getClass().getMethod(methodName, methodParamTypes);
        cachedMethods.put(key, m);
        break;
      }
      catch (NoSuchMethodException nsme) {
        // Try with the ContentElement superclass
        c = c.getSuperclass();
      }
    }
    return m;
  }
 
  public void ignoreConversation(String convId) {
    ignoredConversations.registerConversation(convId);
  }
 
  public void conversationFinished(String convId) {
    ignoredConversations.deregisterConversation(convId);
  }
}
TOP

Related Classes of jade.core.behaviours.OntologyServer

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.