View Javadoc

1       /*
2       * The contents of this file are subject to the BT "ZEUS" Open Source 
3       * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file 
4       * except in compliance with the Licence. You may obtain a copy of the Licence
5       * from $ZEUS_INSTALL/licence.html or alternatively from
6       * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7       * 
8       * Except as stated in Clause 7 of the Licence, software distributed under the
9       * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or 
10      * implied. See the Licence for the specific language governing rights and 
11      * limitations under the Licence.
12      * 
13      * The Original Code is within the package zeus.*.
14      * The Initial Developer of the Original Code is British Telecommunications
15      * public limited company, whose registered office is at 81 Newgate Street, 
16      * London, EC1A 7AJ, England. Portions created by British Telecommunications 
17      * public limited company are Copyright 1996-2001. All Rights Reserved.
18      * 
19      * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20      */
21  
22  
23  package zeus.agents;
24  
25  import zeus.concepts.*;
26  import zeus.actors.intrays.*; 
27  import zeus.actors.outtrays.*;
28  import zeus.actors.factories.*;
29  import zeus.actors.*;
30  import zeus.util.*;
31  import java.net.*; 
32  import java.util.*; 
33  
34  
35  /***
36      SimpleAPI is intended to provide a simple way to program a 
37      Zeus agent. The intention is that the methods that 
38      are implemented here will allow a novice agent programmer to 
39      easily perform a number of the most common task that they will 
40      need to build a functional agent. <p>
41      @author Simon Thompson
42      @since 1.1
43      */
44  public class SimpleAPI {
45      
46      private boolean messQ = false; 
47      private Queue messageQueue = null; 
48      private AgentContext agentContext = null; 
49  
50  
51      /*** 
52          sendMessage can be used to send a message to another agent. 
53          @param performative     the type of message ie. inform,confirm, cfp
54          @param content      the content string in the message - what it is that 
55          you are sending to the other agent
56          @param target       the agent that you are sending this message to. The form 
57          of this string should follow the traditional AID or tcp/ip format 
58          ie. transport://host.place.domain:portNo/context1/context2/contextn/name
59          <br>where <i>transport</i> might be iiop, iiopname, zeus or http, <br>
60          <i>host</i> is the machine that this is on <br> 
61          <i>place</i> is the company or institution's domain name <br>
62          <i>domain</i> is the internet domaine - edu or com or org, or co.uk or fr <br>
63          <i>portNo</i> is an integer which is the port that the agent is listening on <br>
64          <i>contextx</i> is the naming context of the agent addressed <br>
65          <i>name</i> is the name of the agent that is being addressed 
66          @returns a boolean that indicates if the message was sent without an exception being 
67          thrown. 
68         */
69      public boolean sendMessage (String performative, String content, String target) {
70          FIPAPerformative perf = new FIPAPerformative (performative); 
71          perf.setContent(content); 
72          perf.setReceiver (target); 
73          try {
74              TransportFactory tf = agentContext.getTransportFactory(); 
75              OutTray transport = tf.getTransport (target); 
76              InetAddress ip = InetAddress.getLocalHost();
77              String localHost = ip.getHostAddress();
78              InTray myInTray = agentContext.getInTray(); 
79              String sourceAddress = myInTray.getResponseAddress();
80              javax.agent.Envelope env = perf.jasEnvelope(new FIPA_AID_Address(target),sourceAddress);  
81              transport.send(env);} 
82              catch (TransportUnsupportedException tue) { 
83                  return false; }
84              catch (Exception e) { 
85                  e.printStackTrace(); 
86                  System.out.println("Unexpected exception in SimpleAPI.sendMessage() - attempting to recover"); 
87                  return false; 
88              }
89          return true;
90      }
91      
92      
93      /***
94         achieve is used to make the agent attempt to satisfy the 
95         postcondition formed by the parameter toGet[] 
96         The array will be iterated over and a goal will be set for each of the 
97         facts that are passed. 
98         @param toGet[]   an array of facts that are to be the goals of the agent
99         fail)
100        @returns nothing
101         */
102     public void achieve (Fact toGet[]) {
103         for (int count = 0; count < toGet.length; count++) { 
104             Goal goal = new Goal(Goal.DISCRETE,
105                 agentContext.getGenSym().newId("goal"),
106                 toGet[count], 
107                 agentContext.whoami()); 
108             agentContext.getEngine().achieve(goal);
109                            } 
110     }
111         /*** 
112         setHandler method allows you to specify a method in an object that will 
113         be called when a message of type messageType and from the agent agentFrom 
114         is received by this agent.<p> 
115         The method methodName will be called, it must have a single parameter of 
116         type zeus.concepts.Performative - when this method is called by the 
117         handling code this parameter will contain the message that has been 
118         received. <p>
119         @param messageType      the type of message (performative type) that is being watched for
120          Examples of a performative type are <i> inform</i>, 
121         <i>confirm </i>,<i> cfp </i>,<i> request </i> 
122         @param agentFrom    the putative source of the messages in the form 
123         <p>http://www.adastralCity.com/test <p> 
124         This would mean that all messages from the agent called test on the 
125         platform www.adastralCity.com that are passed via http will be 
126         picked up and forwarded to the handleing method. 
127         @param target   the object instance that is providing the handler 
128         method for this
129         @param methodName   the name of the method that is to be called 
130         @returns nothing
131         <p>
132         If the parameters messageType and agentFrom are both null then the effect of 
133        using these methods will be to make all the message that this agent receives
134        be forwarded to target.methodName(Performative);
135         
136         */
137     public void setHandler (String messageType, String agentFrom, 
138                                     Object target, String methodName) { 
139        MsgHandler msgh = agentContext.getMsgHandler();
140        String [] msgPattern = { "type", messageType.toLowerCase(), "sender", "//A"+agentFrom+"//Z"};
141        MessageRule messrule = new MessageRuleImpl(agentContext.newId("Rule"),msgPattern,target,methodName);
142        String [] msgPattern2 = { "type", messageType.toUpperCase(), "sender", "//A"+agentFrom+"//Z"}; 
143        messrule = new MessageRuleImpl(agentContext.newId("Rule"),msgPattern2,target,methodName);
144        msgh.addRule(messrule);
145     }
146     
147 
148         /*** 
149         setHandler method allows you to specify a method in an object that will 
150         be called when a message of type messageType <p> 
151         The method methodName will be called, it must have a single parameter of 
152         type zeus.concepts.Performative - when this method is called by the 
153         handling code this parameter will contain the message that has been 
154         received. <p>
155         @param messageType      the type of message (performative type) that is being watched for
156         Examples of a performative type are <i> inform</i>, 
157         <i>confirm </i>,<i> cfp </i>,<i> request </i> 
158         @param agentFrom    the putative source of the messages in the form 
159         <p>http://www.adastralCity.com/test <p> 
160         This would mean that all messages from the agent called test on the 
161         platform www.adastralCity.com that are passed via http will be 
162         picked up and forwarded to the handleing method.
163         @param target   the object instance that is providing the handler 
164         method for this
165         @param methodName   the name of the method that is to be called 
166         @returns nothing
167         <p>
168         If the parameters messageType and agentFrom are both null then the effect of 
169        using these methods will be to make all the message that this agent receives
170        be forwarded to target.methodName(Performative);
171         
172         */
173     public void setHandler (String messageType, Object target, String methodName) { 
174        MsgHandler msgh = agentContext.getMsgHandler();
175        String [] msgPattern = { "type", messageType.toLowerCase()};
176        MessageRule messrule = new MessageRuleImpl(agentContext.newId("Rule"),msgPattern,target,methodName);
177        msgh.addRule (messrule); 
178        String [] msgPattern2 = { "type", messageType.toUpperCase()};
179        messrule = new MessageRuleImpl(agentContext.newId("Rule"),msgPattern2,target,methodName);
180        msgh.addRule(messrule);
181     }
182     
183 
184     
185     /*** 
186         setMessageQueue method is used to specify to zeus that it should queue messages 
187         in this method so that they can be picked up one at a time in 
188         a simple to understand way.<p>  
189         This is a very primative way of handling messages and should only 
190         be invoked for simple applications. Once the messageQueue has been tyrned on it cannot 
191         be turned off, however, a repeat invokation of this method will cause the queue 
192         to be reset, and all the messages currently stored on it will be discarded.
193         @returns nothing
194         */
195     public void setMessageQueue () { 
196         messQ = true;
197         messageQueue = new Queue(); 
198         // set message handler to call the queueing method
199         this.setHandler (null,null,this,"addQueue");
200     }
201     
202     
203     /*** 
204         Simple method that is called to find out if the message enqueue 
205         mechanism has been turned on or off. 
206         @returns has setMessageQueue been called or not?
207         */
208     public boolean isQueueOn () { 
209         return messQ; 
210     }
211     
212     
213     /***     
214         if the messageQueue has been turned on this method will 
215         return the next message on the queue. <P>
216         If the messageQueue is not on then this call will return null. <p>
217         If the messageQueue is empty this method will return null <p> 
218         @returns the next message from the queue or null
219         */
220     public Performative getNextMessage() { 
221      if (!messQ) return null; 
222      // trying to be defensive
223      synchronized (messageQueue) { 
224         if (messageQueue.isEmpty()) return null;
225         Object retObj = messageQueue.dequeue(); // defensive
226         if (retObj == null)
227             return null; 
228         else 
229         try {
230             return (Performative) retObj;}
231             catch (ClassCastException cce) {
232                 System.out.println("Bad message in SimpleAPI.getNextMessage()"); 
233                 return null;}
234         }
235     }
236     
237     
238     /***
239         waitNextMessage bocks until a message is received by the agent, it will 
240         then return that message. However, this will only work if the setMessageQueue
241         method has been called first, because if it hasn't this will block until you 
242         call the addQueue(Performative) method.
243         @returns the next message off the message queue (blocks if nothing is there)
244         */      
245     public Performative waitNextMessage() { 
246      if (!messQ) return null; 
247      // trying to be defensive
248      synchronized (messageQueue) { 
249         Object retObj = messageQueue.dequeue(); 
250         if (retObj == null)
251             return null; 
252         else 
253         try {
254             return (Performative) retObj;}
255             catch (ClassCastException cce) {
256                 System.out.println("Bad message in SimpleAPI.getNextMessage()"); 
257                 return null;}
258      }                  
259     }
260 
261 
262     /*** 
263     	* addQueue is used to add a message to the internal queue maintained by this
264         * agent. It is primarily intended for internal use, but if the message 
265         * queue is turned on you could use this to send a message to yourself!
266         *@param perf     the performative to add to the queue
267         *@returns nothing
268         */
269     public void addQueue(Performative perf) { 
270         messageQueue.enqueue(perf);
271     }
272     
273 
274         /***
275           * addFact can be used to add a fact into the Zeus resourceDb (the agents beliefs)
276           * This will trigger any rules that match the fact, and will allow agents to acheive
277           * goals that can be met by exectuing tasks with preconditions that match the fact.
278           *@since 1.3
279           *@author Simon Thompson
280           *@param toAdd the fact that you want to be added
281           *@returns nothing
282           */
283     public void addFact (Fact toAdd) {
284        ResourceDb rdb =  agentContext.getResourceDb();
285        rdb.add(toAdd);
286        }
287     
288 
289     /*** 
290       * this init() method is used to set up a SimpleAPI for you to 
291       *  use<p> 
292       *  The suggested method of use is from your AgentExternal : <p> 
293       *  <CODE> public class myExternal implements ZeusExternal {
294       *      public void exec(AgentContext ac) { 
295       *          SimpleAPI api = new SimpleAPI (ac); 
296       *      </CODE> <br>
297       *  You can now use the methods in this class via the api instance. 
298       *@param agentContext     used by this class to access the internals
299       *  of the zeus agent the agentContext object is the directory of 
300       *  agent components that is passed to a Zeus AgentExternal when 
301       *  it is instantiated. Sophisticated agent programmers will 
302       *  want to utilize the agentContext object directly rather than via this 
303       *  simple wrapper, which is designed for novice users.
304       *@returns identity of this class
305       *@see zeus.actors.AgentContext
306       *@see zeus.actors.ZeusAgentContext
307         */ 
308     public SimpleAPI (AgentContext agentContext) { 
309         this.agentContext = agentContext;    
310     }    
311 }