JADE

This talk summarizes material from:

1 Introduction

2 Features

3 Architecture

4 GUI

5 Communications

6 ACLMessage Class

7 Agent Execution

Behavior classes

8 Writing your Agent

9 Ping Agent

import java.util.Date;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;

import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.DFService;
import jade.domain.FIPAException;

/**
   This agent implements a simple Ping Agent for the AgentCities project.
   First of all the agent registers itself with the DF of the platform and 
   then waits for ACLMessages.
   If  a QUERY_REF message arrives that contains the string "ping" within the content 
   then it replies with an INFORM message whose content will be the string "alive". 
   If it receives a NOT_UNDERSTOOD message no reply is sent. 
   For any other message received it replies with a NOT_UNDERSTOOD message.
   The exchanged message are written in a log file whose name is the local name of the agent.

   @author Tiziana Trucco - CSELT S.p.A.
   @version  $Date: 2002/01/31 09:58:40 $ $Revision: 1.4 $  
*/


public class PingAgent extends Agent {

  PrintWriter logFile;
  
  class WaitPingAndReplyBehaviour extends SimpleBehaviour {

    private boolean finished = false;
    
    public WaitPingAndReplyBehaviour(Agent a) {
      super(a);
    }

    public void action() {
      
      ACLMessage  msg = blockingReceive();
      
      if(msg != null){
        if(msg.getPerformative() == ACLMessage.NOT_UNDERSTOOD)
        {
          log("Received the following message: "+ msg.toString());
          log("No reply message sent.");
        }
        else{
          log("Received the following message: "+ msg.toString());
          ACLMessage reply = msg.createReply();
        
          //if((msg.getPerformative()== ACLMessage.QUERY_REF)||(msg.getPerformative()== ACLMessage.QUERY_IF))
          if(msg.getPerformative()== ACLMessage.QUERY_REF)
          {
            String content = msg.getContent();
            if ((content != null) && (content.indexOf("ping") != -1))
            {
              reply.setPerformative(ACLMessage.INFORM);
              //reply.setContent("(pong)");
              reply.setContent("alive");
            }
            else
            {
              reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
              reply.setContent("( UnexpectedContent (expected ping))");
            }
      
          }
          else
          {
            reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
            reply.setContent("( (Unexpected-act "+ACLMessage.getPerformative(msg.getPerformative())+") ( expected (query-ref :content ping)))");

          }
                  
          log("Replied with the following message: "+ reply.toString());
          send(reply);
        }
      }else{
        //System.out.println("No message received");
      }
    }
  
    public boolean done() {
      return finished;
    }
  } //End class WaitPingAndReplyBehaviour
    
  
  protected void setup() {
    
    /** Registration with the DF */
    DFAgentDescription dfd = new DFAgentDescription();
    ServiceDescription sd = new ServiceDescription();   
    sd.setType("AgentcitiesPingAgent"); 
    sd.setName(getName());
    sd.setOwnership("TILAB");
    //sd.addOntologies("PingAgent");
    dfd.setName(getAID());
    dfd.addServices(sd);
    try {
      DFService.register(this,dfd);
    } catch (FIPAException e) {
      System.err.println(getLocalName()+" registration with DF unsucceeded. Reason: "+e.getMessage());
      doDelete();
    }
      
    try{
      logFile = new PrintWriter(new FileWriter(getLocalName()+".txt",true));
      log("Agent: " + getName() + " born");
      WaitPingAndReplyBehaviour PingBehaviour = new  WaitPingAndReplyBehaviour(this);
      addBehaviour(PingBehaviour);
    }catch(IOException e){
      System.out.println("WARNING: The agent needs the "+ getLocalName()+".txt file.");
      e.printStackTrace();
    }
  }

  public synchronized void log(String str) {
        
    logFile.println((new Date()).toString()+ " - " + str);
    logFile.flush();
  }
    
}//end class PingAgent

10 ComplexBehaviourAgent

package examples.behaviours;

import jade.core.Agent;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.core.behaviours.Behaviour;

/**
   This is an example of recursive aggregation of composite agent behaviours.
   A composite behaviour is created, composed of some Sequential Behaviours, 
   and OneShot behaviours.
   @author Giovanni Rimassa - Università di Parma
   @version  $Date: 2001/08/06 14:10:07 $ $Revision: 2.2 $  
*/

