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  package zeus.actors.intrays;
23  
24  import zeus.actors.outtrays.*;
25  import java.net.*;
26  import java.io.*;
27  import java.util.*;
28  import zeus.util.*;
29  import zeus.concepts.*;
30  import zeus.actors.*;
31  import zeus.agents.*;
32  import javax.naming.*;
33  import java.net.*;
34  import java.io.*;
35  import java.util.*;
36  import zeus.util.*;
37  import zeus.concepts.*;
38  
39  import javax.rmi.*;
40  import java.rmi.*;
41  
42  
43  /***
44   * Zeus_ACC_Server uses the FIPA_97_Server and FIPA_2000_Server classes to provide
45   * a unified message reception and handleing service.On init this class will create
46   * a FIPA_97_Server and a FIPA_2000_Server, using itself as a parameter.
47   * When either of these intrays receives a message it will call back the appropiate
48   * handle method in this class. The message will then be processed and placed on the
49   * message handleing q in this instance. Finally this message will be handled and processed.
50   * <p>
51   * @author Simon Thompson
52   * @since 1.1
53   */
54  public class Zeus_ACC_Server extends Server implements InTray, FIPA_97_Handler, FIPA_2000_Handler {  // the ACC agent should include code to set this.
55      
56      public  String hostname = zeus.util.SystemProps.getProperty("HAP_Address");
57      
58      /***
59      iiop2000port is used to store the number of the port that the FIPA_2000 IIOP
60      listening service (the server) will use.
61      This is package protected so that subclasses can do as they will!
62      value is set to "2000" by default
63       */
64      protected String iiop2000Port = "2000";
65      
66      
67      /***
68       * iiop97port is used to store the number of the port that the FIPA_97 IIOP
69       * listening service (the server) will use.
70       * This is package protected so that subclasses can do as they will!
71       * value is set to "1097" by default.
72       */
73      protected String iiop97Port = "1097";
74      
75      
76      /***
77      httpPort is the number of the port that the FIPA_2000 HTTP service
78      will listenon.
79      This is package protected so that you can fiddle with it in subclasses.
80      value is set to "61000" by default
81       */
82      protected String httpPort = "61000";
83      
84      
85      /***
86      access to the context object is provided as protected as a convienience for
87      API programmers and future extentions, it is passed to the init() of this class
88       */
89      protected AgentContext context = null;
90      
91      private Queue  msgQ = new Queue("Zeus_ACC_In");
92      private ZeusParser parser = new ZeusParser();
93      
94      
95      /***
96      name is set to "ACC" by default
97       */
98      protected String name = "ACC";
99      
100     /***
101     twoThousand_Server is the reference to the FIPA_2000_IIOP_Server that
102     this class sets up and runs in it's init().
103      */
104     protected FIPA_2000_IIOP_Server twoThousand_Server = null ;
105     
106     
107     /***
108     ninetySeven_Server is the reference to the FIPA_97_Server that
109     this class sets up and runs in it's init()
110      */
111     protected FIPA_97_Server ninetySeven_Server = null;
112     
113     
114     /***
115     httpServer is the reference to the FIPA_2000_HTTP_Server that
116     this class sets up and runs in it's init()
117      */
118     protected FIPA_2000_HTTP_Server httpServer = null;
119     
120     
121     /***
122      host is protected to allow for interference by putative sub-classes
123      */
124     protected String host = null;
125     
126     
127     /***
128     class constructor that takes the AgentContext and registers this instance with it,
129     and the MailBox and grabs the reference so that it can be used later. This also sets
130     up the ServerThreads for the message transports that this Server is utilizing.
131      */
132     public Zeus_ACC_Server(AgentContext context, Zeus_ACC_MailBox mbox) {
133         this.mbox = (MailBox) mbox;
134         timeout = 10;
135         Assert.notNull(context);
136         this.context = context;
137         TransportConfig twoIIOPConf = SystemProps.getTransport("FIPA_IIOP_2000");
138         if (twoIIOPConf!=null) {
139             debug("setting iiop 2000 port to : " + twoIIOPConf.getPort());
140             iiop2000Port = twoIIOPConf.getPort(); }
141         TransportConfig twoHTTPConf = SystemProps.getTransport("FIPA_HTTP_2000");
142         if (twoHTTPConf != null) {
143             debug("setting http 2000 port to : " + twoHTTPConf.getPort());
144             httpPort = twoHTTPConf.getPort(); }
145         TransportConfig nineIIOPConf = SystemProps.getTransport("FIPA_IIOP_1997");
146         if (nineIIOPConf != null) {
147             debug("setting iiop 1997 port to : " + nineIIOPConf.getPort());
148             iiop97Port = nineIIOPConf.getPort(); }
149         
150         try {
151             
152             
153             InetAddress ip = InetAddress.getLocalHost();
154             host = ip.getHostAddress();
155             if (hostname == null ) {
156                 hostname = host; }
157             twoThousand_Server = new FIPA_2000_IIOP_Server(this,host, iiop2000Port,name,"2000Connection");
158             ninetySeven_Server = new FIPA_97_Server(this,host, iiop97Port,name,"97Connection");
159             httpServer = new FIPA_2000_HTTP_Server(this,host,httpPort,name, "HTTPConnection");
160             // note to self - do http server here
161             this.start();
162             this.setName("Zeus_ACC_Server");}
163         catch (Exception e ) {
164             // will only be called if local host is not set
165             // very unlikely...
166             e.printStackTrace();
167             System.out.println("ERROR - probably localhost cannot be looked up!\n WARNING: attempting to continue, but likely fatal");
168         }
169     }
170     
171     
172     
173     /***
174     stopProcessing will cause the run loop of this class to stop
175      */
176     public void stopProcessing() {
177         processing = false;
178     }
179     
180     
181     /***
182     This is where the changes were needed. Instead of listening on a stupid socket ;-)
183     we simply look in our message queue to see if any goodies have been put there by nice
184     mr FIPA_97_Connection.
185      */
186     public void run() {
187         processing = true;
188         while (processing) {
189             try {// robust!?
190                 Object obj = this.pop();
191                 debug ("popped message off queue"); 
192                 if (obj instanceof String) {
193                     String text =(String) obj;
194                     debug("message popped is: " + text);
195                     //       try {
196                     text = Misc.unescape(text);// swapped from underneath
197                     //    text = text.replace('\n',' ');
198                     //   text = text.replace('\r',' ');
199                     //   text = text.replace('\t',' ');
200                     
201                     forwardFIPAMessage(text);
202                     
203                 }
204       
205                 yield();}
206             catch (Exception e ) {
207                 e.printStackTrace();
208                 System.out.println("exception in ACC server - attempting to recover");
209             }
210             catch (Error er) {  
211                 er.printStackTrace(); 
212                 System.out.println("error - attempting to recover"); 
213             }
214             catch (Throwable tr) { 
215                 tr.printStackTrace();
216                 System.out.println("throwable - attempting to recover"); 
217             }
218         }
219     }
220     
221     
222     /***
223      * for now the behaviour is :-
224      * get message, <br>
225      * act surprised, <br>
226      * then parse it into a FIPAPerformative, <br>
227      * map that to a Performative, <br>
228      * register self as alias in nameserver,<br>
229      * add alias to FIPAAddressBook, <br>
230      * stamp message with said alias,<br>
231      * assert a messageHandleing rule to invoke forwarding behaviour when
232      * a response is received
233      * send message to Zeus agent, <br
234      * pray.<p>
235      */
236     public void forwardFIPAMessage(String text) {
237         try {
238             debug ("forwarding"); 
239             FIPA_AddressBook addresses = ((FIPA_AddressBook)context.getAddressBook());
240             FIPAPerformative fmsg = parser.fipaPerformative(text);
241             FIPA_AID_Address fAddress = fmsg.getSender_As_FIPA_AID();
242             fAddress = addresses.checkAddress(fAddress);
243             if (fAddress.getAlias() == null) {
244                 registerAlias(fAddress); }
245             Performative msg = fmsg.performative();
246             String alias = fAddress.getAlias();
247             msg.setSender(alias);
248             debug ("setting send address to " + alias); 
249             msg.setReplyTo(alias);
250             addresses.add(fAddress);
251             setHandleMessage(fAddress, alias);
252      
253             debug("Zeus content = " + msg.getContent());
254             mbox.sendMsg(msg); }
255         catch (Exception e) {
256             try {
257                 java.io.File file = new java.io.File("debug.out");
258                 java.io.FileOutputStream fileout = new java.io.FileOutputStream(file);
259                 java.io.PrintWriter fw= new java.io.PrintWriter(fileout);
260                 e.printStackTrace(fw);
261                 fw.flush();
262                 fw.close();} catch (Exception ne) { ne.printStackTrace(); }
263             
264         }
265         
266     }
267     
268     
269     /***
270      * set up a forwarding rule, if one is not already present.
271      */
272     private void setHandleMessage(FIPA_AID_Address faddress, String alias) {
273         if (!faddress.getForwardingRuleSet()) {
274             MsgHandler handler = context.getMsgHandler();
275             String msg_pattern[] = {"receiver",alias};
276             handler.addRule(new MessageRuleImpl(context.newId("Rule"),msg_pattern, this, "forward"));
277             faddress.setForwardingRuleSet(true);
278         }
279     }
280     
281     
282     
283     /***
284      * provides a basic mechanism for getting aliases for agents on other platforms
285      * into the Zeus address space. If this method is called from the ACC agent
286      * stub it can be used to setup zeus names and fipa forwarding in the ANServer and
287      * in the ACC
288      */
289     public void setFIPAAlias(String name, String address) {
290         FIPA_AddressBook addresses = ((FIPA_AddressBook)context.getAddressBook());
291         FIPAPerformative fmsg = parser.fipaPerformative(address);
292         FIPA_AID_Address fAddress = fmsg.getSender_As_FIPA_AID();
293         fAddress = addresses.checkAddress(fAddress);
294         if (fAddress.getAlias() == null){
295             fAddress.setAlias(name);
296             registerAlias(fAddress,name);
297             setHandleMessage(fAddress,name);
298             addresses.add(fAddress);
299         }
300         
301         
302     }
303     
304     
305     /***
306      * provides a basic mechanism for getting aliases for agents on other platforms
307      * into the Zeus address space. If this method is called from the ACC agent
308      * stub it can be used to setup zeus names and fipa forwarding in the ANServer and
309      * in the ACC
310      */
311     public  void setFIPAAlias(String name, FIPA_AID_Address fAddress) {
312         FIPA_AddressBook addresses = ((FIPA_AddressBook)context.getAddressBook());
313         fAddress = addresses.checkAddress(fAddress);
314         if (fAddress.getAlias() == null) {
315         fAddress.setAlias(name);   
316             registerAlias(fAddress,name);
317             setHandleMessage(fAddress,name);
318             addresses.add(fAddress);
319         }
320     }
321     
322     
323     /***
324      * forward is the method called when the MsgHandler fires a MessageRule that is setup
325      * by the setHandleMessage method.
326      * It converts the Zeus Performative into a FIPA performative, does any address mapping
327      * that is needed and sends the message to the FIPA_postman.
328      */
329     public void forward(Performative perf) {
330         if (perf.getSender().startsWith("Nameserver")) return;
331         if (perf.getSender().startsWith("Facilitator")) return; // god knows
332         try {
333             FIPAPerformative fPerf = new FIPAPerformative(perf);
334             FIPA_AddressBook addresses = ((FIPA_AddressBook)context.getAddressBook());
335             String raddr =  perf.getReceiver();
336             FIPA_AID_Address faddr = addresses.lookupAlias(raddr);
337             Vector recs = new Vector();
338             recs.addElement(faddr);
339             fPerf.setReceivers(recs);
340             String senderName = perf.getSender();
341             //  Envelope perf.getEnvelope();
342             InetAddress ip = InetAddress.getLocalHost();
343             String localhost = hostname;
344             FIPA_AID_Address sender = new FIPA_AID_Address("(agent-identifier\n:name " + senderName + "@" + localhost + "\n:addresses (sequence " + getResponseAddress()+"))");
345             //  sender.setName(perf.getSender());
346             fPerf.setSender(sender);
347          
348             FIPA_PostMan postey =((Zeus_ACC_MailBox) mbox).getFIPA_PostMan();
349             postey.push(fPerf);
350             // set sender?}
351         }
352         catch (Exception e) {
353             e.printStackTrace();
354         }
355         
356     }
357     
358     
359     
360     /***
361      * send a registration to the nameservers that we are using. <br>
362      * @param sender is the name of the alias to use
363      */
364     protected void registerAlias(FIPA_AID_Address sender) {
365         System.out.println("In register 1");
366         String name = sender.getName()+sender.getHost();
367         AddressBook addressBook = context.getAddressBook();
368         for(int i = 0; i < context.nameservers().size(); i++ ) {
369             String key = sender.setAlias(name);
370             Address addr = (Address)context.nameservers().elementAt(i);
371             addressBook.add(addr);
372             Performative msg = new Performative("request");
373             msg.setReceiver(addr.getName());
374             msg.setReplyWith(key);
375             msg.setContent("register");
376             msg.setSender(key);
377             System.out.println("send message to nameserver");
378             mbox.sendMsg(msg);
379             System.out.println("done message");
380         }
381     }
382     
383     
384     /***
385         send a registration to the nameservers that we are using. <br>
386         @param sender is the name of the alias to use
387      */
388     protected void registerAlias(FIPA_AID_Address address, String name) {
389         AddressBook addressBook = context.getAddressBook();
390         for(int i = 0; i < context.nameservers().size(); i++ ) {
391             String key = address.setAlias(name);
392             Address addr = (Address)context.nameservers().elementAt(i);
393             addressBook.add(addr);
394             Performative msg = new Performative("request");
395             msg.setReceiver(addr.getName());
396             msg.setReplyWith(key);
397             msg.setContent("register");
398             msg.setSender(key);
399             mbox.sendMsg(msg);
400         }
401     }
402     
403     
404     /***
405         send a registration to the nameservers that we are using. <br>
406         @param sender is the name of the alias to use
407      */
408     protected void registerAlias(String name) {
409         AddressBook addressBook = context.getAddressBook();
410         for(int i = 0; i < context.nameservers().size(); i++ ) {
411             String key = name;
412             Address addr = (Address)context.nameservers().elementAt(i);
413             addressBook.add(addr);
414             Performative msg = new Performative("request");
415             msg.setReceiver(addr.getName());
416             msg.setReplyWith(key);
417             msg.setContent("register");
418             msg.setSender(key);
419             mbox.sendMsg(msg);
420         }
421     }
422     
423     
424     /***
425      * registerAgent is functionally identical to registerAlias, but
426      * is semantically slightly different because in the one we are using
427      * the agent name directly, while in the other we are trying to decouple
428      */
429     public void registerAgent(FIPA_AID_Address address, String name) {
430         this.registerAlias(address,name);
431     }
432     
433     
434     protected void finalize() {
435         try {
436             if ( listenSocket != null ) listenSocket.close();
437             timeout = -1;
438         }
439         catch(IOException e) {
440         }
441     }
442     
443     
444     public Address getAddress() {
445         return address;
446     }
447     
448     
449     /***
450     pull something off the ACC message processing queue
451      */
452     public String pop() {
453         return (String) msgQ.dequeue();
454     }
455     
456     
457     /***
458      * put something onto the ACC message processing queue
459      */
460     public void push(String target) {
461         debug ("enqueueing message "); 
462         msgQ.enqueue(target);
463         
464     }
465     
466     
467     /***
468      * handle(String message) is called by the FIPA_97_Server which the init method of the Zeus_ACC_Server
469      * class creates it is used as an interface to unify and collate the information
470      * reception and processing for the ACC agent. <p>
471      * implements the FIPA_97_Handler interface <p>
472      * @param message - the message picked up from the fipa_97 transport
473      */
474     public void handle(String message) {
475         // simply push this onto the message handling q.
476         push(message);
477     }
478     
479     
480     
481     
482     /***
483      * handle (FIPA.FipaMessage aMessage) is called by the FIPA_2000_server that the
484      * init method of this class creates.
485      * implements that FIPA_2000_Handler interface<p>
486      * ISSUES <br>
487      * ------ <br>
488      * Envelopes - what should we do???
489      *
490      * @param aMessage - the message in FIPA 2000 object (java/idl) format
491      * @see FIPA.FipaMessage
492      */
493     public synchronized void handle(FIPA.FipaMessage aMessage) {
494         byte body [] = aMessage.messageBody;
495         String messageStr = new String(body);
496         
497         push(messageStr);
498     }
499     
500     /***
501     return a string of addresses that this server is listening on
502      */
503     public String getResponseAddress() {
504         String httpAddress = httpServer.getResponseAddress();//"http://" + host + ":" + http2000Port  + name
505         String iiop2000Address = twoThousand_Server.getResponseAddress(); //"corbaname::" + host + ":" +iiop2000Port + "/NameService/" name
506         String iiop97Address = ninetySeven_Server.getResponseAddress();//"iiop" + host + ":" + iiop97Port + name
507         String ior2000Address = twoThousand_Server.getIORAddress();
508         // removed corba addresses 
509         String addressStr = new String(iiop2000Address +" " + httpAddress );
510         
511         return (addressStr);
512         
513     }
514     
515     
516     public void debug(String str) {
517           System.out.println ("Zeus ACC server>> " + str);
518     }
519     
520     
521 }