1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package zeus.actors;
29
30 import java.net.*;
31 import java.io.*;
32 import java.util.*;
33 import zeus.util.*;
34 import zeus.concepts.*;
35
36 /***
37 * This component is part of the {@link MailBox}, and is responsible for
38 * dispatching messages on demand to their recipients. This component
39 * operates within its own thread enabling the MailBox to send and receive
40 * multiple messages simultaneously. <p>
41 *
42 * It is unlikely that developers will need to call these methods directly.
43 * Although if the user wants to replace the default TCP/IP messaging mechanism
44 * this could be cleanly achieved by reimplementing the methods of this class.
45 */
46
47 public class PostMan extends Thread {
48 protected final int MAX_RETRY = 10;
49
50 /*** Data structure holding messages pending dispatch */
51 protected Queue outMail = null;
52
53 /*** Data structure holding CC'ed messages pending dispatch to Visualisers */
54 protected Queue ccMail = null;
55
56 /*** Reference to MailBox of which this is a sub-component */
57 protected MailBox mbox = null;
58
59 protected Address myAddress = null;
60 protected boolean dispatching;
61 protected Hashtable waitQueue = new Hashtable();
62 private static int id = 0;
63 private boolean fastAgent = false;
64 int queueLength = 5;
65 int sleepTime = 100;
66
67 public PostMan() {
68 ;
69 }
70
71 public PostMan(MailBox mbox, Queue outMail, Address myAddress) {
72 this(mbox,outMail,null,myAddress);
73
74 }
75
76 public PostMan(MailBox mbox, Queue outMail, Queue ccMail, Address myAddress) {
77
78 this.mbox = mbox;
79 this.outMail = outMail;
80 this.ccMail = ccMail;
81 this.myAddress = myAddress;
82
83
84
85 this.setName("Normal postman"+id);
86 id ++;
87
88 this.start();
89 }
90
91 public void stopDispatching() {
92 dispatching = false;
93 }
94
95 public void lowerStatus() {
96 this.setPriority(Thread.NORM_PRIORITY-2);
97 }
98
99
100
101 /***
102 * this run method is the business end of the agent's communication infrastructure.
103 * It works in the following way. <p>
104 * for every receiver of the message<br>
105 * <t> if lookupAddress good then <br>
106 * <t><t> if can send to that address
107 * <t><t><t> tell the visualisers about the message
108 * <t><t> else
109 * <t><t><t> post an error and delete that address
110 * <t>else
111 * <t><t> ask the nameserver for the address and put this message on a todo list until the nameserver responds
112 * then service it.
113 */
114 public void run() {
115 dispatching = true;
116 while( dispatching ) {
117 try {
118 doPost();
119 }
120 catch (Throwable tr) {
121 tr.printStackTrace();
122 }
123
124 }
125 }
126
127
128 public void doPost() {
129 Performative msg, query;
130 String receiver;
131 Address addr;
132 msg = (Performative) outMail.dequeue();
133 Enumeration allRec = msg.getReceivers();
134 if (allRec == null) {
135 mbox.postErrorMsg(msg,"No reveivers specified"); }
136 else {
137 while (allRec.hasMoreElements()) {
138 receiver = (String) allRec.nextElement();
139 if (( addr = mbox.lookup(receiver)) != null) {
140 if ( postMsg(msg,addr) ) {
141 if ( ccMail != null )
142 mbox.informVisualisers(msg);
143 }
144 else {
145
146
147
148 mbox.postErrorMsg(msg,"Cannot contact reciever");
149 mbox.del(addr);
150 }
151 }
152 else {
153 String key = mbox.addressSought(receiver);
154 if ( key == null ){
155 mbox.postErrorMsg(msg,"Cannot find address of receiver");
156 }
157 else {
158 Vector list = (Vector)waitQueue.get(key);
159 if ( list == null ) {
160 list = new Vector(20);
161 waitQueue.put( key,list);
162 }
163 list.addElement(msg);
164 }
165 }
166 }
167
168 }
169 yield();
170 }
171
172
173 public void addressReceived(String key) {
174 synchronized( waitQueue ) {
175 Vector list = (Vector)waitQueue.remove(key);
176 for(int i = 0; list != null && i < list.size(); i++ )
177 outMail.enqueue(list.elementAt(i));
178 list = null;
179 }
180 }
181
182 /***
183 * Some agents need to message quicky, some don't - they need to be sure that
184 * there reasoning components get a go at the processor.
185 * Call this method on your postman to turn it into a messaging deamon.
186 */
187 public void setFastAgent() {
188 fastAgent = true;
189
190 }
191
192
193 /***
194 * postMsg sends the performative out to the other Zeus agent
195 * a socket is opened and the message is written as a string down it.
196 *
197 * <p>
198 * The behaviour of this method has been changed for 1.1/2.0 to allow some
199 * flexibility on the sender field. This is mostly to allow agents to
200 * send messages and stamp them as comming from someone else - in the case of the
201 * ACC agent this allows an alias to be set up in the name server for each exterior
202 * IIOP/HTTP/WAP/UMTS agent or address of agent that is to be contacted. When the
203 * ACC is contacted under this alias it can use it's FIPAAddresBook to lookup an
204 * aid and construct a new message for forwarding<p>
205 * To summerise : if the sender name in the msg parameter is set then the sent message
206 * will have that sender name, and the address that is returned will also have that name.
207 *
208 */
209 public synchronized boolean postMsg( Performative msg, Address addr ) {
210 PrintWriter out = null;
211 boolean isOk = false;
212 int nTry = 0;
213
214 if (msg.getSender()==null) {
215 msg.setSender(myAddress.getName());
216 }
217 else if (msg.getSender().equals("") || msg.getSender().equals("null")) {
218 msg.setSender(myAddress.getName());
219 }
220
221 Address mailAddress = new ZeusAddress(myAddress);
222
223 if (!msg.getSender().equals(mailAddress.getName())){
224 mailAddress.setName(msg.getSender());
225 if (myAddress.getType().equalsIgnoreCase("facilitator")) {
226 mailAddress.setType("FORWARD"); }
227 }
228 msg.setAddress(mailAddress);
229
230 try {
231 Socket socket = new Socket( addr.getHost(), addr.getPort() );
232 out = new PrintWriter( socket.getOutputStream(), true );
233 Time time;
234 if ( (time = mbox.getAgentContext().currentTime()) != null )
235 msg.setSendTime(time);
236 out.println( msg );
237 out.flush();
238 isOk = true;
239 if ( (time = mbox.getAgentContext().currentTime()) != null )
240 msg.setReceiveTime(time);
241 mbox.notifyMonitors(msg,MailBox.DISPATCH);
242
243 }
244 catch (IOException e) {
245 Core.DEBUG(3,"IOException: " + e);
246 e.printStackTrace();
247 yield();
248 }
249 finally {
250 if (out != null) out.close();
251 }
252
253
254 return isOk;
255
256 }
257
258
259 /***
260 * use in preference to postMsg. Whereas the postMsg method invokes the messaging behaviour
261 * of the agent directly this method places the message on a Q to be dealt with as and when.<br>
262 * This is a good thing, as it ensures that the agent is not forced into spending all its
263 * time just sending messages.....
264 */
265 public void push(Performative msg) {
266
267
268
269
270 outMail.enqueue(msg);
271 }
272
273
274
275 }