// 
public class ComplexBehaviourAgent extends Agent {

  class Behaviour3Step extends OneShotBehaviour {

    private String myCode;

    public Behaviour3Step(Agent a, String code) {
      super(a);
      myCode = code;
    }

    public void action() {
      System.out.println("Agent " + getName() + ": Step " + myCode);
    }

  }


  protected void setup() {

    SequentialBehaviour myBehaviour1 = new SequentialBehaviour(this) {
      
        public int onEnd() {
          reset();
          return super.onEnd();
        }
      };

    SequentialBehaviour myBehaviour2 = new SequentialBehaviour(this);

    SequentialBehaviour myBehaviour2_1 = new SequentialBehaviour(this);
    SequentialBehaviour myBehaviour2_2 = new SequentialBehaviour(this);

    myBehaviour2_1.addSubBehaviour(new Behaviour3Step(this,"2.1.1"));
    myBehaviour2_1.addSubBehaviour(new Behaviour3Step(this,"2.1.2"));
    myBehaviour2_1.addSubBehaviour(new Behaviour3Step(this,"2.1.3"));

    myBehaviour2_2.addSubBehaviour(new Behaviour3Step(this,"2.2.1"));
    myBehaviour2_2.addSubBehaviour(new Behaviour3Step(this,"2.2.2"));
    Behaviour b = new Behaviour3Step(this,"2.2.3");
    myBehaviour2_2.addSubBehaviour(b);

    myBehaviour1.addSubBehaviour(new Behaviour3Step(this,"1.1"));
    myBehaviour1.addSubBehaviour(new Behaviour3Step(this,"1.2"));
    myBehaviour1.addSubBehaviour(new Behaviour3Step(this,"1.3"));

    myBehaviour2.addSubBehaviour(myBehaviour2_1);
    myBehaviour2.addSubBehaviour(myBehaviour2_2);

    myBehaviour2.addSubBehaviour(new Behaviour3Step(this,"2.3"));
    myBehaviour2.addSubBehaviour(new Behaviour3Step(this,"2.4"));
    myBehaviour2.addSubBehaviour(new Behaviour3Step(this,"2.5"));

    addBehaviour(myBehaviour1);
    addBehaviour(myBehaviour2);

  }


}

11 Agents with a GUI

11.1 GUI Agent Example

package examples.mobile;

import java.util.Vector;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Iterator;
import jade.core.*;
import jade.core.behaviours.*;

import jade.domain.mobility.*;
import jade.domain.FIPANames;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;

import jade.gui.GuiAgent;
import jade.gui.GuiEvent;

import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;


/**
   This is an example of mobile agent. This class contains the resources
   used by the agent behaviours: the counter, the flag cntEnabled, and
   the list of visited locations. At the setup it creates a gui and adds
   behaviours to: get the list of available locations from AMS, serve the
   incoming messages, and to increment the counter. In particular, notice
   the usage of the two methods <code>beforeMove()</code> and
   <code>afterMove()</code> to execute some application-specific tasks
   just before and just after the agent migration takes effect.

   Because this agent has a GUI, it extends the class GuiAgent that, in turn,
   extends the class Agent. Being the GUI a different thread, the communication
   between the agent and its GUI is based on event passing.
   @see jade.gui.GuiAgent
   @author Giovanni Caire - CSELT S.p.A
   @version $Date: 2002/07/18 00:22:29 $ $Revision: 2.9 $
*/
public class MobileAgent extends GuiAgent {
  int     cnt;   // this is the counter
  public boolean cntEnabled;  // this flag indicates if counting is enabled
  transient protected MobileAgentGui gui;  // this is the gui
  Location nextSite;  // this variable holds the destination site

  // These constants are used by the Gui to post Events to the Agent
  public static final int EXIT = 1000;
  public static final int MOVE_EVENT = 1001;
  public static final int STOP_EVENT = 1002;
  public static final int CONTINUE_EVENT = 1003;
  public static final int REFRESH_EVENT = 1004;
  public static final int CLONE_EVENT = 1005;

  // this vector contains the list of visited locations
  Vector visitedLocations = new Vector();

