Вы находитесь на странице: 1из 12

Building Multi-Agent Systems with JADE

Introduction 1. 2. 3. 4. 5. 6. 7. Installing the software Your first programs Parallelism and Behaviours Agent communication Using the Directory Facilities (DF) Using Jade Behaviours

--> Using ontologies


o o o

7.1 The bank example 7.2. Messages with serialized Java objects 7.3. Defining an application-specific ontology 8. Graphical Interfaces 9. Mobility

7. Using ontologies
If agents are to communicate in a way that makes sense for them, they must share the same language, vocabulary and protocols. By following FIPA standards, Jade already supports a certain degree of commonality; this is evident in the use of FIPA communicative acts and the Coder/Decoder classes for SLn languages which determine the form of the messages exchanged between agents. However, you will need to define your own vocabulary and semantics for the content of the messsages exchanged between your agents. This means defining an ontology. In fact, JADE provides three ways to implement communication between agents. 1. The first and most basic way consists of using strings to represent the content of messages. This is the technique that we have used so far in all of our examples. This is convenient when the content of messages is atomic data, but not in the case of abstract concepts, objects or structured data. In such cases, the string needs to be parsed to access its various parts. 2. The second way exploits Java technology to transmit Serialized Java objects directly as the content of messages. This is often a convenient method for a local application where all agents are implemented in Java. One inconvenience is that these messages are not readable by humans.

3. The third method involves the definition of the objects to be transferred as extension of predefined classes so that Jade can encode and decode messages in a standard FIPA format. This allows Jade agents to interoperate with other agent systems. The three types of message content are reflected by three Depending on the types of message content, different methods will be used to set and get content. The table below gives the correspondance. Content type Strings Java Objects Ontology Objects Getting content getContent() extractContent() Setting content SetContent() fillContent()

getContentObject() SetContentObject()

In what follows, we take one application, a Bank example, and implement it in two ways. First, we implement communication between agents using serialized Java objects. Then, we go the more formal route and convert our objects into an ontology with the support provided by JADE.

7.1 The bank example


In this example, we create two agents which implement the client and server roles for a bank with savings accounts. The BankServerAgent class, acts as a server and the BankClientAgent class acts as client. The two classes use (implement) a common interface, BankVocabulary, that defines the constants which represent the terms that constitute the specific language of the agents. The bank directory consists of 3 subdirectories that contain the source code for 3 versions of the example. The first version, Bank-1-jObjects, shows how to implement communication between agents using Java objects. The second version, Bank-2-Onto, shows how to implement the communication between agents using an ontology. And the third directory, Bank-3-Gui, adds a graphical user interface that will be the subject of the next chapter. The conversation between the two agents follows a very simple protocol. To create an account or to make an operation, the client agent sends a REQUEST message to the server agent. The server agent responds with an INFORM after processing the request or with an NOT_UNDERSTOOD if it cannot decode the content of the message. To query information about a specific account, the client agent sends a QUERY_REF to the server agent which responds with an INFORM after processing the query or with a NOT_UNDERSTOOD if it cannot decode the content of the message.

7.2. Messages with serialized Java objects


In modeling the interaction between various agents, it is useful to identify the pertinent concepts and actions and to define these as classes. Here are the classes that are used in the Bank application:

y y y y y y

Account: concept of a bank savings account Operation: concept of a bank operation MakeOperation: action of making an operation such as deposit or withdrawal OperationList: concept of the list of last operations CreateAccount: action of creating an account Information: concept of querying information about an account such as the balance and the list of last operations Problem: result of an action that fails

These classes can be found in the source file for the server. If objects are to sent as parts of messages, it is imperative that they are declared to implement the java.io.Serializable interface, otherwise the serialization of the content of the messages before their sending will fail. Below is the definition of the MakeOperation class. Here we follow the usual OO practice of declaring the class attributes private and adding public accessor (set/get) methods. This also means that later, when we turn these classes into Ontology Content Elements, they can be reused with almost no modification.
class MakeOperation implements java.io.Serializable { private String accountId; private int type; private float amount; public String getAccountId() { return accountId; } public int getType() { return type; } public float getAmount() { return amount; } public void setAccountId(String accountId) { this.accountId = accountId; } public void setType(int type) { this.type = type; } public void setAmount(float amount) { this.amount = amount; } }

Here is an extract of BankClientAgent where the client REQUESTs the server to carry out a given operation. This is done by creating and sending a MakeOperation object.

