1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
223 synchronized (messageQueue) {
224 if (messageQueue.isEmpty()) return null;
225 Object retObj = messageQueue.dequeue();
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
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 }