  public void setup() {
    // register the SL0 content language
    getContentManager().registerLanguage(new SLCodec(), FIPANames.ContentLanguage.FIPA_SL0);
    // register the mobility ontology
    getContentManager().registerOntology(MobilityOntology.getInstance());

    // creates and shows the GUI
    gui = new MobileAgentGui(this);
    gui.setVisible(true); 

    // get the list of available locations and show it in the GUI
    addBehaviour(new GetAvailableLocationsBehaviour(this));

    // initialize the counter and the flag
    cnt = 0;
    cntEnabled = true;

    ///////////////////////
      // Add agent behaviours to increment the counter and serve
      // incoming messages
      Behaviour b1 = new CounterBehaviour(this);
      addBehaviour(b1); 
      Behaviour b2 = new ServeIncomingMessagesBehaviour(this);
      addBehaviour(b2); 
  }

  public void takeDown() {
    if (gui!=null) {
      gui.dispose();
      gui.setVisible(false);
    }
    System.out.println(getLocalName()+" is now shutting down.");
  }

  /**
   * This method stops the counter by disabling the flag
   */
  void stopCounter(){
    cntEnabled = false;
  }

  /**
   * This method resume counting by enabling the flag
   */
  void continueCounter(){
    cntEnabled = true;
  }

  /**
   * This method displays the counter in the GUI
   */
  void displayCounter(){
    gui.displayCounter(cnt);
  }
  
   
  protected void beforeClone() {
    System.out.println(getLocalName()+" is now cloning itself.");
  }

  protected void afterClone() {
    System.out.println(getLocalName()+" has cloned itself.");
    afterMove();
  }
  /**
   * This method is executed just before moving the agent to another
   * location. It is automatically called by the JADE framework.
   * It disposes the GUI and prints a bye message on the standard output.
   */
  protected void beforeMove() 
  {
    gui.dispose();
    gui.setVisible(false);
    System.out.println(getLocalName()+" is now moving elsewhere.");
  }

  /**
   * This method is executed as soon as the agent arrives to the new 
   * destination.
   * It creates a new GUI and sets the list of visited locations and
   * the list of available locations (via the behaviour) in the GUI.
   */
  protected void afterMove() {
    System.out.println(getLocalName()+" is just arrived to this location.");
    // creates and shows the GUI
    gui = new MobileAgentGui(this);
    //if the migration is via RMA the variable nextSite can be null.
    if(nextSite != null)
    {
      visitedLocations.addElement(nextSite);
      for (int i=0; i<visitedLocations.size(); i++)
        gui.addVisitedSite((Location)visitedLocations.elementAt(i));
    }
    gui.setVisible(true);   
      
    // Register again SL0 content language and JADE mobility ontology,
    // since they don't migrate.
    getContentManager().registerLanguage(new SLCodec(), FIPANames.ContentLanguage.FIPA_SL0);
    getContentManager().registerOntology(MobilityOntology.getInstance());
    // get the list of available locations from the AMS.
    // FIXME. This list might be stored in the Agent and migrates with it.
    addBehaviour(new GetAvailableLocationsBehaviour(this));
  }

  /////////////////////////////////
    // GUI HANDLING
    

    // AGENT OPERATIONS FOLLOWING GUI EVENTS
    protected void onGuiEvent(GuiEvent ev)
  {
    switch(ev.getType()) 
    {
    case EXIT:
      gui.dispose();
      gui = null;
      doDelete();
      break;
    case MOVE_EVENT:
      Iterator moveParameters = ev.getAllParameter();
      nextSite =(Location)moveParameters.next();
      doMove(nextSite);
      break;
    case CLONE_EVENT:
      Iterator cloneParameters = ev.getAllParameter();
      nextSite =(Location)cloneParameters.next();
      doClone(nextSite,"clone"+cnt+"of"+getName());
      break;
    case STOP_EVENT:
      stopCounter();
      break;
    case CONTINUE_EVENT:
      continueCounter();
      break;
    case REFRESH_EVENT:
      addBehaviour(new GetAvailableLocationsBehaviour(this));
      break;
    }

  }

}

12 Interaction Protocols

12.1 Initiator

package examples.protocols;

import java.io.*;

import jade.core.*;
import jade.core.behaviours.*;
import jade.proto.*;
import jade.lang.acl.*;
import jade.domain.FIPAAgentManagement.*;
import java.util.Vector;
import java.util.Enumeration;

