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-2002. All Rights Reserved.
18   *
19   * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20   */
21  
22  /*
23   * NIOServer.java
24   *
25   * Created on 09 April 2002, 14:29
26   */
27  
28  package zeus.actors.intrays;
29  
30  
31  import java.nio.channels.*;
32  import java.net.*;
33  import java.io.*;
34  import java.util.*;
35  import zeus.util.*;
36  import zeus.concepts.*;
37  import zeus.actors.*;
38  
39  
40  /***
41   *this is a souped up version of the native socket transport to take advantage
42   *of the nio libraries.
43   */
44  
45  public class NIOServer extends Thread implements InTray {
46      public static final int MAX_CONNECTIONS = 1;
47      public static final int MAX_QUEUE_LENGTH = 100; // 50
48      public static final int DEFAULT_PORT_MIN = 6700;//6700
49      public static final int DEFAULT_PORT_MAX = 7800;//6800
50      public int maxMessageSize = 100000;
51      protected ServerSocket listenSocket;
52      protected Address      address;
53      protected int          connection_count = 0;
54      protected boolean      processing;
55      private AgentContext context = null;
56      private java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(maxMessageSize);
57      /***
58       * timeout was originally private, but subclasses need to
59       * use it to construct there own treads of control, so I changed it to protected
60       * (ST -14/8/00)
61       */
62      protected   long         timeout = -1;
63      
64      /*** Data structure holding messages as they are read in */
65      protected Queue        inMail;
66      
67      /*** Reference to MailBox of which this is a sub-component */
68      protected MailBox      mbox;
69      
70      protected MsgHandler msgHandler = null;
71      
72      
73      // java.nio extentions
74      java.nio.channels.Selector selector;
75      ServerSocketChannel server ;
76      SelectionKey key;
77      SelectionKey serverKey;
78      private LinkedList clients;
79      private java.nio.channels.Selector readSelector;
80      ServerSocket socket;
81      
82      // added so that the class can be extended without starting the threads.
83      public NIOServer() { ; }
84      
85      
86      public NIOServer(AgentContext context, MailBox mbox, Queue inMail) {
87          Assert.notNull(context);
88          this.context = context;
89          // Get localhost details
90          try {
91          InetAddress ip = InetAddress.getLocalHost();
92          String localhost = ip.getHostAddress();
93          Core.DEBUG(4,"Ip Address is: " + ip);
94    
95          // Select port for listening
96          boolean port_found = false;
97          for(int port = DEFAULT_PORT_MIN; !port_found && port < DEFAULT_PORT_MAX; port++ ) {
98              clients = new LinkedList();
99              readSelector = java.nio.channels.Selector.open();
100             server = ServerSocketChannel.open(); 
101             socket = server.socket(); 
102             socket.bind(new InetSocketAddress(port), 100); 
103             server.configureBlocking(false); 
104             //  listenSocket = new ServerSocket(port,MAX_QUEUE_LENGTH);
105             port_found = true;
106             address = new ZeusAddress(context.whoami(),localhost,port,context.whatami());
107             context.AddressBook().add(address);
108              }
109             if ( !port_found ) {
110                 System.err.println("Cannot get a port for listening");
111                 //  System.exit(0);
112             }
113         
114         
115         } catch (Exception e) { 
116             e.printStackTrace(); 
117         }
118         // Store variables
119         //  this.inMail = inMail;
120         this.mbox = mbox;
121         
122         // LL 030500 1.03b
123         // lowerStatus();
124         
125         // Start the server listening for connections
126         this.setName("Normal server");
127         this.start();
128     }
129     
130     public AgentContext getAgentContext() {
131         return mbox.getAgentContext();
132     }
133     
134     
135     public synchronized void updateCount(int x) {
136         debug("update count");
137         connection_count += x;
138         if ( x < 0 ) {
139             debug("notifying");
140             notify();
141         }
142     }
143     
144     public void stopProcessing() {
145         processing = false;
146     }
147     
148     public void lowerStatus() {
149         this.setPriority(Thread.NORM_PRIORITY-2);
150         timeout = 1000;
151     }
152     
153     // LL 030500 1.03bB
154     public void normalStatus() {
155         this.setPriority(Thread.NORM_PRIORITY);
156         timeout = 1000;//1000?
157     }
158     // LL 030500 1.03bE
159     
160     // The body of the server thread.  Loop forever, listening for and
161     // accepting connections from clients.  For each connection,
162     // create a Connection object to handle communication through the
163     // new Socket.
164     
165     public void run() {
166         processing = true;
167         SocketChannel client;
168         while(processing) {
169             debug("alive");
170             try {
171                 while (true) {
172                     client = server.accept();
173                     if (client!=null)
174                         registerClient(client);
175                     serviceClients();
176                 }
177             }
178             catch (Exception e) {
179                 e.printStackTrace();
180                 Core.DEBUG(3,"Exception listening for connections: " + e);
181             }
182             finally {
183                   try {
184                 server.socket().close();}
185                 catch (Exception e) {
186                     ;
187                 }
188             }
189             
190         }
191     }
192     
193     public void serviceClients()
194     throws IOException {
195         Set keys;
196         Iterator it;
197         SelectionKey key;
198         SocketChannel client;
199         try {
200         if(readSelector.select(1) > 0) {
201             keys = readSelector.selectedKeys();
202             it = keys.iterator();
203             while(it.hasNext()) {
204                 key = (SelectionKey)it.next();
205                 if(key.isReadable()) {
206                     int bytes;
207                     client = (SocketChannel)key.channel();
208                     buffer.clear();
209                     bytes = client.read(buffer);
210                     if(bytes >= 0) {
211                         PerformativeParser parser = new PerformativeParser(new ByteArrayInputStream(buffer.array()));
212                         Performative msg = parser.Message();
213                         this.newMsg(msg);
214                     } else if(bytes < 0) {
215                         clients.remove(client);
216                         client.close();
217                     }
218                 }
219             }
220         }}catch (Exception e) {
221             e.printStackTrace();
222         }
223     }
224     
225     
226     public void registerClient(SocketChannel client) throws IOException {
227         client.configureBlocking(false);
228         client.register(readSelector, SelectionKey.OP_READ);
229         clients.add(client);
230     }
231     
232     
233     
234     
235     protected void finalize() {
236         try {
237             if ( listenSocket != null ) listenSocket.close();
238         }
239         catch(IOException e) {
240         }
241     }
242     
243     public Address getAddress() {
244         return address;
245     }
246     
247     /***
248      * ensures that messages are processed
249      * // synchronized
250      */
251     public void newMsg( Performative msg ) {
252         Address addr;
253         Time time;
254         AgentContext context = this.getAgentContext();
255         debug("1");
256         if ( (time = context.currentTime()) != null )
257             msg.setReceiveTime(time);
258         // add this agent to the addressbook
259         debug("2");
260         if ( (addr = msg.getAddress()) != null )
261             context.AddressBook().add(addr);
262         // if (inMail == null){
263         debug("3");
264         if (msgHandler==null)
265             msgHandler = context.getMsgHandler();
266         //	     inMail = msgHandler.getMessageQueue();
267         //}
268         
269         Core.DEBUG(3,"putting message from " + msg.getSender() + " on handler queue");
270         //inMail.enqueue(msg);
271         debug("4");
272         msgHandler.processMessage(msg);
273         debug("5");
274         mbox.notifyMonitors(msg,MailBox.RECEIVE);
275         debug("6");
276     }
277     
278     
279     /***
280      * implement in haste, repent at leisure
281      */
282     public String getResponseAddress() {
283         return (address.toString());
284     }
285     
286     
287     public void debug(String str) {
288         System.out.println("Server>> " + str);
289     }
290     
291 }
292