From f900bd84927e08acb2c47527da9cc4efe3a2b968 Mon Sep 17 00:00:00 2001 From: imilne Date: Wed, 7 Mar 2007 11:09:07 +0000 Subject: [PATCH] Added shutdown() methods for the socket-based PickManager code. 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 | 6 + src/uk/ac/vamsas/client/picking/PickEndPoint.java | 62 +-- src/uk/ac/vamsas/client/picking/PickServer.java | 55 +-- src/uk/ac/vamsas/client/picking/SocketManager.java | 52 +- src/uk/ac/vamsas/client/picking/TestApp.java | 4 +- .../vamsas/client/simpleclient/SimpleClient.java | 2 +- .../client/simpleclient/SimplePickManager.java | 7 +- src/uk/ac/vamsas/test/ExampleApplication.java | 516 ++++++++++++-------- 8 files changed, 375 insertions(+), 329 deletions(-) diff --git a/src/uk/ac/vamsas/client/picking/IPickManager.java b/src/uk/ac/vamsas/client/picking/IPickManager.java index 6c9615d..a91802d 100644 --- a/src/uk/ac/vamsas/client/picking/IPickManager.java +++ b/src/uk/ac/vamsas/client/picking/IPickManager.java @@ -17,4 +17,10 @@ public interface IPickManager * @param handler the message handler to register */ public void registerMessageHandler(IMessageHandler handler); + + /** + * Shutsdown the pick manager processes, terminating any connections to + * other clients. + */ + public void shutdown(); } \ No newline at end of file diff --git a/src/uk/ac/vamsas/client/picking/PickEndPoint.java b/src/uk/ac/vamsas/client/picking/PickEndPoint.java index 1864874..8191a80 100644 --- a/src/uk/ac/vamsas/client/picking/PickEndPoint.java +++ b/src/uk/ac/vamsas/client/picking/PickEndPoint.java @@ -39,15 +39,15 @@ class PickEndPoint extends Thread in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // Start the thread to listen for incoming messages -// logger.info("CLIENT: connection successful to port " -// + socket.getPort() + " via port " + socket.getLocalPort()); + logger.info("CLIENT: connection successful to port " + + socket.getPort() + " via port " + socket.getLocalPort()); start(); return true; } catch (Exception e) { - //logger.info("CLIENT: connection failed: " + e); + logger.info("CLIENT: connection failed: " + e); return false; } } @@ -73,40 +73,13 @@ class PickEndPoint extends Thread terminate(); } } - /** - * state of server thread - running or not running - */ - private boolean running=false; - /** - * condition for server thread to stop - */ - private boolean enabled=true; - public void haltEndpoint() { - // TODO: FIX THIS METHOD - if (!running || !enabled) { - logger.debug("PickEndpoint is not running or already requested to halt."); - return; - } - logger.debug("Disabling pick endpoint."); - enabled=false; - terminate(); - while (running) { - try { - Thread.sleep(1); - } catch (Exception e) { - } - } - logger.debug("Pick endpoint has stopped."); - } - + // void receive() (threaded) public void run() { - enabled=true; - running=true; try { - while (enabled) + while (true) { String str = in.readLine(); //logger.info("CLIENT: recv " + str + " from " + rPort); @@ -114,34 +87,26 @@ class PickEndPoint extends Thread // TODO: Spawn this off into the GUI Event-Dispatch thread... // Convert the string back into something API friendly - if (str!=null) { Message message = strToMessage(str); // Ignore corrupted or unknown message types if (message != null) manager.processMessage(this, message); - } } } catch (Exception e) { - // Means the other end of the connection has (probably) died - logger.debug("Exception in receiver loop: "+e.getMessage()); - } - // terminate this endpoint (if this is server side) - //logger.info("CLIENT: read failed: " + e); - - terminate(); - - running=false; + // Means the other end of the connection has (probably died) so we need + // terminate this endpoint (if this is server side) + //logger.info("CLIENT: read failed: " + e); + + terminate(); + } } - private void terminate() + void terminate() { - try { - if (socket.isConnected()) - socket.close(); - } + try { socket.close(); } catch (IOException e) {} //logger.info("CLIENT: closing connection to port " + socket.getPort()); @@ -150,7 +115,6 @@ class PickEndPoint extends Thread private Message strToMessage(String str) { - // TODO: generalize message class try { if (str.startsWith("CUSTOM")) diff --git a/src/uk/ac/vamsas/client/picking/PickServer.java b/src/uk/ac/vamsas/client/picking/PickServer.java index ab2aaf8..a9e7c1c 100644 --- a/src/uk/ac/vamsas/client/picking/PickServer.java +++ b/src/uk/ac/vamsas/client/picking/PickServer.java @@ -57,35 +57,7 @@ class PickServer extends Thread return false; } } - /** - * state of server thread - running or not running - */ - private boolean running=false; - /** - * condition for server thread to stop - */ - private boolean enabled=true; - public void haltServer() { - // TODO: FIX THIS METHOD - if (!running || !enabled) { - logger.debug("PickServer is not running or already requested to halt."); - return; - } - logger.debug("Disabling pick server."); - enabled=false; - while (running) { - try { - serverSocket.close(); - } catch (Exception e) { - - } - try { - Thread.sleep(5); - } catch (Exception e) { - } - } - logger.debug("Pick server has stopped."); - } + /** * Thread listening method - loops indefinitely listening for connections. * When one is received, the socket object is passed to the manager so it @@ -93,25 +65,32 @@ class PickServer extends Thread */ public void run() { - enabled=true; - running=true; - //logger.info("SERVER: listening on " + PORT + " - SERVER"); + logger.info("SERVER: listening on " + PORT + " - SERVER"); // Loop forever, accepting connectons from other clients - // TODO: terminate the server when haltServer is called (fails tests currently) - while (enabled) + // TODO: add in the ability to terminate the server if a VAMSAS session + // is ended + while (true) { try { Socket socket = serverSocket.accept(); - //logger.info("SERVER: connection detected"); + logger.info("SERVER: connection detected"); manager.addEndPoint(socket); } catch (IOException e) {} } - running=false; - manager.haltManager(); - + } + + void terminate() + { + logger.info("Server shutting down..."); + + try { serverSocket.close(); } + catch (Exception e) + { + logger.error(e); + } } } \ No newline at end of file diff --git a/src/uk/ac/vamsas/client/picking/SocketManager.java b/src/uk/ac/vamsas/client/picking/SocketManager.java index 5df3c43..ad12a71 100644 --- a/src/uk/ac/vamsas/client/picking/SocketManager.java +++ b/src/uk/ac/vamsas/client/picking/SocketManager.java @@ -26,6 +26,8 @@ public class SocketManager implements IPickManager private IMessageHandler msgHandler; + private boolean isRunning = true; + /** * Constructs a new PickManager. This method will return immediately, while * a looping thread runs that attempts to run the server or connect to an @@ -92,13 +94,18 @@ public class SocketManager implements IPickManager */ private void forwardMessage(PickEndPoint origin, Message message) { - ListIterator itor = clients.listIterator(); - while (itor.hasNext()) + for (int i = clients.size()-1; i >= 0; i--) { - PickEndPoint client = (PickEndPoint) itor.next(); - - if (client != origin) - client.send(message); + try + { + PickEndPoint client = (PickEndPoint) clients.get(i); + if (client != origin) + client.send(message); + } + catch (Exception e) + { + System.out.println("FORWARD: " + e); + } } } @@ -130,8 +137,8 @@ public class SocketManager implements IPickManager //logger.info("List now contains " + clients.size() + " client(s)"); // If there's no endpoints left, then we've lost all connections and - // need to reinitialize - if (clients.size() == 0) + // need to reinitialize - but only if we've not been told to stop + if (clients.size() == 0 && isRunning) new InitializeThread().start(); } @@ -142,7 +149,7 @@ public class SocketManager implements IPickManager { public void run() { - //logger.info("Initializing connection..."); + logger.info("Initializing connection..."); boolean connected = false; // Loop until we can get a connection (one way or the other) @@ -163,17 +170,18 @@ public class SocketManager implements IPickManager } } } - public void haltManager() { - // TODO: FIX this method - if (server==null) - throw new Error("Client Implementation Error: haltManager called on uninitialized SocketManager."); - logger.debug("Halting PickManager threads..."); - while (clients.size()>0) { - ((PickEndPoint)clients.getFirst()).haltEndpoint(); - } - server.haltServer(); - - logger.debug("Halted PickManager threads."); - - } + + public void shutdown() + { + if (server == null) + throw new Error("Client Implementation Error: shutdown() called on uninitialized SocketManager."); + + isRunning = false; + + if (server.isServer()) + server.terminate(); + + while (clients.size() > 0) + ((PickEndPoint)clients.getFirst()).terminate(); + } } \ 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 index 50b338a..d7f3d35 100644 --- a/src/uk/ac/vamsas/client/picking/TestApp.java +++ b/src/uk/ac/vamsas/client/picking/TestApp.java @@ -20,7 +20,7 @@ public class TestApp implements IMessageHandler while (true) { - try { Thread.sleep((int) (Math.random()*20000)); } + try { Thread.sleep((int) (Math.random()*5000)); } catch (InterruptedException e) {} int rnd = (int) (Math.random()*100); @@ -35,6 +35,6 @@ public class TestApp implements IMessageHandler public void handleMessage(Message message) { -// System.out.println("Handler received " + message.getRawMessage()); + System.out.println("Handler received " + message.getRawMessage()); } } \ No newline at end of file diff --git a/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java b/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java index 677094c..5ec75e8 100644 --- a/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java +++ b/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java @@ -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(); diff --git a/src/uk/ac/vamsas/client/simpleclient/SimplePickManager.java b/src/uk/ac/vamsas/client/simpleclient/SimplePickManager.java index 8ac5516..376662c 100644 --- a/src/uk/ac/vamsas/client/simpleclient/SimplePickManager.java +++ b/src/uk/ac/vamsas/client/simpleclient/SimplePickManager.java @@ -72,9 +72,8 @@ public class SimplePickManager implements IPickManager { public void setPassThru(boolean passThru) { this.passThru = passThru; } - public void haltPickManager() { - // TODO: FIX haltPickManager to cleanly end after SimpleClient.finalize() is called - manager.haltManager(); - + + public void shutdown() { + manager.shutdown(); } } diff --git a/src/uk/ac/vamsas/test/ExampleApplication.java b/src/uk/ac/vamsas/test/ExampleApplication.java index 328495b..0a44380 100644 --- a/src/uk/ac/vamsas/test/ExampleApplication.java +++ b/src/uk/ac/vamsas/test/ExampleApplication.java @@ -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 [+]\n" - +" 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 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 + } + } -- 1.7.10.2