/**
 * This example shows an agent performing the role of the initiator of
 a FIPARequest of FIPAQuery protocol.
 * It sends random  one of the following performatives:
 * <ul>
 * <li> REQUEST <code>ACLMessage</code> to start a FIPA request protocol
 * <li> QUERY-IF or QUERY-REF <code>ACLMessage</code> to start a FIPA Query protocol. 
 * </ul>
 * The user must pass as arguements to the initiator agent the local
 names of the responder agents otherwise the agent exits.
 * This example show how a initiator role of a FIPARequest or
 FIPAQuery protocol can be realized using the
 * <code>AchiveREInitiator</code> behaviour. 
 * @see jade.proto.AchieveREInitiator
 * @see jade.proto.AchiveREResponder
 * @author Tiziana Trucco - Telecom Italia Lab S.p.A
 * @version $Date: 2001/09/18 12:26:17 $ $Revision: 1.4 $
 **/



public class Initiator extends Agent {

  /**
     Creare a new ACLMessage to start a protocol.
  **/
  ACLMessage createNewMessage(){
  
    ACLMessage messageToSend = new ACLMessage(ACLMessage.NOT_UNDERSTOOD);
    double chance = Math.random();
    double range = 1.0/3.0;

    //set the receivers according to the parameter setted.
    Object[] receivers = getArguments();
    if(receivers == null || receivers.length == 0){
      //no receiver set as argument of the agent
      System.out.println( "ERROR: No responders passed as arguments. To run this example launch some responders and pas its local names as argument to the initiator agent" );
      //doDelete();
      System.exit(0);
    }else{
      //set the receiver of the message
      for (int i=0; i<receivers.length; i++)
        messageToSend.addReceiver(new AID((String)receivers[i],false));
    }
    //set the timeout to 10 seconds
    long timeout = System.currentTimeMillis() + 10000;
    messageToSend.setReplyByDate(new java.util.Date(timeout));


    if (chance <range)
    {//sending a REQUEST
      messageToSend.setPerformative(ACLMessage.REQUEST);
      messageToSend.setProtocol(jade.proto.FIPAProtocolNames.FIPA_REQUEST);
    }else if(chance < (range * 2)){
      //sending a QUERY_REF
      messageToSend.setPerformative(ACLMessage.QUERY_REF);
      messageToSend.setProtocol(jade.proto.FIPAProtocolNames.FIPA_QUERY);
      System.out.println("Initiator is sending a Query-Ref message");
    }else {
      //sending a QUERY_IF
      messageToSend.setPerformative(ACLMessage.QUERY_IF);
      messageToSend.setProtocol(jade.proto.FIPAProtocolNames.FIPA_QUERY);
      System.out.println("Initiator is sending a Query-If message");
    }
  
    System.out.println(getLocalName()+" is sending a "+ACLMessage.getPerformative(messageToSend.getPerformative())+" message to initiate the protocol");
    return messageToSend;
  }
    
  public void setup() {
  
    Behaviour b;
    ACLMessage request = createNewMessage();
    //System.out.println(request);
    b = new MyInitiator(this, request, true);
    addBehaviour(b);
  }
    
  /**
     Inner class MyInitiator
  */
  class MyInitiator extends AchieveREInitiator {
    boolean restartOnEnd;
    /**
     * @param req the ACLMessage to be sent in order to initiate the protocol
     * @param restartOnEnd if true the behaviour is reset and readded
     * to the agent queue of behaviours as soon as it terminates. Take
     * care becuase this might cause an infinite loop.
     *
     **/
    public MyInitiator(Agent a, ACLMessage req, boolean restartOnEnd) {
      super(a, req);
      this.restartOnEnd = restartOnEnd;
    }
  
    protected void handleAgree(ACLMessage agree) {
      System.out.println(myAgent.getLocalName()+ " in handleAgree: " + agree);
    }
  
