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.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;
48 public static final int DEFAULT_PORT_MIN = 6700;
49 public static final int DEFAULT_PORT_MAX = 7800;
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
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
83 public NIOServer() { ; }
84
85
86 public NIOServer(AgentContext context, MailBox mbox, Queue inMail) {
87 Assert.notNull(context);
88 this.context = context;
89
90 try {
91 InetAddress ip = InetAddress.getLocalHost();
92 String localhost = ip.getHostAddress();
93 Core.DEBUG(4,"Ip Address is: " + ip);
94
95
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
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
112 }
113
114
115 } catch (Exception e) {
116 e.printStackTrace();
117 }
118
119
120 this.mbox = mbox;
121
122
123
124
125
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
154 public void normalStatus() {
155 this.setPriority(Thread.NORM_PRIORITY);
156 timeout = 1000;
157 }
158
159
160
161
162
163
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
259 debug("2");
260 if ( (addr = msg.getAddress()) != null )
261 context.AddressBook().add(addr);
262
263 debug("3");
264 if (msgHandler==null)
265 msgHandler = context.getMsgHandler();
266
267
268
269 Core.DEBUG(3,"putting message from " + msg.getSender() + " on handler queue");
270
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