refactored org to uk
authorjprocter <jprocter@compbio.dundee.ac.uk>
Thu, 14 Dec 2006 17:50:39 +0000 (17:50 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Thu, 14 Dec 2006 17:50:39 +0000 (17:50 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@267 be28352e-c001-0410-b1a7-c7978e42abec

src/uk/ac/vamsas/client/picking/PickEndPoint.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/PickManager.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/PickServer.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/TestApp.java [new file with mode: 0644]

diff --git a/src/uk/ac/vamsas/client/picking/PickEndPoint.java b/src/uk/ac/vamsas/client/picking/PickEndPoint.java
new file mode 100644 (file)
index 0000000..951e8d4
--- /dev/null
@@ -0,0 +1,101 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+import java.io.*;\r
+import java.net.*;\r
+\r
+class PickEndPoint extends Thread\r
+{\r
+       private Socket socket;\r
+       private int rPort;\r
+       private BufferedWriter os;\r
+       private BufferedReader in;\r
+\r
+       private PickManager manager;    \r
+       \r
+       PickEndPoint(PickManager manager, Socket s)\r
+       {\r
+               this.manager = manager;\r
+               socket = s;\r
+       }\r
+       \r
+       boolean openConnection()\r
+       {\r
+               try\r
+               {\r
+                       // Create the socket if it doesn't already exist\r
+                       if (socket == null)\r
+                               socket = new Socket(InetAddress.getLocalHost(), PickServer.PORT);\r
+                       \r
+                       rPort = socket.getPort();\r
+                       socket.setKeepAlive(true);\r
+                                               \r
+                       // Open the streams for reading/writing\r
+                       os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));\r
+                       in = new BufferedReader(new InputStreamReader(socket.getInputStream()));\r
+               \r
+                       // Start the thread to listen for incoming messages\r
+                       System.out.println("CLIENT: connection successful to port "\r
+                               + socket.getPort() + " via port " + socket.getLocalPort());\r
+                       start();\r
+                       \r
+                       return true;\r
+               }\r
+               catch (Exception e)\r
+               {\r
+                       System.out.println("CLIENT: connection failed: " + e);\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       void send(String str)\r
+       {\r
+               try\r
+               {\r
+                       System.out.println("CLIENT: send " + str + " to " + rPort);\r
+                       os.write(str);\r
+                       \r
+                       // We use a newline to terminate the message\r
+                       os.newLine();\r
+                       os.flush();\r
+               }\r
+               catch (Exception e)\r
+               {\r
+                       System.out.println("CLIENT: failed to send");\r
+                       \r
+                       // TODO: terminate the connection on a failed send or retry?\r
+                       terminate();\r
+               }\r
+       }\r
+       \r
+       // void receive() (threaded)\r
+       public void run()\r
+       {\r
+               try\r
+               {\r
+                       while (true)\r
+                       {\r
+                               String str = in.readLine();                             \r
+                               System.out.println("CLIENT: recv " + str + " from " + rPort);\r
+                               \r
+                               manager.handleMessage(this, str);\r
+                       }\r
+               }\r
+               catch (Exception e)\r
+               {\r
+                       // Means the other end of the connection has (probably died) so we need\r
+                       // terminate this endpoint (if this is server side)\r
+                       System.out.println("CLIENT: read failed: " + e);\r
+                                               \r
+                       terminate();\r
+               }\r
+       }\r
+       \r
+       private void terminate()\r
+       {\r
+               try { socket.close(); }\r
+               catch (IOException e) {}\r
+               \r
+               System.out.println("CLIENT: closing connection to port " + socket.getPort());\r
+               manager.removeEndPoint(this);\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/PickManager.java b/src/uk/ac/vamsas/client/picking/PickManager.java
new file mode 100644 (file)
index 0000000..ee03f8a
--- /dev/null
@@ -0,0 +1,147 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+import java.net.*;\r
+import java.util.*;\r
+import java.util.logging.*;\r
+\r
+/**\r
+ * Manager class that maintains a list of connected clients in addition to\r
+ * attempting to run a server to listen for client connections. If the server\r
+ * initialization fails, then an attempt to connect (as a client) to another JVM\r
+ * that is already a server happens instead.\r
+ */\r
+public class PickManager\r
+{\r
+       private static Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");\r
+       \r
+       // Maintains a list of client communication objects - each object represents\r
+       // a way of talking to either:\r
+       //  the server - if this is client side (and in which case, the list will only contain one element\r
+       //  the other clients - if this is server side\r
+       private LinkedList clients;\r
+       \r
+       private PickServer server;\r
+       \r
+       /**\r
+        * Constructs a new PickManager. This method will return immediately, while\r
+        * a looping thread runs that attempts to run the server or connect to an\r
+        * existing server.\r
+        */\r
+       public PickManager()\r
+       {\r
+               server = new PickServer(this);\r
+               clients = new LinkedList();\r
+               \r
+               new InitializeThread().start();\r
+       }\r
+       \r
+       /**\r
+        * Attempts to establish a connection between two client endpoints. This\r
+        * method is called in two ways: 1) by the server when it receives a remote\r
+        * request (in which case the socket will already be established) and 2) by\r
+        * a client that is attempting to connect *to* the server.\r
+        * @param socket a socket endpoint for the connection\r
+        * @return true if the connection is successfully, false otherwise\r
+        */\r
+       boolean addEndPoint(Socket socket)\r
+       {\r
+               PickEndPoint client = new PickEndPoint(this, socket);\r
+               \r
+               if (client.openConnection())\r
+               {\r
+                       clients.add(client);\r
+                       logger.fine("List now contains " + clients.size() + " client(s)");\r
+                       return true;\r
+               }\r
+               \r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Sends a message to other clients.\r
+        * @param str the message to send\r
+        */\r
+       public void sendMessage(String str)\r
+       {\r
+               forwardMessage(null, str);\r
+       }\r
+       \r
+       /**\r
+        * Forwards (or sends) a message. When the server (client A) receives a\r
+        * message from client B, it must also forward it to clients C and D (etc),\r
+        * but mustn't forward it *back* to client B.\r
+        * @param origin the client endpoint that received the message (will be null\r
+        * if the message originates from this instance\r
+        * @param str the message to send\r
+        */\r
+       private void forwardMessage(PickEndPoint origin, String str)\r
+       {\r
+               ListIterator itor = clients.listIterator();\r
+               while (itor.hasNext())\r
+               {\r
+                       PickEndPoint client = (PickEndPoint) itor.next();\r
+                       \r
+                       if (client != origin)\r
+                               client.send(str);\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Handles a received message. If the manager is running in server mode,\r
+        * then it must ensure the message is also forwarded to the other clients.\r
+        * @param origin the client endpoint that received the message\r
+        * @str the message that was received\r
+        */\r
+       void handleMessage(PickEndPoint origin, String str)\r
+       {\r
+               if (server.isServer())\r
+                       forwardMessage(origin, str);\r
+               \r
+               // TODO: pass message to VAMSAS API\r
+       }\r
+       \r
+       /**\r
+        * Removes a client connection from the list when its connection is no\r
+        * longer valid.\r
+        * @param client the client endpoint to remove\r
+        */\r
+       void removeEndPoint(PickEndPoint client)\r
+       {\r
+               clients.remove(client);\r
+               logger.fine("List now contains " + clients.size() + " client(s)");\r
+               \r
+               // If there's no endpoints left, then we've lost all connections and\r
+               // need to reinitialize\r
+               if (clients.size() == 0)\r
+                       new InitializeThread().start();\r
+       }\r
+       \r
+       /**\r
+        * Thread extension class to handle the actual initialization\r
+        */\r
+       private class InitializeThread extends Thread\r
+       {\r
+               public void run()\r
+               {\r
+                       logger.fine("Initializing connection...");\r
+                       boolean connected = false;\r
+                       \r
+                       // Loop until we can get a connection (one way or the other)\r
+                       while (!connected)\r
+                       {\r
+                               // Sleep for a rnd time so we don't end up with all the VAMSAS\r
+                               // apps trying to initialize servers at the same time\r
+                               try { Thread.sleep((int)Math.random()); }\r
+                               catch (InterruptedException e) {}\r
+                                       \r
+                               // Attempt to open the server port...\r
+                               if (server.isServer() || server.createServer())\r
+                                       connected = true;\r
+\r
+                               // If it fails, then attempt to make a client connection...\r
+                               else if (addEndPoint(null))\r
+                                       connected = true;\r
+                       }\r
+               }\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/PickServer.java b/src/uk/ac/vamsas/client/picking/PickServer.java
new file mode 100644 (file)
index 0000000..61884a3
--- /dev/null
@@ -0,0 +1,83 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+import java.io.*;\r
+import java.net.*;\r
+import java.util.logging.*;\r
+\r
+/**\r
+ * Server class that listens for incoming connections on a predefined port.\r
+ */\r
+class PickServer extends Thread\r
+{\r
+       private static Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");\r
+       \r
+       // The port number we'll listen on\r
+       static final int PORT = 53782;\r
+       \r
+       private ServerSocket serverSocket;\r
+       // Set to true once the server is established\r
+       private boolean isServer = false;\r
+       \r
+       private PickManager manager;\r
+       \r
+       /**\r
+        * Constructs a new instance of the server (but doesn't start it).\r
+        * @param manager a reference to the pick manager that owns this server\r
+        */\r
+       PickServer(PickManager manager)\r
+       {\r
+               this.manager = manager;\r
+       }\r
+       \r
+       /**\r
+        * Returns true if this server instance is running.\r
+        * Return true if this server instance is running\r
+        */\r
+       boolean isServer()\r
+               { return isServer; }\r
+       \r
+       /**\r
+        * Attempts to create the server by opening a server socket on the port.\r
+        * @return true if the server was created; false otherwise\r
+        */\r
+       boolean createServer()\r
+       {\r
+               try\r
+               {\r
+                       serverSocket = new ServerSocket(PORT);\r
+                       start();                        \r
+                       \r
+                       return isServer = true;\r
+               }\r
+               catch (IOException e)\r
+               {\r
+                       logger.info("SERVER: " + e);\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Thread listening method - loops indefinitely listening for connections.\r
+        * When one is received, the socket object is passed to the manager so it\r
+        * can make a full client connection for further comms.\r
+        */\r
+       public void run()\r
+       {\r
+               logger.fine("SERVER: listening on " + PORT + " - SERVER");\r
+               \r
+               // Loop forever, accepting connectons from other clients\r
+               // TODO: add in the ability to terminate the server if a VAMSAS session\r
+               // is ended\r
+               while (true)\r
+               {\r
+                       try\r
+                       {\r
+                               Socket socket = serverSocket.accept();                          \r
+                               logger.fine("SERVER: connection detected");\r
+                               \r
+                               manager.addEndPoint(socket);\r
+                       }\r
+                       catch (IOException e) {}\r
+               }\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/TestApp.java b/src/uk/ac/vamsas/client/picking/TestApp.java
new file mode 100644 (file)
index 0000000..988939b
--- /dev/null
@@ -0,0 +1,33 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+import java.util.logging.*;\r
+\r
+public class TestApp\r
+{\r
+       private static Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");\r
+       \r
+       public static void main(String[] args)\r
+               throws Exception\r
+       {\r
+//             logger.setLevel(Level.INFO);\r
+               \r
+               TestApp app = new TestApp();\r
+               \r
+               PickManager manager = new PickManager();\r
+               \r
+               // Send 5 test messages...\r
+//             for (int i = 0; i < 5; i++)\r
+               while (true)\r
+               {                       \r
+                       try { Thread.sleep((int) (Math.random()*20000)); }\r
+                       catch (InterruptedException e) {}\r
+                       \r
+                       int rnd = (int) (Math.random()*100);\r
+                       manager.sendMessage("" + rnd);\r
+               }\r
+       }\r
+       \r
+       public TestApp()\r
+       {\r
+       }\r
+}
\ No newline at end of file