Picking API now has message classes and basic implementation of interfaces (for its...
authorimilne <imilne@issues.jalview.org>
Thu, 14 Dec 2006 19:29:20 +0000 (19:29 +0000)
committerimilne <imilne@issues.jalview.org>
Thu, 14 Dec 2006 19:29:20 +0000 (19:29 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@302 be28352e-c001-0410-b1a7-c7978e42abec

src/uk/ac/vamsas/client/picking/CustomMessage.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/IMessageHandler.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/IPickManager.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/Message.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/MouseOverMessage.java [new file with mode: 0644]
src/uk/ac/vamsas/client/picking/PickEndPoint.java
src/uk/ac/vamsas/client/picking/PickServer.java
src/uk/ac/vamsas/client/picking/SocketManager.java [moved from src/uk/ac/vamsas/client/picking/PickManager.java with 64% similarity]
src/uk/ac/vamsas/client/picking/TestApp.java

diff --git a/src/uk/ac/vamsas/client/picking/CustomMessage.java b/src/uk/ac/vamsas/client/picking/CustomMessage.java
new file mode 100644 (file)
index 0000000..3f07cfc
--- /dev/null
@@ -0,0 +1,17 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+/**\r
+ * Defines a custom message that applications can use to send message types that\r
+ * haven't been predefined in the API.\r
+ */\r
+public class CustomMessage extends Message\r
+{      \r
+       /**\r
+        * Constructs a new custom message.\r
+        * @param message the message to be sent\r
+        */\r
+       public CustomMessage(String message)\r
+       {\r
+               this.message = "CUSTOM_" + message;\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/IMessageHandler.java b/src/uk/ac/vamsas/client/picking/IMessageHandler.java
new file mode 100644 (file)
index 0000000..e09b81d
--- /dev/null
@@ -0,0 +1,15 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+/**\r
+ * Interface that defines the methods required for a message handler. This\r
+ * interface must be implemented by the client application (TOPALi, Jalview or\r
+ * AstexViewer).\r
+ */\r
+public interface IMessageHandler\r
+{\r
+       /**\r
+        * Responds to a message received event.\r
+        * @param message the message that was received\r
+        */\r
+       public void handleMessage(Message message);\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/IPickManager.java b/src/uk/ac/vamsas/client/picking/IPickManager.java
new file mode 100644 (file)
index 0000000..6c9615d
--- /dev/null
@@ -0,0 +1,20 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+/**\r
+ * Interface that defines the methods required for a pick manager.\r
+ */\r
+public interface IPickManager\r
+{\r
+       /**\r
+        * Sends a message.\r
+        * @param message the message to send\r
+        */\r
+       public void sendMessage(Message message);\r
+       \r
+       /**\r
+        * Registers a message handler with the manager that allows the manager to\r
+        * perform a method callback on that object whenever a message is received.\r
+        * @param handler the message handler to register\r
+        */\r
+       public void registerMessageHandler(IMessageHandler handler);\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/Message.java b/src/uk/ac/vamsas/client/picking/Message.java
new file mode 100644 (file)
index 0000000..1a0165d
--- /dev/null
@@ -0,0 +1,24 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+/**\r
+ * Abstract base class for all message types supported by the picking API.\r
+ */\r
+public abstract class Message\r
+{\r
+       protected String message;\r
+       \r
+       /**\r
+        * Constructs a new message.\r
+        */\r
+       protected Message()\r
+       {\r
+\r
+       }\r
+       \r
+       /**\r
+        * Returns the raw message content as a string.\r
+        * @return the raw message content as a string\r
+        */\r
+       public String getRawMessage()\r
+               { return message; }\r
+}
\ No newline at end of file
diff --git a/src/uk/ac/vamsas/client/picking/MouseOverMessage.java b/src/uk/ac/vamsas/client/picking/MouseOverMessage.java
new file mode 100644 (file)
index 0000000..d14dc22
--- /dev/null
@@ -0,0 +1,38 @@
+package uk.ac.vamsas.client.picking;\r
+\r
+/**\r
+ * Message class that can be used to send mouse over events.\r
+ */\r
+public class MouseOverMessage extends Message\r
+{\r
+       private String vorbaID;\r
+       private int position;\r
+       \r
+       /**\r
+        * Constructs a new mouse over message.\r
+        * @param vorbaID the VAMSAS object ID of the event's source (usually an\r
+        * alignment or alignment sequence)\r
+        * @param position a position on the source in its coordinate system (ie a\r
+        * column or nucleotide/residue position)\r
+        */\r
+       public MouseOverMessage(String vorbaID, int position)\r
+       {\r
+               this.vorbaID = vorbaID;\r
+               this.position = position;\r
+               \r
+               message = "MOUSEOVER_"\r
+                       + "vorbaID=" + vorbaID + "_" + "position=" + position;\r
+       }\r
+       \r
+       /**\r
+        * Constructs a new mouse over message from its underlying string format.\r
+        * @param str the string representation of an instance of this object\r
+        * @throws java.lang.Exception if the message cannot be reconstructed\r
+        */\r
+       MouseOverMessage(String str)\r
+               throws Exception\r
+       {\r
+               String[] elements = str.split("_");\r
+               \r
+       }\r
+}
\ No newline at end of file
index 951e8d4..e62c79e 100644 (file)
@@ -2,17 +2,20 @@ package uk.ac.vamsas.client.picking;
 \r
 import java.io.*;\r
 import java.net.*;\r
+import java.util.logging.*;\r
 \r
 class PickEndPoint extends Thread\r
 {\r
+       private Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");\r
+       \r
        private Socket socket;\r
        private int rPort;\r
        private BufferedWriter os;\r
        private BufferedReader in;\r
 \r
-       private PickManager manager;    \r
+       private SocketManager manager;  \r
        \r
-       PickEndPoint(PickManager manager, Socket s)\r
+       PickEndPoint(SocketManager manager, Socket s)\r
        {\r
                this.manager = manager;\r
                socket = s;\r
@@ -34,7 +37,7 @@ class PickEndPoint extends Thread
                        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
+                       logger.info("CLIENT: connection successful to port "\r
                                + socket.getPort() + " via port " + socket.getLocalPort());\r
                        start();\r
                        \r
@@ -42,16 +45,18 @@ class PickEndPoint extends Thread
                }\r
                catch (Exception e)\r
                {\r
-                       System.out.println("CLIENT: connection failed: " + e);\r
+                       logger.info("CLIENT: connection failed: " + e);\r
                        return false;\r
                }\r
        }\r
        \r
-       void send(String str)\r
+       void send(Message message)\r
        {\r
                try\r
                {\r
-                       System.out.println("CLIENT: send " + str + " to " + rPort);\r
+                       String str = message.getRawMessage();\r
+                       \r
+                       logger.info("CLIENT: send " + str + " to " + rPort);\r
                        os.write(str);\r
                        \r
                        // We use a newline to terminate the message\r
@@ -60,7 +65,7 @@ class PickEndPoint extends Thread
                }\r
                catch (Exception e)\r
                {\r
-                       System.out.println("CLIENT: failed to send");\r
+                       logger.info("CLIENT: failed to send");\r
                        \r
                        // TODO: terminate the connection on a failed send or retry?\r
                        terminate();\r
@@ -75,16 +80,23 @@ class PickEndPoint extends Thread
                        while (true)\r
                        {\r
                                String str = in.readLine();                             \r
-                               System.out.println("CLIENT: recv " + str + " from " + rPort);\r
+                               logger.info("CLIENT: recv " + str + " from " + rPort);\r
+                               \r
+                               // TODO: Spawn this off into the GUI Event-Dispatch thread...\r
+                               \r
+                               // Convert the string back into something API friendly\r
+                               Message message = strToMessage(str);\r
                                \r
-                               manager.handleMessage(this, str);\r
+                               // Ignore corrupted or unknown message types\r
+                               if (message != null)                            \r
+                                       manager.processMessage(this, message);\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
+                       logger.info("CLIENT: read failed: " + e);\r
                                                \r
                        terminate();\r
                }\r
@@ -95,7 +107,25 @@ class PickEndPoint extends Thread
                try { socket.close(); }\r
                catch (IOException e) {}\r
                \r
-               System.out.println("CLIENT: closing connection to port " + socket.getPort());\r
+               logger.info("CLIENT: closing connection to port " + socket.getPort());\r
                manager.removeEndPoint(this);\r
        }\r
+       \r
+       private Message strToMessage(String str)\r
+       {\r
+               try\r
+               {\r
+                       if (str.startsWith("CUSTOM_"))\r
+                               return new CustomMessage(str.substring(7));\r
+               \r
+                       if (str.startsWith("MOUSEOVER_"))\r
+                               return new MouseOverMessage(str);\r
+               }\r
+               catch (Exception e)\r
+               {\r
+                       logger.info("Unable to reconstruct message: " + e);\r
+               }\r
+               \r
+               return null;\r
+       }\r
 }
\ No newline at end of file
index 61884a3..2247049 100644 (file)
@@ -9,7 +9,7 @@ import java.util.logging.*;
  */\r
 class PickServer extends Thread\r
 {\r
-       private static Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");\r
+       private 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
@@ -18,13 +18,13 @@ class PickServer extends Thread
        // Set to true once the server is established\r
        private boolean isServer = false;\r
        \r
-       private PickManager manager;\r
+       private SocketManager 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
+       PickServer(SocketManager manager)\r
        {\r
                this.manager = manager;\r
        }\r
@@ -63,7 +63,7 @@ class PickServer extends Thread
         */\r
        public void run()\r
        {\r
-               logger.fine("SERVER: listening on " + PORT + " - SERVER");\r
+               logger.info("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
@@ -73,7 +73,7 @@ class PickServer extends Thread
                        try\r
                        {\r
                                Socket socket = serverSocket.accept();                          \r
-                               logger.fine("SERVER: connection detected");\r
+                               logger.info("SERVER: connection detected");\r
                                \r
                                manager.addEndPoint(socket);\r
                        }\r
@@ -5,14 +5,14 @@ import java.util.*;
 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
+ * Concrete implementation of the IPickManager interface that uses sockets for\r
+ * message communication. An instance of this class attempts to run the central\r
+ * server for other clients; failing that, it attempts to connect to an existing\r
+ * server instead.\r
  */\r
-public class PickManager\r
+public class SocketManager implements IPickManager\r
 {\r
-       private static Logger logger = Logger.getLogger("uk.ac.vamsas.client.picking");\r
+       private 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
@@ -22,13 +22,17 @@ public class PickManager
        \r
        private PickServer server;\r
        \r
+       private IMessageHandler msgHandler;\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
+       public SocketManager()\r
        {\r
+//             logger.setLevel(Level.OFF);\r
+               \r
                server = new PickServer(this);\r
                clients = new LinkedList();\r
                \r
@@ -36,6 +40,16 @@ public class PickManager
        }\r
        \r
        /**\r
+        * Registers a message handler with the manager that allows the manager to\r
+        * perform a method callback on that object whenever a message is received.\r
+        * @param handler the message handler to register\r
+        */\r
+       public void registerMessageHandler(IMessageHandler handler)\r
+       {\r
+               msgHandler = handler;\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
@@ -43,14 +57,14 @@ public class PickManager
         * @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
+       synchronized 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
+                       logger.info("List now contains " + clients.size() + " client(s)");\r
                        return true;\r
                }\r
                \r
@@ -59,11 +73,11 @@ public class PickManager
        \r
        /**\r
         * Sends a message to other clients.\r
-        * @param str the message to send\r
+        * @param message the message to send\r
         */\r
-       public void sendMessage(String str)\r
+       public void sendMessage(Message message)\r
        {\r
-               forwardMessage(null, str);\r
+               forwardMessage(null, message);\r
        }\r
        \r
        /**\r
@@ -72,9 +86,9 @@ public class PickManager
         * 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
+        * @param message the message to send\r
         */\r
-       private void forwardMessage(PickEndPoint origin, String str)\r
+       private void forwardMessage(PickEndPoint origin, Message message)\r
        {\r
                ListIterator itor = clients.listIterator();\r
                while (itor.hasNext())\r
@@ -82,7 +96,7 @@ public class PickManager
                        PickEndPoint client = (PickEndPoint) itor.next();\r
                        \r
                        if (client != origin)\r
-                               client.send(str);\r
+                               client.send(message);\r
                }\r
        }\r
        \r
@@ -90,14 +104,17 @@ public class PickManager
         * 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
+        * @message the message that was received\r
         */\r
-       void handleMessage(PickEndPoint origin, String str)\r
-       {\r
+       void processMessage(PickEndPoint origin, Message message)\r
+       {       \r
                if (server.isServer())\r
-                       forwardMessage(origin, str);\r
-               \r
-               // TODO: pass message to VAMSAS API\r
+                       forwardMessage(origin, message);\r
+                       \r
+               if (msgHandler != null)\r
+                       msgHandler.handleMessage(message);\r
+               else\r
+                       logger.info("No handler available to deal with incoming message");\r
        }\r
        \r
        /**\r
@@ -105,10 +122,10 @@ public class PickManager
         * longer valid.\r
         * @param client the client endpoint to remove\r
         */\r
-       void removeEndPoint(PickEndPoint client)\r
+       synchronized void removeEndPoint(PickEndPoint client)\r
        {\r
                clients.remove(client);\r
-               logger.fine("List now contains " + clients.size() + " client(s)");\r
+               logger.info("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
@@ -123,7 +140,7 @@ public class PickManager
        {\r
                public void run()\r
                {\r
-                       logger.fine("Initializing connection...");\r
+                       logger.info("Initializing connection...");\r
                        boolean connected = false;\r
                        \r
                        // Loop until we can get a connection (one way or the other)\r
index 988939b..95b23dc 100644 (file)
@@ -2,32 +2,36 @@ package uk.ac.vamsas.client.picking;
 \r
 import java.util.logging.*;\r
 \r
-public class TestApp\r
+/**\r
+ * Simple example of a (runnable) class that shows how to use the picking API.\r
+ */\r
+public class TestApp implements IMessageHandler\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
+       \r
+       public TestApp()\r
+       {\r
+               IPickManager manager = new SocketManager();\r
+               manager.registerMessageHandler(this);\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
+                       CustomMessage msg = new CustomMessage("" + rnd);\r
+                       \r
+                       manager.sendMessage(msg);\r
                }\r
        }\r
        \r
-       public TestApp()\r
+       public void handleMessage(Message message)\r
        {\r
+//             System.out.println("Handler received " + message.getRawMessage());\r
        }\r
 }
\ No newline at end of file