    protected void handleRefuse(ACLMessage refuse) {
      System.out.println(myAgent.getLocalName()+ " in handleRefuse: " + refuse);
    }
    protected void handleFailure(ACLMessage failure) {
      System.out.println(myAgent.getLocalName()+ " in handleFailure: " + failure);
    }
    protected void handleNotUnderstood(ACLMessage notUnderstood) {
      System.out.println(myAgent.getLocalName()+ " in handleNotUnderstood: " + notUnderstood);
    }
    protected void handleInform(ACLMessage inform) {
      System.out.println(myAgent.getLocalName()+ " in handleInform: " + inform);
    }
    protected void handleAllResponses(Vector allResponses) {
      System.out.print(myAgent.getLocalName()+ " in handleAllResponses: ");
      for (Enumeration it = allResponses.elements(); it.hasMoreElements(); ) {
        ACLMessage rsp = (ACLMessage) it.nextElement();
        System.out.print(ACLMessage.getPerformative(rsp.getPerformative())+" ");
      }
      System.out.println();
    }

    protected void handleAllResultNotifications(Vector allResultNotifications) {
      System.out.println(myAgent.getLocalName()+ " in handleAllResultNotifications: ");
      for (Enumeration it = allResultNotifications.elements(); it.hasMoreElements(); ) {
        ACLMessage rsp = (ACLMessage) it.nextElement();
        System.out.print(ACLMessage.getPerformative(rsp.getPerformative())+" ");
      }
      System.out.println();
    }

    protected void handleOutOfSequence(ACLMessage msg){
      System.out.println(myAgent.getLocalName()+ " in handleOutOfSequence: " + msg);
    }
  
    protected Vector prepareRequests(ACLMessage msg) {
      Vector l = super.prepareRequests(msg);
      if (l.size() == 0) //msg was null because the beahviour was reset
        l.addElement(createNewMessage());
      return l;
    }

    public int onEnd(){
      try{
        if (restartOnEnd) {
          System.out.println("\nPress a Key to repeat the protocol: ");
          BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
          String reply = buff.readLine();
    
          reset(createNewMessage());
          myAgent.addBehaviour(this);
        }
      }catch(Exception e){
        e.printStackTrace();
      }
      return super.onEnd();
    }
  
  } // End of inner class MyInitiator
    
}//end class Initiator

12.2 Responder

package examples.protocols;

import jade.core.*;
import jade.core.behaviours.*;
import jade.proto.*;
import jade.lang.acl.*;
import jade.domain.FIPAAgentManagement.*;
import java.io.*;

/**
 * This agent acts as a  responder for the FIPARequest and FIPAQuery protocol
 * The example shows how to write two simple the FIPARequest protocol
 and the FIPAQuery Protocol
 using the <code>AchiveREResponder<code> behaviour.
 * If a REQUEST message arrives the agent could reply in one of the following way:
 <UL>
 * <li> send an AGREE message and then an INFORM message
 * <li> send an AGREE message and then a FAILURE message
 * <li> send an AGREE message and then no message 
 * <li> send an AGREE message and then an out of sequence message
 * <li> send an INFORM message
 * <li> send a REFUSE message
 * <li> send a NOT_UNDERSTOD message
 * <li> send an out of sequence message
 * <li> send no message
 * </ul>
 * If QUERY-IF or QUERY-REF message arrive the agent could reply in one of the following way:
 * <ul>
 * <li> send a NOT_UNDERSTOOD message
 * <li> send a REFUSE message
 * <li> send a FAILURE message
 * <li> send an INFORM message
 * <li> send an out of sequence message
 * <li> send no message
 * </ul> 
 * This agent can be use together with an <code>Initiator</code> agent to see an agent conversation 
 * using random the FIPARequest or FIPAQuery protocol.
 *
 * @see jade.proto.AchieveREInitiator
 * @see jade.proto.AchieveREResponder
 * @author Tiziana Trucco - Telecom Italia Lab S.p.A
 * @version $Date: 2001/09/18 10:28:32 $ $Revision: 1.3 $
 **/


public class Responder extends Agent {
    
  public void setup() {
  
    Behaviour requestB = new MyRequestResponder(this, AchieveREResponder.createMessageTemplate(FIPAProtocolNames.FIPA_REQUEST));
    addBehaviour(requestB);
  
    Behaviour queryB = new MyRequestResponder(this,AchieveREResponder.createMessageTemplate(FIPAProtocolNames.FIPA_QUERY));
    addBehaviour(queryB);
  
  }



    
  /**
     Inner class MyRequestResponder
  */
  class MyRequestResponder extends AchieveREResponder {
    boolean sentAgree = false;
  
