1 package uk.ac.vamsas.client.picking;
\r
5 import java.util.logging.*;
\r
8 * Concrete implementation of the IPickManager interface that uses sockets for
\r
9 * message communication. An instance of this class attempts to run the central
\r
10 * server for other clients; failing that, it attempts to connect to an existing
\r
13 public class SocketManager implements IPickManager
\r
15 private Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");
\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
23 private PickServer server;
\r
25 private IMessageHandler msgHandler;
\r
28 * Constructs a new PickManager. This method will return immediately, while
\r
29 * a looping thread runs that attempts to run the server or connect to an
\r
32 public SocketManager()
\r
34 // logger.setLevel(Level.OFF);
\r
36 server = new PickServer(this);
\r
37 clients = new LinkedList();
\r
39 new InitializeThread().start();
\r
43 * Registers a message handler with the manager that allows the manager to
\r
44 * perform a method callback on that object whenever a message is received.
\r
45 * @param handler the message handler to register
\r
47 public void registerMessageHandler(IMessageHandler handler)
\r
49 msgHandler = handler;
\r
53 * Attempts to establish a connection between two client endpoints. This
\r
54 * method is called in two ways: 1) by the server when it receives a remote
\r
55 * request (in which case the socket will already be established) and 2) by
\r
56 * a client that is attempting to connect *to* the server.
\r
57 * @param socket a socket endpoint for the connection
\r
58 * @return true if the connection is successfully, false otherwise
\r
60 synchronized boolean addEndPoint(Socket socket)
\r
62 PickEndPoint client = new PickEndPoint(this, socket);
\r
64 if (client.openConnection())
\r
66 clients.add(client);
\r
67 logger.info("List now contains " + clients.size() + " client(s)");
\r
75 * Sends a message to other clients.
\r
76 * @param message the message to send
\r
78 public void sendMessage(Message message)
\r
80 forwardMessage(null, message);
\r
84 * Forwards (or sends) a message. When the server (client A) receives a
\r
85 * message from client B, it must also forward it to clients C and D (etc),
\r
86 * but mustn't forward it *back* to client B.
\r
87 * @param origin the client endpoint that received the message (will be null
\r
88 * if the message originates from this instance
\r
89 * @param message the message to send
\r
91 private void forwardMessage(PickEndPoint origin, Message message)
\r
93 ListIterator itor = clients.listIterator();
\r
94 while (itor.hasNext())
\r
96 PickEndPoint client = (PickEndPoint) itor.next();
\r
98 if (client != origin)
\r
99 client.send(message);
\r
104 * Handles a received message. If the manager is running in server mode,
\r
105 * then it must ensure the message is also forwarded to the other clients.
\r
106 * @param origin the client endpoint that received the message
\r
107 * @message the message that was received
\r
109 void processMessage(PickEndPoint origin, Message message)
\r
111 if (server.isServer())
\r
112 forwardMessage(origin, message);
\r
114 if (msgHandler != null)
\r
115 msgHandler.handleMessage(message);
\r
117 logger.info("No handler available to deal with incoming message");
\r
121 * Removes a client connection from the list when its connection is no
\r
123 * @param client the client endpoint to remove
\r
125 synchronized void removeEndPoint(PickEndPoint client)
\r
127 clients.remove(client);
\r
128 logger.info("List now contains " + clients.size() + " client(s)");
\r
130 // If there's no endpoints left, then we've lost all connections and
\r
131 // need to reinitialize
\r
132 if (clients.size() == 0)
\r
133 new InitializeThread().start();
\r
137 * Thread extension class to handle the actual initialization
\r
139 private class InitializeThread extends Thread
\r
143 logger.info("Initializing connection...");
\r
144 boolean connected = false;
\r
146 // Loop until we can get a connection (one way or the other)
\r
149 // Sleep for a rnd time so we don't end up with all the VAMSAS
\r
150 // apps trying to initialize servers at the same time
\r
151 try { Thread.sleep((int)Math.random()); }
\r
152 catch (InterruptedException e) {}
\r
154 // Attempt to open the server port...
\r
155 if (server.isServer() || server.createServer())
\r
158 // If it fails, then attempt to make a client connection...
\r
159 else if (addEndPoint(null))
\r