Added shutdown() methods for the socket-based PickManager code.
authorimilne <imilne@issues.jalview.org>
Wed, 7 Mar 2007 11:09:07 +0000 (11:09 +0000)
committerimilne <imilne@issues.jalview.org>
Wed, 7 Mar 2007 11:09:07 +0000 (11:09 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@350 be28352e-c001-0410-b1a7-c7978e42abec

src/uk/ac/vamsas/client/picking/IPickManager.java
src/uk/ac/vamsas/client/picking/PickEndPoint.java
src/uk/ac/vamsas/client/picking/PickServer.java
src/uk/ac/vamsas/client/picking/SocketManager.java
src/uk/ac/vamsas/client/picking/TestApp.java
src/uk/ac/vamsas/client/simpleclient/SimpleClient.java
src/uk/ac/vamsas/client/simpleclient/SimplePickManager.java
src/uk/ac/vamsas/test/ExampleApplication.java

index 6c9615d..a91802d 100644 (file)
@@ -17,4 +17,10 @@ public interface IPickManager
         * @param handler the message handler to register\r
         */\r
        public void registerMessageHandler(IMessageHandler handler);\r
+       \r
+       /**\r
+        * Shutsdown the pick manager processes, terminating any connections to\r
+        * other clients.\r
+        */\r
+       public void shutdown();\r
 }
\ No newline at end of file
index 1864874..8191a80 100644 (file)
@@ -39,15 +39,15 @@ class PickEndPoint extends Thread
                        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));\r
                \r
                        // Start the thread to listen for incoming messages\r
-//                     logger.info("CLIENT: connection successful to port "\r
-//                             + socket.getPort() + " via port " + socket.getLocalPort());\r
+                       logger.info("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
-                       //logger.info("CLIENT: connection failed: " + e);\r
+                       logger.info("CLIENT: connection failed: " + e);\r
                        return false;\r
                }\r
        }\r
@@ -73,40 +73,13 @@ class PickEndPoint extends Thread
                        terminate();\r
                }\r
        }\r
-  /**\r
-   * state of server thread - running or not running\r
-   */\r
-  private boolean running=false;\r
-  /**\r
-   * condition for server thread to stop\r
-   */\r
-  private boolean enabled=true;\r
-  public void haltEndpoint() {\r
-  // TODO: FIX THIS METHOD\r
-    if (!running || !enabled) {\r
-      logger.debug("PickEndpoint is not running or already requested to halt.");\r
-      return;\r
-    }\r
-    logger.debug("Disabling pick endpoint.");\r
-    enabled=false;\r
-    terminate();\r
-    while (running) {\r
-      try {\r
-        Thread.sleep(1);\r
-      } catch (Exception e) {\r
-      }\r
-    }\r
-    logger.debug("Pick endpoint has stopped.");\r
-  }\r
-\r
+       \r
        // void receive() (threaded)\r
        public void run()\r
        {\r
-    enabled=true;\r
-    running=true;\r
                try\r
                {\r
-                       while (enabled)\r
+                       while (true)\r
                        {\r
                                String str = in.readLine();                             \r
                                //logger.info("CLIENT: recv " + str + " from " + rPort);\r
@@ -114,34 +87,26 @@ class PickEndPoint extends Thread
                                // TODO: Spawn this off into the GUI Event-Dispatch thread...\r
                                \r
                                // Convert the string back into something API friendly\r
-        if (str!=null) {\r
                                Message message = strToMessage(str);\r
                                \r
                                // Ignore corrupted or unknown message types\r
                                if (message != null)                            \r
                                        manager.processMessage(this, message);\r
-        }\r
                        }\r
                }\r
                catch (Exception e)\r
                {\r
-                       // Means the other end of the connection has (probably) died\r
-      logger.debug("Exception in receiver loop: "+e.getMessage());\r
-    }\r
-               // terminate this endpoint (if this is server side)\r
-    //logger.info("CLIENT: read failed: " + e);\r
-          \r
-    terminate();\r
-  \r
-               running=false;\r
+                       // Means the other end of the connection has (probably died) so we need\r
+                       // terminate this endpoint (if this is server side)\r
+                       //logger.info("CLIENT: read failed: " + e);\r
+                                               \r
+                       terminate();\r
+               }\r
        }\r
        \r