    public MyRequestResponder(Agent a, MessageTemplate mt) {
      super(a, mt, null);
    }
  
    protected ACLMessage prepareResponse(ACLMessage request) throws RefuseException, NotUnderstoodException {
      sentAgree=false;
      double chance = Math.random();
      
      double range = 1.0 / 6.0;
      ACLMessage response = request.createReply();
      
      if(chance < range ){
        //send a NOT UNDERSTOOD
        response.setPerformative(ACLMessage.NOT_UNDERSTOOD);
      }else if(chance <(range * 2.0)){
        //send a REFUSE    
        response.setPerformative(ACLMessage.REFUSE);
      }else if (chance < (range * 3.0)){
        //send an AGREE
        response.setPerformative(ACLMessage.AGREE);
        sentAgree = true;
      }else if (chance < (range * 4.0)){
        //send an out of sequence Message
        response.setPerformative(ACLMessage.SUBSCRIBE);
      }else if(chance <(range * 5.0)){
        //send an INFORM
        response.setPerformative(ACLMessage.INFORM);
      }else{
        //check the time out expiration in initiator. 
        response = null;
      }
      System.out.println( myAgent.getLocalName() + " --> is sending "+(response==null?"no":(response.getPerformative()==ACLMessage.SUBSCRIBE?"an out-of-sequence":ACLMessage.getPerformative(response.getPerformative())))+ " response to the protocol initiator." );
      return response;  
    }
  
    protected ACLMessage prepareResultNotification(ACLMessage request, ACLMessage response) throws FailureException {
      
      double chance = Math.random();
      
      ACLMessage resNot = request.createReply();
      
      if(sentAgree){
        if(chance < 0.25){
          //SENDING INFORM
          resNot.setPerformative(ACLMessage.INFORM);
        }else if(chance < 0.50){
          // sending FAILURE
          resNot.setPerformative(ACLMessage.FAILURE);
        }else if(chance < 0.75){
          //sending out of sequence message
          resNot.setPerformative(ACLMessage.SUBSCRIBE);
          myAgent.addBehaviour(new unblockInitiator(myAgent,resNot));
        }else{
          // sending no message checking TIMEOUT of Initiator.
          myAgent.addBehaviour(new unblockInitiator(myAgent,resNot));
          resNot = null;
        }
      }else {
        // the inform message has been already sent.
        resNot = null;
      }
      System.out.println( myAgent.getLocalName() +  " --> is sending "+(resNot==null?"no":(resNot.getPerformative()==ACLMessage.SUBSCRIBE?"an out-of-sequence":ACLMessage.getPerformative(resNot.getPerformative())))+ " result notification to the protocol initiator." );
      return resNot;
    }
  } // End of inner class MyRequestResponder
    
    


    /**
     * This inner class is a behaviour that waits until the user presses a
     * key and then sends a message
     **/
  class unblockInitiator extends OneShotBehaviour {
    ACLMessage msg;
    unblockInitiator(Agent a, ACLMessage msg) {
      super(a);
      this.msg=msg;
    }
    public void action() {
      System.out.println(myAgent.getLocalName() + ": This situation causes the initiator to block forever; when you are tired of waiting, press a key and a FAILURE message will be sent to unblock the initiator ...");
      try {
        BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
        String reply = buff.readLine();
      } catch (IOException e) {
        e.printStackTrace();
      }
      msg.setPerformative(ACLMessage.FAILURE);
      myAgent.send(msg);
    }
  }

}//end of class Responder 

13 Ontology Support

13.1 Content Reference Model

13.2 Steps For Using Ontology Support

  1. Define an ontology including the schemas for the types of predicate, agent action and concept that are pertinent to the addressed domain.
  2. Develop proper Java classes for all types of predicate, agent action and concept in the ontology.
  3. Selecting a suitable content language among those directly supported by JADE. (use SL).
  4. Register the defined ontology and the selected content language for the agent.
  5. Create and handle content expressions as Java objects that are instances of the classes developed in (2) and let JADE translate these Java objects to/from strings or sequences of bytes that fit the content slot of ACLMessages.

13.3 MusicShopOntology

package examples.content.musicShopOntology;

