From b4dc48a6b8be7fa6628bc61599b4678030c4084e Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 17 Aug 2007 14:41:01 +0000 Subject: [PATCH] safety checks and informational Errors generated when IClientDocument is not stored at end of handling an update. Attempts to properly close all session file handles on finalization (Clients.obj.lck still locked and VamDoc.jar still locked after finalize though). git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@434 be28352e-c001-0410-b1a7-c7978e42abec --- .../client/simpleclient/EventGeneratorThread.java | 44 +++++++++++- .../vamsas/client/simpleclient/SimpleClient.java | 70 +++++++++++++------- .../vamsas/client/simpleclient/VamsasSession.java | 47 +++++-------- 3 files changed, 106 insertions(+), 55 deletions(-) diff --git a/src/uk/ac/vamsas/client/simpleclient/EventGeneratorThread.java b/src/uk/ac/vamsas/client/simpleclient/EventGeneratorThread.java index 311c825..4a0b1fb 100644 --- a/src/uk/ac/vamsas/client/simpleclient/EventGeneratorThread.java +++ b/src/uk/ac/vamsas/client/simpleclient/EventGeneratorThread.java @@ -83,7 +83,15 @@ public class EventGeneratorThread { */ log.debug("Watchers inited."); } - void _raise(String handlerEvent, String property, Object oldval, Object newval) { + /** + * Call registered handlers for a vamsas session event + * @param handlerEvent a named event + * @param property property name to pass to handler + * @param oldval old value of property to pass + * @param newval new value of property to pass + * @return true if event generation did not raise any exceptions. + */ + boolean _raise(String handlerEvent, String property, Object oldval, Object newval) { PropertyChangeSupport h = (PropertyChangeSupport) handlers.get(handlerEvent); if (h!=null) { log.debug("Triggering:"+handlerEvent); @@ -91,10 +99,17 @@ public class EventGeneratorThread { h.firePropertyChange(property, oldval, newval); } catch (Exception e) { log.warn("Client Exception during handling of "+handlerEvent, e); + return false; + } + catch (Error e) + { + log.error("Serious! Client Error during handling of "+handlerEvent, e); + return false; } log.debug("Finished :"+handlerEvent); } else log.debug("No handlers for raised "+handlerEvent); + return true; } protected boolean storeDocRequest(Lock lock) { if (log.isDebugEnabled()) @@ -115,13 +130,38 @@ public class EventGeneratorThread { session.vamArchive.fileLock=doclock; if (client.pickmanager!=null) client.pickmanager.setPassThru(false); + if (log.isDebugEnabled()) { + log.debug("Initiating a documentChanged event. Document is "+(client.cdocument==null ? "closed" : "open")); + } // TODO: decide if individual object update handlers are called as well as overall event handler - _raise(Events.DOCUMENT_UPDATE, client.getSessionUrn(), null, client); + if (!_raise(Events.DOCUMENT_UPDATE, client.getSessionUrn(), null, client)) + { + log.info("Recovering from errors or exceptions generated by client application"); + if (client.cdocument!=null) + { + try { + client.tidyAwaySessionDocumentState(); + } + catch (Exception e) + { + log.warn("Exception generated by vamsas library - when tidying away session document:",e); + } + catch (Error e) + { + log.error("LIBRARY Implementation error - when tidying away session document:",e); + } + } + + } if (client.pickmanager!=null) client.pickmanager.setPassThru(true); if (log.isDebugEnabled()) { log.debug("Finished handling a documentChanged event. Document is "+(client.cdocument==null ? "closed" : "open")); } + if (client.cdocument!=null) + { + log.warn("Implementation Error ? ClientDocument instance has not been closed or updated by handler!"); + } /*try { client._session.getVamsasDocument().closeArchive(); } catch (Exception e) {log.warn("Unexpected exception when closing document after update.",e);}; diff --git a/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java b/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java index fccfba7..8e8fba2 100644 --- a/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java +++ b/src/uk/ac/vamsas/client/simpleclient/SimpleClient.java @@ -313,32 +313,23 @@ public class SimpleClient implements IClient { throw new Error("Client Error - updateDocument() called before getClientDocument() on this SimpleClient instance."); if (newdoc!=cdocument) throw new Error("Client Error - SimpleClient.updateDocument() can only take the IClientDocument instance returned from SimpleClient.getClientDocument()"); - + if (evgen.isDocumentWatchEnabled()) - throw new Error("Client Error - or Library Bug : Document watcher still enabled whilst ClientDocument instance exists."); + throw new Error("Probable Client Error (did you remember to call SimpleClient.updateDocument(clientdoc) at the end of the document update handler?) - or Library Bug : Document watcher still enabled whilst ClientDocument instance exists."); if (!cdocument.isModified()) { // client document is silently got rid of, with no session update events. if (log.isDebugEnabled()) log.debug("updateDocument for "+session.getSessionUrn()+" with unmodified IClientDocument (skipping the write)"); } else { - try { - boolean updated=cdocument.updateSessionDocument(); - if (!updated) { - log.warn("Session document did not update properly for session directory "+_session.sessionDir); - // cdocument.archive.cancelArchive(); // LATER: could be done - would need to prevent updateSessionDocument closing the iohandler. - _session.slog.warn("Session Document updated but may not be valid (false return from org.vamsas.simpleclient.ClientDocument.updateSessionDocument()"); - } else { - log.debug("Document update successful."); - } - _session.setUnsavedFlag(); - } - catch (IOException e) { - log.warn("IO Problems when updating document!",e); - _session.slog.error("IO problems when attempting to update document."); - } + writeSessionDocument(); } - // garbage collect the ClientDocument instance. + tidyAwaySessionDocumentState(); + } + /** + * garbage collect the ClientDocument instance and re-enable watchers. + */ + protected void tidyAwaySessionDocumentState() { try { log.debug("Finalizing ClientDocument instance."); cdocument.finalize(); @@ -355,7 +346,28 @@ public class SimpleClient implements IClient { _session.slog.error("IO problems when attempting to release lock on session document."); } } - + + /** + * write the cdocument instance to the session for real. + */ + private void writeSessionDocument() { + try { + boolean updated=cdocument.updateSessionDocument(); + if (!updated) { + log.warn("Session document did not update properly for session directory "+_session.sessionDir); + // cdocument.archive.cancelArchive(); // LATER: could be done - would need to prevent updateSessionDocument closing the iohandler. + _session.slog.warn("Session Document updated but may not be valid (false return from org.vamsas.simpleclient.ClientDocument.updateSessionDocument()"); + } else { + log.debug("Document update successful."); + } + _session.setUnsavedFlag(); + } + catch (IOException e) { + log.warn("IO Problems when updating document!",e); + _session.slog.error("IO problems when attempting to update document."); + } + } + /* * (non-Javadoc) * @@ -511,23 +523,27 @@ public class SimpleClient implements IClient { protected void releaseActiveClientFile() throws IOException { - log.debug("Releasing active client file"); + log.debug("Releasing active client locks"); if( activeClientFilelock != null) {// Release the lock + log.debug("Releasing lock on active client lock file"); activeClientFilelock.release(); + log.debug("ReleaseActiveClientFile called when client has no lock on its clientLockFile"); activeClientFilelock = null; } else { log.debug("ReleaseActiveClientFile called when client has no lock on its clientLockFile"); } if (this.clientlockFile != null) { + log.debug("trying to delete active client lock file"); if (this.clientlockFile.exists()) - this.clientlockFile.delete(); - log.debug("deleted active client lock file"); + { + this.clientlockFile.delete(); + log.debug("deleted active client lock file"); + } } else { log.debug("ReleaseActiveClientFile called when client has no clientLockFile"); } - } protected void createActiveClientFile() throws IOException @@ -566,4 +582,12 @@ public class SimpleClient implements IClient { protected File getClientlockFile() { return clientlockFile; } + /** + * + * @return the lock for the client in the session + */ + protected Lock getClientLock() { + return activeClientFilelock; + } + } diff --git a/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java b/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java index b24ef68..2ae181d 100644 --- a/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java +++ b/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java @@ -486,52 +486,38 @@ public class VamsasSession { client.evgen.stopWatching(); cwe.setHandler(null); -// ask to the client to copy application data into the document + // ask to the client to copy application data into the document client.evgen._raise(Events.DOCUMENT_FINALIZEAPPDATA, null, client,null); - - if ( this.isLastActiveClient(client)) - { + boolean closeSession=isLastActiveClient(client); + if (closeSession) + { log.debug("Raising request-to-save event"); client.evgen._raise(Events.DOCUMENT_REQUESTTOCLOSE, null, client, null); - //client.evgen._raise(Events.SESSION_SHUTDOWN, null, client.getSessionHandle(), null); - log.debug("Last active client: closing session"); - log.info("Closing session"); - getSessionManager().removeSession(client.getSessionHandle()); - } - + client.evgen._raise(Events.SESSION_SHUTDOWN, null, client.getSessionHandle(), null); + } try { - log.debug("Releasing active client file"); + log.debug("Attempting to release active client locks"); client.releaseActiveClientFile(); } catch (IOException e) { log.error("error during active file client release"); } - } - - - - /*clist.removeClient(client.getClientHandle(),null); - if (this.clist.retrieveClientList() == null|| this.clist.retrieveClientList().length<1) - {//assume it is the last client has been removed shutting down session - slog.info("last client removed: removing session"); - log.debug("last client removed: removing session"); - this.getSessionManager().removeSession(client.getSessionHandle()); - } - else + if (closeSession) { - int active=clist.retrieveClientList().length; - log.debug("Still "+active+" active clients"); - slog.info("Still "+active+" active clients"); - }*/ - + log.debug("Last active client: closing session"); + log.info("Closing session"); + getSessionManager().removeSession(client.getSessionHandle()); + } + } } private boolean isLastActiveClient(SimpleClient client) { log.debug("Testing if current client is the last one."); + log.debug("current client lockfile is '"+client.getClientlockFile()+"'"); boolean noOtherActiveClient = true; //create, if need, subdirectory to contain client files File clientlockFileDir = new File (this.sessionDir, clientFileDirectory); @@ -554,7 +540,7 @@ public class VamsasSession { { File clientFile = clientFiles[i]; log.debug("testing file for lock: "+clientFile.getAbsolutePath()); - if(client.getClientlockFile().equals(clientFile)) + if(client.getClientLock().isTargetLockFile(clientFile)) { log.debug("current client file found"); continue; @@ -693,6 +679,7 @@ public class VamsasSession { } log.debug("Stopping EventGenerator.."); + // TODO: ensure ClientsFile lock is really released!! clist.unlockFile(); client.evgen.stopWatching(); } watcher.setHandler(null);//Do not check if the client is the last client. watcher will shutdown anyway @@ -712,7 +699,7 @@ public class VamsasSession { // close document client.evgen._raise(Events.DOCUMENT_REQUESTTOCLOSE, null, client,null); log.debug("close document request done"); - this.closeSession(client.getSessionHandle()); + closeSession(client.getSessionHandle()); } /** -- 1.7.10.2