-       private void terminate()\r
+       void terminate()\r
        {\r
-               try { \r
-      if (socket.isConnected())\r
-        socket.close(); \r
-      }\r
+               try { socket.close(); }\r
                catch (IOException e) {}\r
                \r
                //logger.info("CLIENT: closing connection to port " + socket.getPort());\r
@@ -150,7 +115,6 @@ class PickEndPoint extends Thread
        \r
        private Message strToMessage(String str)\r
        {\r
-    // TODO: generalize message class \r
                try\r
                {\r
                        if (str.startsWith("CUSTOM"))\r
index ab2aaf8..a9e7c1c 100644 (file)
@@ -57,35 +57,7 @@ class PickServer extends Thread
                        return false;\r
                }\r
        }\r
-  /**\r
-   * state of server thread - running or not running\r
-   */\r
-       private boolean running=false;\r
-  /**\r
-   * condition for server thread to stop\r
-   */\r
-  private boolean enabled=true;\r
-  public void haltServer() {\r
-  // TODO: FIX THIS METHOD\r
-    if (!running || !enabled) {\r
-      logger.debug("PickServer is not running or already requested to halt.");\r
-      return;\r
-    }\r
-    logger.debug("Disabling pick server.");\r
-    enabled=false;\r
-    while (running) {\r
-      try {\r
-        serverSocket.close();\r
-      } catch (Exception e) {\r
-        \r
-      }\r
-      try {\r
-        Thread.sleep(5);\r
-      } catch (Exception e) {\r
-      }\r
-    }\r
-    logger.debug("Pick server has stopped.");\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
@@ -93,25 +65,32 @@ class PickServer extends Thread
         */\r
        public void run()\r
        {\r
-    enabled=true;\r
-    running=true;\r
-               //logger.info("SERVER: listening on " + PORT + " - SERVER");\r
+               logger.info("SERVER: listening on " + PORT + " - SERVER");\r
                \r
                // Loop forever, accepting connectons from other clients\r
-               // TODO: terminate the server when haltServer is called (fails tests currently) \r
-    while (enabled)\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.info("SERVER: connection detected");\r
+                               logger.info("SERVER: connection detected");\r
                                \r
                                manager.addEndPoint(socket);\r
                        }\r
                        catch (IOException e) {}\r
                }\r
-    running=false;\r
-    manager.haltManager();\r
-    \r
+       }\r
+       \r
+       void terminate()\r
+       {\r
+               logger.info("Server shutting down...");\r
+               \r
+               try { serverSocket.close(); }\r
+               catch (Exception e)\r
+               {\r
+                       logger.error(e);\r
+               }\r
        }\r
 }
\ No newline at end of file
index 5df3c43..ad12a71 100644 (file)
@@ -26,6 +26,8 @@ public class SocketManager implements IPickManager
        \r
        private IMessageHandler msgHandler;\r
        \r
+       private boolean isRunning = true;\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
@@ -92,13 +94,18 @@ public class SocketManager implements IPickManager
         */\r
        private void forwardMessage(PickEndPoint origin, Message message)\r
        {\r
-               ListIterator itor = clients.listIterator();\r
-               while (itor.hasNext())\r
+               for (int i = clients.size()-1; i >= 0; i--)\r
                {\r
-                       PickEndPoint client = (PickEndPoint) itor.next();\r
-                       \r
-                       if (client != origin)\r
-                               client.send(message);\r
+                       try\r
+                       {\r
+                               PickEndPoint client = (PickEndPoint) clients.get(i);\r
+                               if (client != origin)\r
+                                       client.send(message);\r
+                       }\r
+                       catch (Exception e)\r
+                       {\r
+                               System.out.println("FORWARD: " + e);\r
+                       }\r
                }\r
        }\r
        \r
@@ -130,8 +137,8 @@ public class SocketManager implements IPickManager
                //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
