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 sthrows 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 sthrows 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 }
Java2html