MakeOperation mo = new MakeOperation(); mo.setAccountId(acc.getId()); mo.setType(command); mo.setAmount(amount); ACLMessage msg = new ACLMessage( ACLMessage.REQUEST ); msg.addReceiver(server); try { msg.setContentObject( mo ); } catch (Exception ex) { ex.printStackTrace(); } send(msg);

On the other side, the server receives and decode the content of the message as implemented in the inner classes ReceiveMessages and HandleOperation of the BankServerAgent class:
class ReceiveMessages extends CyclicBehaviour { public ReceiveMessages(Agent a) { super(a); } public void action() { ACLMessage msg = receive(); if (msg == null) { block(); return; } try { Object content = msg.getContentObject(); switch (msg.getPerformative()) { case (ACLMessage.REQUEST): if (action instanceof CreateAccount) addBehaviour(new HandleCreateAccount(myAgent, msg)); else if (content instanceof MakeOperation) addBehaviour(new HandleOperation(myAgent, msg)); ... } } class HandleOperation extends OneShotBehaviour { ACLMessage request; public HandleOperation(Agent a, ACLMessage request) { super(a); this.request = request } public void action() {

try { Operation op = (Operation) request.getContentObject(); ACLMessage reply = request.createReply(); // Process the operation Object result = processOperation(op); ... } catch (Exception ex) { ex.printStackTrace(); } } }

7.3. Defining an application-specific ontology


An application-specific ontology describes the elements that can be used as content of agent messages.An ontology is composed of two parts, a vocabulary that describe the terminology of concepts used by agents in their space of communication, and the nomenclature of the relationships between these concepts, and that describe their semantic and structure. You implement an ontology for your application by extending the class Ontology predefined in JADE and adding a set of element schemas describing the structure of concepts, actions, and predicates that are allowed to compose the content of your messages. You may also extend directly the basic ontology classes BasicOntology or ACLOntology according to your need. But if you do so, you also indirectly extend the ontology class since these two classes are themselves subclasses of the Ontology class. In the version 2 of the bank example, we defined the BankOntology class that our two agents use to communicate in place of the java objects that we discussed previously. We do not "throw away" our java objects that remain in fact valid, but instead of using them directly in the content of messages, we just wrapp them into specifics terms and concepts defined within the BankOntology class. To do that, we just modified slightly our java classes by making them implement the appropriate interfaces provided by JADE. In fact, when defining an ontology you will generally deal with the three interfaces Concept, AgentAction and Predicate. The corresponding classes to be used in your ontology class are respectively the ConceptSchema, AgentActionSchema and PredicateSchema. Examining the hierarchy of these classes, we see that the AgentActionSchema class inherits from the ConceptSchema class which in turn is a subclass of the TermSchema class. While the PredicateSchema class inherits from the ContentElementSchema class. But at the base, these interfaces have a common superclass which is the ObjectSchema class.
java.lang.Object | +--jade.content.schema.ObjectSchema | +--jade.content.schema.ObjectSchemaImpl | +--jade.content.schema.TermSchema

| +--jade.content.schema.ConceptSchema | +--jade.content.schema.AgentActionSchema java.lang.Object | +--jade.content.schema.ObjectSchema | +--jade.content.schema.ObjectSchemaImpl | +--jade.content.schema.ContentElementSchema | +--jade.content.schema.PredicateSchema

An important point to know is when to use one or another of these ontology objects. To briefly explain that, let's examine these three examples: 1. Agent A requests agent B to perform a specific task. According to FIPA, the content of the message that A sends to B must be an "action", i.e., a tuple which slots are the identifier of agent that is requested to perform the action (here agent B) and a descriptor respresenting the task to be performed (here the requested task). In JADE, the task will be defined by a java object implementing the AgentAction interface and the action will be an instance of the class Action to which you pass in arguments the AID of agent B and the object describing the task to be performed.

2. Agent A asks agent B if a given proposition is true. According to FIPA, the content of the message must be the object representing the proposition to check. In JADE a proposition can be defined by a java object implementing the interface Predicate.

3. Now let's take an example closer to our bank example: suppose the client agent requests the server agent to perform an action consisting of making a deposit on a given account. To do this, we defined the class MakeOperation describing the action to be performed. Since it is an action, we make the MakeOperation class implement the AgentAction interface. On the server side, once it has processed the information, it replies by sending back together with the requested action wrapped in a Result object, an Account object representing the result of processing the operation or a Problem object if the action failed. As the Account and Problem object are not agent actions neither propositions, we simply defined them as concepts by implementing the interface Concept.

Besides these three interfaces that allow you to define the abstracts objects of your application ontology, JADE also provides support for defining atomic elements that constitute generally the slots of the abstract concepts, such as String, Integer, Float and so on. The support for these atomic types of objects is provided through the class PrimitiveSchema and handled by the BasicOntology class. Applying these principles, the java objects previously defined in the version 1 of the bank example are modified as follows (you can access the files under the directory Bank-2-Onto):
y y y y y y

the Account class now implements the Concept interface the Operation class implements the Concept interface the MakeOperation class implements the AgentAction interface the CreateAccount class implements the AgentAction interface the Information class implements the AgentAction interface the Problem class implements the Concept interface

Comparativeley with the version 1, only one class disappeared. This is the OperationList class which is of no use now since the Result class (which is provided by JADE) that we use to hold the result of actions that are performed by the server agent already contains a List object as attribute. Now let's see step by step how to put together all these pieces of puzzle to define an applicationspecific ontology by examining the example of making an operation. Step 1: you define the vocabulary of your agents communication space. In the BankVocabulary interface, we have the following lines of code that define the terminology involved in the concept of making an operation:
public interface BankVocabulary { ... public public public public ... } static static static static final final final final String String String String MAKE_OPERATION = "MakeOperation"; MAKE_OPERATION_TYPE = "type"; MAKE_OPERATION_AMOUNT = "amount"; MAKE_OPERATION_ACCOUNTID = "accountId";

Step 2: you define the java class that specifies the structure and semantic of the object MakeOperation. This is almost the same definition as we used in the previous example except that it implements AgentAction and not java.io.Serializable
class MakeOperation implements AgentAction { private String accountId; private int type;

private float amount; public String getAccountId() { return accountId; } public int getType() { return type; } public float getAmount() { return amount; } public void setAccountId(String accountId) { this.accountId = accountId; } public void setType(int type) { this.type = type; } public void setAmount(float amount) { this.amount = amount; } }

A java class defining an ontology object must necessarily include the set and get methods that allow to access the attributes of the class that must be declared private. Take care when choosing the attributes names of your object and their corresponding get and set methods. In fact, you can not choose any name you like at this step because they must imperatively match (case insensitive) the names that you gave to these attributes when defining the vocabulary. for example in the vocabulary, we decided that the name for the element MAKE_OPERATION_TYPE is "type". So in the java class, the name of the attribute must be type and the corresponding get and set methods must be getType() and setType(). This is an important point to be aware about because during the operation of filling the content of the message, the content manager first reads the attribute type that it associates with the class MakeOperation. It then searches in the ontology under the MakeOperation schema, for the element identified in the vocabulary by the name "type". If it cannot find such an element it throws an exception. Step 3: you define the schema of the object. In the BankOntology class we find these lines of code that specifiy the schema of the concept MakeOperation:
public class BankOntology extends Ontology implements BankVocabulary { // ----------> The name identifying this ontology public static final String ONTOLOGY_NAME = "Bank-Ontology"; // ----------> The singleton instance of this ontology private static Ontology instance = new BankOntology();

// ----------> Method to access the singleton ontology object public static Ontology getInstance() { return instance; } // Private constructor private BankOntology() { super(ONTOLOGY_NAME, BasicOntology.getInstance()); try { // ------- Add Concepts ... // ------- Add AgentActions ... // MakeOperation add(as = new AgentActionSchema(MAKE_OPERATION), MakeOperation.class); as.add(MAKE_OPERATION_TYPE, (PrimitiveSchema) getSchema(BasicOntology.INTEGER), ObjectSchema.MANDATORY); as.add(MAKE_OPERATION_AMOUNT, (PrimitiveSchema) getSchema(BasicOntology.FLOAT), ObjectSchema.MANDATORY); as.add(MAKE_OPERATION_ACCOUNTID, (PrimitiveSchema) getSchema(BasicOntology.STRING), ObjectSchema.MANDATORY); ... } catch (OntologyException oe) { oe.printStackTrace(); } } }// BankOntology

Note that the constructor of your ontology class must be defined with private access and include the static public method getInstance() that your agent program calls to get a reference to the singleton instance of your ontology class. In the class AgentActionSchema, you have a set of add(...) methods, some of which are inherited from the ConceptSchema class that it extends. These methods allow you to add to the schema of the object that you are defining, the elements that will be used by the content manager as slots when filling the content of messages. In our example, we used the add() method that takes three arguments, the name of the slot to be added, the schema of this slot and the optionality. The optionlaity can take two values: MANDATORY indicating that the slot cannot have a null value, or OPTIONAL indicating that it can have a null value. The consequence is that if you specify MANDATORY, then this element must be imperatively provided when setting the values of corresponding attributes in the java class. On the other hand if you specify OPTIONAL, you are allowed to not provide a value for this slot.

Step 4: you are now ready to use the ontology for the content of your agents messages. To set the content of a message using an ontology, you must first register with the agent's content manager, the ontology and the language that will be used for assembling and parsing(or coding and decoding) the content of messages. In our example we use the codec language which is implemented in JADE through the class SLCodec and the ontology is naturally our BankOntology: In the BankClientAgent class in the directory Bank-2-Onto, you find these lines of code that illustrate how to register the language and ontology:
public class BankClientAgent extends Agent implements BankVocabulary { ... private Codec codec = new SLCodec(); private Ontology ontology = BankOntology.getInstance(); protected void setup() { // Register language and ontology getContentManager().registerLanguage(codec); getContentManager().registerOntology(ontology); ... } ... }//class BankClientAgent

To use the ontoloy when composing your message, you first set the attributes of your java object. Then you specify within the message instance, the language and ontology that it complies to. you then obtain a reference to the ContentManager object by calling the method getContentManager() of the Agent class. Finally you call the fillContent(...) method of the ContentManager object to which you pass in arguments the message and the content that it will be filled with. This is done through the following lines of code:
public class BankClientAgent extends Agent implements BankVocabulary { ... void requestOperation() { .... MakeOperation mo = new MakeOperation(); mo.setType(command); mo.setAmount(amount); mo.setAccountId(acc.getId()); sendMessage(ACLMessage.REQUEST, mo); } ... void sendMessage(int performative, AgentAction action) {

... ACLMessage msg = new ACLMessage(performative); msg.setLanguage(codec.getName()); msg.setOntology(ontology.getName()); try { getContentManager().fillContent(msg, new Action(server, action)); msg.addReceiver(server); send(msg); ... } catch (Exception ex) { ex.printStackTrace(); } } }//End BankClientAgent

At the server side, you follow the same steps to receive and extract the content of the message. The server agent must also register its content manager with the same language and ontology. Then, obtaining a reference to the content manager object it calls its method extractContent(...) to which it passes in argument the message to be extracted. It then casts the extracted content with the java class that it was expecting. Once it has the java object, it can finally retrieve the content of the slots by calling the get methods provided in the java class of the object. This is illustrated through the following lines of code in the BankServerAgent class:
public class BankServerAgent extends Agent implements BankVocabulary { ... private Codec codec = new SLCodec(); private Ontology ontology = BankOntology.getInstance(); ... protected void setup() { // Register language and ontology getContentManager().registerLanguage(codec); getContentManager().registerOntology(ontology); ... } ... class ReceiveMessages extends CyclicBehaviour { public ReceiveMessages(Agent a) { super(a); } public void action() { ACLMessage msg = receive(); if (msg == null) { block(); return; } try { ContentElement content = getContentManager().extractContent(msg); Concept action = ((Action)content).getAction();

switch (msg.getPerformative()) { case (ACLMessage.REQUEST): ... if (action instanceof CreateAccount) addBehaviour(new HandleCreateAccount(myAgent, msg)); else if (action instanceof MakeOperation) addBehaviour(new HandleOperation(myAgent, msg)); ... break; ... } catch(Exception ex) { ex.printStackTrace(); } } }// End ReceiveMessages ... class HandleOperation extends OneShotBehaviour { private ACLMessage request; HandleOperation(Agent a, ACLMessage request) { super(a); this.request = request; } public void action() { try { ContentElement content = getContentManager().extractContent(request); MakeOperation mo = (MakeOperation)((Action)content).getAction(); //Process the operation Object obj = processOperation(mo); //Send the reply ... } catch(Exception ex) { ex.printStackTrace(); } } }// End HandleOperation ... }// End BankServerAgent

Top Previous Next

Вам также может понравиться