-               if (clients.size() == 0)\r
+               // need to reinitialize - but only if we've not been told to stop\r
+               if (clients.size() == 0 && isRunning)\r
                        new InitializeThread().start();\r
        }\r
        \r
@@ -142,7 +149,7 @@ public class SocketManager implements IPickManager
        {\r
                public void run()\r
                {\r
-                       //logger.info("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
@@ -163,17 +170,18 @@ public class SocketManager implements IPickManager
                        }\r
                }\r
        }\r
-  public void haltManager() {\r
-    // TODO: FIX this method\r
-    if (server==null)\r
-      throw new Error("Client Implementation Error: haltManager called on uninitialized SocketManager.");\r
-    logger.debug("Halting PickManager threads...");\r
-    while (clients.size()>0) {\r
-      ((PickEndPoint)clients.getFirst()).haltEndpoint();\r
-    }\r
-    server.haltServer();\r
-    \r
-    logger.debug("Halted PickManager threads.");\r
-    \r
-  }\r
+       \r
+       public void shutdown()\r
+       {\r
+               if (server == null)\r
+                       throw new Error("Client Implementation Error: shutdown() called on uninitialized SocketManager.");\r
+               \r
+               isRunning = false;\r
+               \r
+               if (server.isServer())\r
+                       server.terminate();\r
+\r
+               while (clients.size() > 0)\r
+                       ((PickEndPoint)clients.getFirst()).terminate();\r
+       }\r
 }
\ No newline at end of file
index 50b338a..d7f3d35 100644 (file)
@@ -20,7 +20,7 @@ public class TestApp implements IMessageHandler
                \r
                while (true)\r
                {                       \r
-                       try { Thread.sleep((int) (Math.random()*20000)); }\r
+                       try { Thread.sleep((int) (Math.random()*5000)); }\r
                        catch (InterruptedException e) {}\r
                        \r
                        int rnd = (int) (Math.random()*100);\r
@@ -35,6 +35,6 @@ public class TestApp implements IMessageHandler
        \r
        public void handleMessage(Message message)\r
        {\r
-//             System.out.println("Handler received " + message.getRawMessage());\r
+               System.out.println("Handler received " + message.getRawMessage());\r
        }\r
 }
