001
002 /**
003 * Title: Advanced Network Client Sample<p>
004 * Description: <p>
005 * Copyright: Copyright (C) 2009 Alexey Veremenko<p>
006 * Company: <p>
007 * @author Alexey Veremenko
008 * @version 1.0
009 */
010 package networking.server;
011
012 import networking.protocol.*;
013
014 import java.net.*;
015 import java.io.*;
016 import java.util.*;
017
018 class MasterServer extends MasterServerListenersHost
019 implements IMasterServer
020 {
021 /**
022 * MasterServer port
023 */
024 private static final int PORT = IServerFactory.PORT;
025
026 /**
027 * Bind port
028 */
029 private int m_port = PORT;
030
031 /**
032 * Server socket
033 */
034 private ServerSocket m_socket = null;
035
036 /**
037 * Indicate active state
038 */
039 private boolean m_active = false;
040
041 /**
042 * Maximum clients allowed to serve
043 */
044 private int m_limit = 400;
045
046 /**
047 * Maximum talk clients allowed to serve
048 */
049 private int m_talkLimit = 4;
050
051 /**
052 * List of registered servers
053 */
054 private List m_servers = new ArrayList();
055
056 /**
057 * List of clients being servered
058 */
059 private List m_clients = new ArrayList();
060
061 /**
062 * Report error
063 * @param e exception
064 */
065 private void error(Exception e)
066 {
067 log("Master: error " + e.getMessage());
068 e.printStackTrace(System.out);
069 }
070
071 /**
072 * Construct new MasterServer object
073 */
074 protected MasterServer()
075 {
076 this(PORT);
077 }
078
079 /**
080 * Construct new MasterServer object to run on port @port
081 * @param port port
082 */
083 protected MasterServer(int port)
084 {
085 m_port = port;
086 }
087
088 /*
089 * Implement Runnable
090 */
091 public void run()
092 {
093 try
094 {
095 m_active = true;
096 m_socket = new ServerSocket(m_port);
097
098 // Allow m_socket.accept() to block only for 0.5 sec
099 m_socket.setSoTimeout(500);
100
101 fire(STARTED);
102 log("Master: started on port " + m_port);
103
104 // Accept requests in a loop while active
105 while (m_active)
106 {
107 // Check limit
108 if (m_servers.size() < m_limit)
109 {
110 try
111 {
112 new Server(m_socket.accept(), this).start();
113 }
114 catch (InterruptedIOException e)
115 {
116 // Accept time-out expired
117 }
118 catch (Exception e)
119 {
120 error(e);
121 }
122 }
123 else
124 {
125 Thread.currentThread().yield();
126 }
127 }
128
129 m_socket.close();
130
131 log("Master: stopped");
132 }
133 catch (Exception e)
134 {
135 log("Master: crashed");
136 error(e);
137 }
138
139 fire(TERMINATED);
140 log("Master: terminated");
141 }
142
143 /*
144 * Implement IMasterServer
145 */
146 public void stop()
147 {
148 m_active = false;
149 }
150
151 /*
152 * Implement IMasterServer
153 */
154 synchronized public void shutdown()
155 {
156 log("Master: shutdown");
157
158 stop();
159
160 // Stop all forked servers
161 for (Iterator i = m_servers.iterator(); i.hasNext(); )
162 {
163 Server s = (Server)i.next();
164 s.stop1();
165 }
166 }
167
168 /**
169 * Inform servers about clients list changes
170 */
171 synchronized private void clientListChanged() throws Exception
172 {
173 // Debug info
174 log("Master: Clients list changes: " + m_servers.size() +
175 " clients on-line");
176
177 // Send message to each server
178 for (Iterator i = m_servers.iterator(); i.hasNext(); )
179 {
180 Server s = (Server)i.next();
181 s.enque(new Message(Message.CLIENT_LIST_CHANGED, getClients(), null));
182 }
183
184 // Notify listeners
185 fire(LIST_CHANGED, getClients());
186 }
187
188 /**
189 * Register new server
190 * @param s server
191 * @return true on success, otherwise false
192 */
193 synchronized boolean register(Server s) throws Exception
194 {
195 // Check talk clients number
196 if (m_servers.size() >= getTalkLimit())
197 {
198 // Registration failed, inform client about that
199 s.enque(new Message(Message.REJECT, getClients(),
200 "The number of clients on-line has reached maximum: " +
201 getTalkLimit()));
202 return false;
203 }
204 // Check unique name
205 else if (m_clients.contains(s.getClient()))
206 {
207 // Registration failed, inform client about that
208 s.enque(new Message(Message.REJECT, getClients(),
209 "This name is already used"));
210 return false;
211 }
212 else
213 {
214 // Successful, inform client about that
215 s.enque(new Message(Message.ACCEPT));
216 }
217
218 // Update lists
219 m_servers.add(s);
220 m_clients.add(s.getClient());
221 // Inform others
222 clientListChanged();
223 return true;
224 }
225
226 /**
227 * Unregister server
228 * @param s server
229 */
230 synchronized void unregister(Server s) throws Exception
231 {
232 // Update lists
233 boolean bChanged = m_servers.remove(s);
234 m_clients.remove(s.getClient());
235 // Inform others
236 if (bChanged)
237 clientListChanged();
238 }
239
240 /**
241 * Get a list of registered servers
242 * @return list of Server objects
243 */
244 synchronized public final List getServers()
245 {
246 return Collections.unmodifiableList(m_servers);
247 }
248
249 /**
250 * Get a list of clients being served
251 * @return list of Client objects
252 */
253 synchronized public final List getClients()
254 {
255 return Collections.unmodifiableList(m_clients);
256 }
257
258 /**
259 * Get server object from client object
260 * @param c client object
261 */
262 synchronized public final Server getServer(Client c)
263 {
264 // Check each server
265 for (Iterator i = m_servers.iterator(); i.hasNext(); )
266 {
267 Server s = (Server)i.next();
268 if (c.equals(s.getClient()))
269 return s;
270 }
271
272 return null;
273 }
274
275 /*
276 * Implement IMasterServer
277 */
278 public final int getLimit()
279 {
280 return m_limit;
281 }
282
283 /*
284 * Implement IMasterServer
285 */
286 public void setLimit(int limit)
287 {
288 m_limit = limit;
289 }
290
291 /*
292 * Implement IMasterServer
293 */
294 public final int getTalkLimit()
295 {
296 return m_talkLimit;
297 }
298
299 /*
300 * Implement IMasterServer
301 */
302 public void setTalkLimit(int limit)
303 {
304 m_talkLimit = limit;
305 }
306
307 /**
308 * Logging routine
309 * @param s log message
310 */
311 synchronized protected void log(String s)
312 {
313 System.out.println(s);
314 fire(LOG, s);
315 }
316
317 /**
318 * Report error
319 * @param e exception
320 * @param s server
321 */
322 synchronized void error(Exception e, Server s)
323 {
324 System.out.println(s.getSignature());
325 error(e);
326 }
327 }
|