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-9. All Rights Reserved.
18   *
19   * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20   */
21  
22  
23  
24  /*
25   * @(#)PostMan.java 1.00
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          // ( ccMail == null )
84          //this.setPriority(Thread.NORM_PRIORITY-2);
85          this.setName("Normal postman"+id);
86          id ++;
87          //this.lowerStatus();
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             // never, ever stop dispatching.
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()) { //1
138                 receiver = (String) allRec.nextElement();
139                 if (( addr = mbox.lookup(receiver)) != null) { //2
140                     if ( postMsg(msg,addr) ) {
141                         if ( ccMail != null )
142                             mbox.informVisualisers(msg);
143                     }
144                     else {//2
145                         // The receiver cannot be contacted at the given
146                         // address - we assume the address is wrong, and
147                         // delete it from the address book.
148                         mbox.postErrorMsg(msg,"Cannot contact reciever");
149                         mbox.del(addr);
150                     }
151                 }
152                 else {//3
153                     String key = mbox.addressSought(receiver);
154                     if ( key == null ){
155                         mbox.postErrorMsg(msg,"Cannot find address of receiver");
156                     }
157                     else {//4
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                     }// end else 4
165                 }// end else 3
166             }//end if 2
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; // GC
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         // if statements added by simon
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         // set the address in the envelope
221         Address mailAddress = new ZeusAddress(myAddress);
222         //changes for forwarding...
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       //  while( !isOk && nTry++ < MAX_RETRY ) {
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 );  // Send msg
237                 out.flush();         // flush out-stream
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         //  System.out.println("leaving postman");
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         // System.out.println("mailq = " + outMail.size());
267         //while (outMail.size() > queueLength) {
268         //    doPost();
269         //       }
270         outMail.enqueue(msg);
271     }
272     
273     
274     
275 }