c313e254a83530594751b3635481691db64ab6a0
[vamsas.git] / src / org / vamsas / client / picking / PickManager.java
1 package org.vamsas.client.picking;\r
2 \r
3 import java.net.*;\r
4 import java.util.*;\r
5 import java.util.logging.*;\r
6 \r
7 /**\r
8  * Manager class that maintains a list of connected clients in addition to\r
9  * attempting to run a server to listen for client connections. If the server\r
10  * initialization fails, then an attempt to connect (as a client) to another JVM\r
11  * that is already a server happens instead.\r
12  */\r
13 public class PickManager\r
14 {\r
15         private static Logger logger = Logger.getLogger("org.vamsas.client.picking");\r
16         \r
17         // Maintains a list of client communication objects - each object represents\r
18         // a way of talking to either:\r
19         //  the server - if this is client side (and in which case, the list will only contain one element\r
20         //  the other clients - if this is server side\r
21         private LinkedList clients;\r
22         \r
23         private PickServer server;\r
24         \r
25         /**\r
26          * Constructs a new PickManager. This method will return immediately, while\r
27          * a looping thread runs that attempts to run the server or connect to an\r
28          * existing server.\r
29          */\r
30         public PickManager()\r
31         {\r
32                 server = new PickServer(this);\r
33                 clients = new LinkedList();\r
34                 \r
35                 new InitializeThread().start();\r
36         }\r
37         \r
38         /**\r
39          * Attempts to establish a connection between two client endpoints. This\r
40          * method is called in two ways: 1) by the server when it receives a remote\r
41          * request (in which case the socket will already be established) and 2) by\r
42          * a client that is attempting to connect *to* the server.\r
43          * @param socket a socket endpoint for the connection\r
44          * @return true if the connection is successfully, false otherwise\r
45          */\r
46         boolean addEndPoint(Socket socket)\r
47         {\r
48                 PickEndPoint client = new PickEndPoint(this, socket);\r
49                 \r
50                 if (client.openConnection())\r
51                 {\r
52                         clients.add(client);\r
53                         logger.fine("List now contains " + clients.size() + " client(s)");\r
54                         return true;\r
55                 }\r
56                 \r
57                 return false;\r
58         }\r
59         \r
60         /**\r
61          * Sends a message to other clients.\r
62          * @param str the message to send\r
63          */\r
64         public void sendMessage(String str)\r
65         {\r
66                 forwardMessage(null, str);\r
67         }\r
68         \r
69         /**\r
70          * Forwards (or sends) a message. When the server (client A) receives a\r
71          * message from client B, it must also forward it to clients C and D (etc),\r
72          * but mustn't forward it *back* to client B.\r
73          * @param origin the client endpoint that received the message (will be null\r
74          * if the message originates from this instance\r
75          * @param str the message to send\r
76          */\r
77         private void forwardMessage(PickEndPoint origin, String str)\r
78         {\r
79                 ListIterator itor = clients.listIterator();\r
80                 while (itor.hasNext())\r
81                 {\r
82                         PickEndPoint client = (PickEndPoint) itor.next();\r
83                         \r
84                         if (client != origin)\r
85                                 client.send(str);\r
86                 }\r
87         }\r
88         \r
89         /**\r
90          * Handles a received message. If the manager is running in server mode,\r
91          * then it must ensure the message is also forwarded to the other clients.\r
92          * @param origin the client endpoint that received the message\r
93          * @str the message that was received\r
94          */\r
95         void handleMessage(PickEndPoint origin, String str)\r
96         {\r
97                 if (server.isServer())\r
98                         forwardMessage(origin, str);\r
99                 \r
100                 // TODO: pass message to VAMSAS API\r
101         }\r
102         \r
103         /**\r
104          * Removes a client connection from the list when its connection is no\r
105          * longer valid.\r
106          * @param client the client endpoint to remove\r
107          */\r
108         void removeEndPoint(PickEndPoint client)\r
109         {\r
110                 clients.remove(client);\r
111                 logger.fine("List now contains " + clients.size() + " client(s)");\r
112                 \r
113                 // If there's no endpoints left, then we've lost all connections and\r
114                 // need to reinitialize\r
115                 if (clients.size() == 0)\r
116                         new InitializeThread().start();\r
117         }\r
118         \r
119         /**\r
120          * Thread extension class to handle the actual initialization\r
121          */\r
122         private class InitializeThread extends Thread\r
123         {\r
124                 public void run()\r
125                 {\r
126                         logger.fine("Initializing connection...");\r
127                         boolean connected = false;\r
128                         \r
129                         // Loop until we can get a connection (one way or the other)\r
130                         while (!connected)\r
131                         {\r
132                                 // Sleep for a rnd time so we don't end up with all the VAMSAS\r
133                                 // apps trying to initialize servers at the same time\r
134                                 try { Thread.sleep((int)Math.random()); }\r
135                                 catch (InterruptedException e) {}\r
136                                         \r
137                                 // Attempt to open the server port...\r
138                                 if (server.isServer() || server.createServer())\r
139                                         connected = true;\r
140 \r
141                                 // If it fails, then attempt to make a client connection...\r
142                                 else if (addEndPoint(null))\r
143                                         connected = true;\r
144                         }\r
145                 }\r
146         }\r
147 }