import jade.content.onto.*;
import jade.content.schema.*;
import jade.content.schema.facets.*;
import examples.content.ecommerceOntology.*;

/**
 * Ontology containing music related concepts.
 * @author Giovanni Caire - TILAB
 */
public class MusicShopOntology extends Ontology implements MusicShopVocabulary {
  // NAME
  public static final String ONTOLOGY_NAME = "Music-shop-ontology";
  
  // The singleton instance of this ontology
  // It "inherits" from the ecommerceontology
  private static Ontology theInstance = new MusicShopOntology(ECommerceOntology.getInstance());
  
  public static Ontology getInstance() {
    return theInstance;
  }
  
  /**
   * Constructor
   */
  private MusicShopOntology(Ontology base) {
    super(ONTOLOGY_NAME, base);

    try {
      //Thre are CDs, tracks, and singles (songs)
      add(new ConceptSchema(CD), CD.class);
      add(new ConceptSchema(TRACK), Track.class);
      add(new ConceptSchema(SINGLE), Single.class);

      //Our cs for a CD 
      ConceptSchema cs = (ConceptSchema) getSchema(CD);
      //extends ecommerceontoloty
      cs.addSuperSchema((ConceptSchema) getSchema(ECommerceOntology.ITEM));
      //A CD has a title
      cs.add(CD_TITLE, (PrimitiveSchema) getSchema(BasicOntology.STRING));
      //and tracks
      cs.add(CD_TRACKS, (ConceptSchema) getSchema(TRACK), 1, ObjectSchema.UNLIMITED);

      //a track
      cs = (ConceptSchema) getSchema(TRACK);
      //has a name
      cs.add(TRACK_NAME, (TermSchema) getSchema(BasicOntology.STRING));
      //and a duration
      cs.add(TRACK_DURATION, (TermSchema) getSchema(BasicOntology.INTEGER), ObjectSchema.OPTIONAL);
      //and pcm
      cs.add(TRACK_PCM, (TermSchema) getSchema(BasicOntology.BYTE_SEQUENCE), ObjectSchema.OPTIONAL);
      
      cs = (ConceptSchema) getSchema(SINGLE);
      cs.addSuperSchema((ConceptSchema) getSchema(CD));
      // A SINGLE only includes two tracks 
      cs.addFacet(CD_TRACKS, new CardinalityFacet(2, 2));
    } 
    catch (OntologyException oe) {
      oe.printStackTrace();
    } 
  }

}

13.4 Term Classes

package examples.content.musicShopOntology;

import jade.content.*;
import jade.util.leap.List;
import jade.util.leap.Iterator;
import examples.content.ecommerceOntology.*;

public class CD extends Item {
  private String title = null;
  private List tracks = null;
  
  public String getTitle() {
    return title;
  }
  
  public void setTitle(String t) {
    title = t;
  }
  
  public List getTracks() {
    return tracks;
  }
  
  public void setTracks(List l) {
    tracks = l;
  }

  public String toString() {
    StringBuffer sb = new StringBuffer(title);
    if (tracks != null) {
      Iterator it = tracks.iterator();
      int i = 0;
      while (it.hasNext()) {
        sb.append(" ");
        Track t = (Track) it.next();
        sb.append("track-"+i+": "+t.toString());
        i++;
      }
    }
    return sb.toString();
  }

}


package examples.content.musicShopOntology;

public class Single extends CD {
}


package examples.content.musicShopOntology;

import jade.content.*;

public class Track implements Concept {
  private String name = null;
  private Integer duration = null;
  private byte[] pcm = null;
  
  // NAME
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
  
  // DURATION
  public Integer getDuration() {
    return duration;
  }
  
  public void setDuration(Integer duration) {
    this.duration = duration;
  }
  
  // PCM
  public byte[] getPcm() {
    return pcm;
  }
  
  public void setPcm(byte[] pcm) {
    this.pcm = pcm;
  }
  
  public String toString() {
    return name+(duration != null ? ("["+duration.intValue()+" sec]") : "");
  }
}


//Notice that this is part of the ecommerceOntology
package examples.content.ecommerceOntology;

import jade.content.*;
import jade.core.AID;

public class Owns implements Predicate {
  private AID owner;
  private Item item;
  
  public AID getOwner() {
    return owner;
  }
  