\ No newline at end of file
index 677094c..5ec75e8 100644 (file)
@@ -211,7 +211,7 @@ public class SimpleClient implements IClient {
       new Thread() {
         public void run() {
           SimpleClient.log.debug("Stopping pickManager..");
-          dying.pickmanager.haltPickManager();
+          dying.pickmanager.shutdown();
           SimpleClient.log.debug("pickManager halted.");
         }
       }.start();
index 8ac5516..376662c 100644 (file)
@@ -72,9 +72,8 @@ public class SimplePickManager implements IPickManager {
   public void setPassThru(boolean passThru) {\r
     this.passThru = passThru;\r
   }\r
-  public void haltPickManager() {\r
-      // TODO: FIX haltPickManager to cleanly end after SimpleClient.finalize() is called\r
-      manager.haltManager();\r
-      \r
+  \r
+  public void shutdown() {\r
+       manager.shutdown();\r
   }\r
 }\r
index 328495b..0a44380 100644 (file)
@@ -18,221 +18,311 @@ import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.IOException;
 import java.util.Vector;
+
 /**
- * Toy vamsas command line client application demonstrating the API.
- * TODO: test appData get/set methods
- * TODO: verify and test pickManager and interaction between it and other session events
- * TODO: add more session interaction events (currently: modifies document on start up, then modifies every 2 updates before finalizing after 5 updates.
+ * Toy vamsas command line client application demonstrating the API. TODO: test
+ * appData get/set methods TODO: verify and test pickManager and interaction
+ * between it and other session events TODO: add more session interaction events
+ * (currently: modifies document on start up, then modifies every 2 updates
+ * before finalizing after 5 updates.
+ * 
  * @author jimp
  */
 
-public class ExampleApplication {
-  private static ClientHandle app;
-  private static UserHandle user; // TODO: make this something defined by the api
-  private static IClientFactory clientfactory;
-  private static IClient vorbaclient;
-  private static byte[] mydata;
-  private static Vector vamsasObjects;
-  private static boolean isUpdated = false;
-  private static boolean isShuttingdown = false;
-  private static boolean isFinalizing = false;
-  private static void processVamsasDocument(IClientDocument doc) {
-    doc.addVamsasRoot(Core.getDemoVamsas());
-    vorbaclient.updateDocument(doc);
-    // merge vamsasObjects with vamsas objects in document
-    // get this apps 'mydata' if it hasn't got it already.
-    // .. access this application's 'public' mydata' if there is any.
-  }
-  private static void addHandlers(IClient avorbaclient) {
-    // make a non-volatile reference to the client instance.
-    final IClient vorbaclient = avorbaclient;
-    // register update handler
-    vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() {
-      public void propertyChange(PropertyChangeEvent evt) {
-        System.out.println("Vamsas document update for "+evt.getPropertyName()
-            +": "+evt.getOldValue()+" to "+evt.getNewValue());
-        // merge new data into ours.
-        // example - output doc
-        try {
-          IClientDocument cdoc = vorbaclient.getClientDocument();
-          uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport(cdoc.getVamsasRoots(), true, System.out);
-          vorbaclient.updateDocument(cdoc);
-        } catch (Exception e) {
-          System.err.println("Exception whilst dumping document tree after an update.");
-          e.printStackTrace(System.err);
-        }
-        isUpdated=true; // tell main thread to reflect change...
-      }
-    });
-    // register close handler
-    vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE, 
-        new PropertyChangeListener() {
-       public void propertyChange(PropertyChangeEvent evt) {
-         System.out.println("Received request to close vamsas document.");
-         // ask user for a filename to save it to. 
-         // Then pass it to the vorba object...
-         vorbaclient.storeDocument(new java.io.File("UserLocation"));
-       }
-    });
-    
-    // register some more handlers to monitor the session :
-    
-    vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION, 
-        new PropertyChangeListener() {
-      public void propertyChange(PropertyChangeEvent evt) {
-        System.out.println("New Vamsas client for "+evt.getPropertyName()
-            +": "+evt.getOldValue()+" to "+evt.getNewValue());
-        // tell app add new client to its list of clients.
-      }
-    });
-    vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION, 
-        new PropertyChangeListener() {
-      public void propertyChange(PropertyChangeEvent evt) {
-        System.out.println("Vamsas client finalizing for "+evt.getPropertyName()
-            +": "+evt.getOldValue()+" to "+evt.getNewValue());
-        // tell app to update its list of clients to communicate with.
-      }
-    });
-    vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN, 
-        new PropertyChangeListener() {
-      public void propertyChange(PropertyChangeEvent evt) {
-        System.out.println("Session "+evt.getPropertyName()+" is shutting down.");
-        // tell app to finalize its session data before shutdown.
-      }
-    });
-    vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA, 
-        new PropertyChangeListener() {
-      public void propertyChange(PropertyChangeEvent evt) {
-        System.out.println("Application received a DOCUMENT_FINALIZEAPPDATA event.");
-        // tell app to finalize its session data prior to the storage of the current session as an archive.
-      }
-    });
-    
-  }
-  public static String 
-       Usage="ExampleApplication [session urn] watch/n( future usage is :/n <vamsasFileDirectory> <vamsasSessionURN> <action> [+<arguments>]\n"
-         +"<action> is one of :\n\tsave,update,close,watch";
-  static String sess=null;
-  private static boolean parseArgs(String args[]) {
-    if (args.length==0) {
-      return false;
-    }
-    if (!args[0].toLowerCase().equals("watch")) {
-      sess=args[0];
-    }
-    return true;
-  }
-  public static void main(String[] args) {
-    class ExamplePicker implements Runnable {
-      String me=null;
-      public IPickManager pm = null;
-      ExamplePicker(String me,IPickManager pm) {
-        this.me = me;
-        this.pm = pm;
-      }
-      public void run() {
-        int mcount=1;
-        while (pm!=null) {
-          try { Thread.sleep(1000+(long) Math.random()*10000); }
-          catch (Exception e){ };
-          if (pm!=null)
-          {
-            pm.sendMessage(new uk.ac.vamsas.client.picking.CustomMessage("Message "+mcount+++" from "+me));
-          }
-        }
-      }
-        
-    };
-
-    if (!parseArgs(args)) {
-      System.err.print(Usage);
-    }
-    // get IClientFactory
-    try {
-      clientfactory = new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
-    } catch (IOException e) {
-      System.err.println(e+"\n"+Usage);
-      System.exit(1);
-    }
-    
-    // get an Iclient with session data
-    app = new ClientHandle("uk.ac.vamsas.test.ExampleApplication","0.1");
-    user = new UserHandle("arnolduser","deathsdoor");
-    try {
-      vorbaclient = clientfactory.getIClient(app, user);
-    } catch (NoDefaultSessionException e) {
-      System.err.println("There appear to be several sessions to choose from :");
-      String[] sessions = clientfactory.getCurrentSessions();
-      for (int s=0;s<sessions.length; s++)
-        System.err.println(sessions[s]);
-      System.exit(2);
-    }
-    addHandlers(vorbaclient);
-    try {
-      vorbaclient.joinSession();
-    }
-    catch (Exception se) {
-      se.printStackTrace();
-      System.err.println(se+" when joining session.\n"+Usage);
-      System.exit(1);
-    }
-    // register an update listener and a close listener.
-    // get document data
-    try {
-      IClientDocument cdoc = vorbaclient.getClientDocument();
-      processVamsasDocument(cdoc);
-    } catch (Exception e) {
-      System.err.println("Unexpected exception when retrieving the client document for the first time!");
-      e.printStackTrace(System.err);
-      System.exit(1);
-    }
-    int update=0;
-    ExamplePicker picker = new ExamplePicker(vorbaclient.getClientHandle().getClientUrn(),vorbaclient.getPickManager());
-    Thread pickthread = new Thread(picker);
-    pickthread.start();
-    picker.pm.registerMessageHandler(new IMessageHandler() {
-
-      public void handleMessage(Message message) {
-        System.out.println("Received |"+message.getRawMessage()+"|");
-      }
-      
-    });
-    while (!isShuttingdown && update<5) {
-      // do something with data
-      // , update document, or something.
-      // ..
-      if (isUpdated) {
-        System.out.println("Update handler called "+(++update)+" times");
-        System.out.println("******************************************");
-        isUpdated=false; // TODO: saner update det method.
-        if (update % 2==1) {
-          try {
-            IClientDocument cdoc = vorbaclient.getClientDocument();
-            processVamsasDocument(cdoc);
-          }
-          catch (Exception e) {
-            System.err.println("Error when updating document after an even numbered update.");
-            e.printStackTrace(System.err);
-          }
-        }
-      }
-      try { Thread.sleep(15); } catch (Exception e) {};
-    }
-    System.out.println("Shutting down picker.");
-    picker.pm=null;
-    while (pickthread.isAlive()) {
-      System.out.println("Waiting for picker to die...");
-      try { Thread.sleep(1000); 
-      } catch (Exception e) {};
-    }
-  
-    System.out.println("Finalizing.");
-      // call finalizeClient
-    vorbaclient.finalizeClient();
-    // { meanwhile, eventHandlers are called to do any saves if need be }
-    // and all registered listeners will be deregistered to avoid deadlock.
-    
-    // finish
-  }
-  
+public class ExampleApplication
+{
+       private static ClientHandle app;
+
+       private static UserHandle user; // TODO: make this something defined by the
+                                                                       // api
+
+       private static IClientFactory clientfactory;
+
+       private static IClient vorbaclient;
+
+       private static byte[] mydata;
+
+       private static Vector vamsasObjects;
+
+       private static boolean isUpdated = false;
+
+       private static boolean isShuttingdown = false;
+
+       private static boolean isFinalizing = false;
+
+       private static void processVamsasDocument(IClientDocument doc)
+       {
+               doc.addVamsasRoot(Core.getDemoVamsas());
+               vorbaclient.updateDocument(doc);
+               // merge vamsasObjects with vamsas objects in document
+               // get this apps 'mydata' if it hasn't got it already.
+               // .. access this application's 'public' mydata' if there is any.
+       }
+
+       private static void addHandlers(IClient avorbaclient)
+       {
+               // make a non-volatile reference to the client instance.
+               final IClient vorbaclient = avorbaclient;
+               // register update handler
+               vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() {
+                       public void propertyChange(PropertyChangeEvent evt)
+                       {
+                               System.out.println("Vamsas document update for "
+                                               + evt.getPropertyName() + ": " + evt.getOldValue()
+                                               + " to " + evt.getNewValue());
+                               // merge new data into ours.
+                               // example - output doc
+                               try
+                               {
+                                       IClientDocument cdoc = vorbaclient.getClientDocument();
+                                       uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport(
+                                                       cdoc.getVamsasRoots(), true, System.out);
+                                       vorbaclient.updateDocument(cdoc);
+                               }
+                               catch (Exception e)
+                               {
+                                       System.err
+                                                       .println("Exception whilst dumping document tree after an update.");
+                                       e.printStackTrace(System.err);
+                               }
+                               isUpdated = true; // tell main thread to reflect change...
+                       }
+               });
+               // register close handler
+               vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE,
+                               new PropertyChangeListener() {
+                                       public void propertyChange(PropertyChangeEvent evt)
+                                       {
+                                               System.out
+                                                               .println("Received request to close vamsas document.");
+                                               // ask user for a filename to save it to.
+                                               // Then pass it to the vorba object...
+                                               vorbaclient.storeDocument(new java.io.File(
+                                                               "UserLocation"));
+                                       }
+                               });
+
+               // register some more handlers to monitor the session :
+
+               vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION,
+                               new PropertyChangeListener() {
+                                       public void propertyChange(PropertyChangeEvent evt)
+                                       {
+                                               System.out.println("New Vamsas client for "
+                                                               + evt.getPropertyName() + ": "
+                                                               + evt.getOldValue() + " to "
+                                                               + evt.getNewValue());
+                                               // tell app add new client to its list of clients.
+                                       }
+                               });
+               vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION,
+                               new PropertyChangeListener() {
+                                       public void propertyChange(PropertyChangeEvent evt)
+                                       {
+                                               System.out.println("Vamsas client finalizing for "
+                                                               + evt.getPropertyName() + ": "
+                                                               + evt.getOldValue() + " to "
+                                                               + evt.getNewValue());
+                                               // tell app to update its list of clients to communicate
+                                               // with.
+                                       }
+                               });
+               vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN,
+                               new PropertyChangeListener() {
+                                       public void propertyChange(PropertyChangeEvent evt)
+                                       {
+                                               System.out.println("Session " + evt.getPropertyName()
+                                                               + " is shutting down.");
+                                               // tell app to finalize its session data before
+                                               // shutdown.
+                                       }
+                               });
+               vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA,
+                               new PropertyChangeListener() {
+                                       public void propertyChange(PropertyChangeEvent evt)
+                                       {
+                                               System.out
+                                                               .println("Application received a DOCUMENT_FINALIZEAPPDATA event.");
+                                               // tell app to finalize its session data prior to the
+                                               // storage of the current session as an archive.
+                                       }
+                               });
+
+       }
+
+       public static String Usage = "ExampleApplication [session urn] watch/n( future usage is :/n <vamsasFileDirectory> <vamsasSessionURN> <action> [+<arguments>]\n"
+                       + "<action> is one of :\n\tsave,update,close,watch";
+
+       static String sess = null;
+
+       private static boolean parseArgs(String args[])
+       {
+               if (args.length == 0)
+               {
+                       return false;
+               }
+               if (!args[0].toLowerCase().equals("watch"))
+               {
+                       sess = args[0];
+               }
+               return true;
+       }
+
+       public static void main(String[] args)
+       {
+               class ExamplePicker extends Thread
+               {
+                       String me = null;
+
+                       public IPickManager pm = null;
+
+                       ExamplePicker(String me, IPickManager pm)
+                       {
+                               this.me = me;
+                               this.pm = pm;
+                       }
+
+                       public void run()
+                       {
+                               int mcount = 1;
+                               while (pm != null)
+                               {
+                                       try { Thread.sleep(1000 + (long) Math.random() * 10000); }
+                                       catch (Exception e) {}
+                                       
+                                       if (pm != null)
+                                       {
+                                               pm.sendMessage(new uk.ac.vamsas.client.picking.CustomMessage("Message " + mcount++ + " from " + me));
+                                       }
+                               }
+                       }
+
+               }
+
+               if (!parseArgs(args))
+               {
+                       System.err.print(Usage);
+               }
+               // get IClientFactory
+               try
+               {
+                       clientfactory = new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
+               }
+               catch (IOException e)
+               {
+                       System.err.println(e + "\n" + Usage);
+                       System.exit(1);
+               }
+
+               // get an Iclient with session data
+               app = new ClientHandle("uk.ac.vamsas.test.ExampleApplication", "0.1");
+               user = new UserHandle("arnolduser", "deathsdoor");
+               try
+               {
+                       vorbaclient = clientfactory.getIClient(app, user);
+               }
+               catch (NoDefaultSessionException e)
+               {
+                       System.err
+                                       .println("There appear to be several sessions to choose from :");
+                       String[] sessions = clientfactory.getCurrentSessions();
+                       for (int s = 0; s < sessions.length; s++)
+                               System.err.println(sessions[s]);
+                       System.exit(2);
+               }
+               addHandlers(vorbaclient);
+               try
+               {
+                       vorbaclient.joinSession();
+               }
+               catch (Exception se)
+               {
+                       se.printStackTrace();
+                       System.err.println(se + " when joining session.\n" + Usage);
+                       System.exit(1);
+               }
+               // register an update listener and a close listener.
+               // get document data
+               try
+               {
+                       IClientDocument cdoc = vorbaclient.getClientDocument();
+                       processVamsasDocument(cdoc);
+               }
+               catch (Exception e)
+               {
+                       System.err
+                                       .println("Unexpected exception when retrieving the client document for the first time!");
+                       e.printStackTrace(System.err);
+                       System.exit(1);
+               }
+               int update = 0;
+               ExamplePicker picker = new ExamplePicker(vorbaclient.getClientHandle()
+                               .getClientUrn(), vorbaclient.getPickManager());
+               
+               picker.start();
+               picker.pm.registerMessageHandler(new IMessageHandler() {
+
+                       public void handleMessage(Message message)
+                       {
+                               System.out
+                                               .println("Received |" + message.getRawMessage() + "|");
+                       }
+
+               });
+               while (!isShuttingdown && update < 5)
+               {
+                       // do something with data
+                       // , update document, or something.
+                       // ..
+                       if (isUpdated)
+                       {
+                               System.out.println("Update handler called " + (++update)
+                                               + " times");
+                               System.out
+                                               .println("******************************************");
+                               isUpdated = false; // TODO: saner update det method.
+                               if (update % 2 == 1)
+                               {
+                                       try
+                                       {
+                                               IClientDocument cdoc = vorbaclient.getClientDocument();
+                                               processVamsasDocument(cdoc);
+                                       }
+                                       catch (Exception e)
+                                       {
+                                               System.err
+                                                               .println("Error when updating document after an even numbered update.");
+                                               e.printStackTrace(System.err);
+                                       }
+                               }
+                       }
+                       
+                       try     { Thread.sleep(15); }
+                       catch (Exception e) {}
+
+               }
+               System.out.println("Shutting down picker.");
+               picker.pm = null;
+               while (picker.isAlive())
+               {
+                       System.out.println("Waiting for picker to die...");
+                       try
+                       {
+                               Thread.sleep(1000);
+                       }
+                       catch (Exception e)
+                       {
+                       }
+                       ;
+               }
+
+               System.out.println("Finalizing.");
+               // call finalizeClient
+               vorbaclient.finalizeClient();
+               // { meanwhile, eventHandlers are called to do any saves if need be }
+               // and all registered listeners will be deregistered to avoid deadlock.
+
+               // finish
+       }
+
 }