  public void setOwner(AID id) {
    owner = id;
  }
  
  public Item getItem() {
    return item;
  }

  public void setItem(Item i) {
    item = i;
  }
}

13.5 CDTrader

package examples.content;

import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import jade.util.leap.List;
import jade.util.leap.ArrayList;
import jade.util.leap.Iterator;

import jade.content.*;
import jade.content.abs.*;
import jade.content.onto.*;
import jade.content.onto.basic.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;

import examples.content.musicShopOntology.*;
import examples.content.ecommerceOntology.*;

import java.util.Date;

/**
   This is an agent that plays at the same time the part of a seller of 
   CDs and a buyer of CDs.
   More in details the conversation between the "seller" and the "buyer"
   will go on as follows:
   - "Seller" informs "buyer" that he owns a CD ("Synchronicity").
   - "Buyer" asks for the price of that CD
   - "Seller" informs "buyer" about the price
   - "Buyer" requests "seller" to sell him the CD specifying his credit card
   - "Seller" performs the action (this step is not actually implemented as 
   it would imply interacting with a delivery system like UPS and an
   electronic payment system) and notifies "buyer"
*/
public class CDTrader extends Agent {
  private ContentManager manager  = (ContentManager) getContentManager();
  // This agent "speaks" the SL language
  private Codec      codec    = new SLCodec();
  // This agent "knows" the Music-Shop ontology
  private Ontology   ontology = MusicShopOntology.getInstance();

  protected void setup() {

    //regiter the codec and ontology that I am using
    manager.registerLanguage(codec);
    manager.registerOntology(ontology);
  
    // BUYER PART
    addBehaviour(new HandleInformBehaviour(this));
      
    // SELLER PART
    addBehaviour(new HandleQueryBehaviour(this));      
    addBehaviour(new HandleRequestBehaviour(this)); 
      
    CD myCd = new CD();
    myCd.setSerialID(123456);
    myCd.setTitle("Synchronicity");
    List tracks = new ArrayList();
    Track t = new Track();
    t.setName("Synchronicity");
    tracks.add(t);
    t = new Track();
    t.setName("Every breath you take");
    tracks.add(t);
    t = new Track();
    t.setName("King of pain");
    t.setDuration(new Integer(240));
    tracks.add(t);
      
    myCd.setTracks(tracks);
          
    addBehaviour(new InformOwnsBehaviour(this, myCd));      
  }
    
  protected void takeDown() {
    System.out.println(getName()+" exiting ...");
  }
    
  // SELLER informs BUYER that he owns a given Item
  class InformOwnsBehaviour extends OneShotBehaviour {
    private Item it;
    
    public InformOwnsBehaviour(Agent a, Item it) { 
      super(a); 
      this.it = it;
    }
    
    public void action() {
      try {
        System.out.println("\nSELLER: Inform BUYER that I own "+it);

        //This is an example of sending a message using the ontology support.
        
        // Prepare the message
        ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
        AID receiver = getAID(); // Send the message to myself
                    
        msg.setSender(getAID());
        msg.addReceiver(receiver);
        msg.setLanguage(codec.getName());
        msg.setOntology(ontology.getName());

        // Fill the content
        Owns owns = new Owns();
        owns.setOwner(getAID());
        owns.setItem(it);
          
        manager.fillContent(msg, owns);
        send(msg);
      } 
      catch(Exception e) { 
        e.printStackTrace(); 
      }

    }
  }
  
  ///some stuff here
     
}

URLs

  1. JADE - A FIPA-compliant agent framework., http://jmvidal.cse.sc.edu/library/jade.pdf
  2. JADE Programmer's Guide., http://sharon.cselt.it/projects/jade/doc/programmersguide.pdf
  3. JADE Administrators's Guide., http://sharon.cselt.it/projects/jade/doc/administratorsguide.pdf
  4. JADE Tutorial: Application-Defined Content Languages and Ontologies., http://sharon.cselt.it/projects/jade/doc/CLOntoSupport.pdf
  5. http://sharon.cselt.it/projects/jade/, http://sharon.cselt.it/projects/jade/

This talk available at http://jmvidal.cse.sc.edu/talks/jade/
Copyright © 2009 José M. Vidal . All rights reserved.

23 September 2002, 12:07PM