From 4af676753de2489148d92c834398ec88079bcf24 Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 12 Jan 2007 15:51:15 +0000 Subject: [PATCH] SimpleClient implementation testable against uk.ac.vamsas.test.ExampleApplication git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@341 be28352e-c001-0410-b1a7-c7978e42abec --- .../vamsas/client/simpleclient/ClientDocument.java | 91 ++++-- .../client/simpleclient/EventGeneratorThread.java | 299 +++++++++++--------- .../vamsas/client/simpleclient/SimpleClient.java | 122 +++++--- .../vamsas/client/simpleclient/VamsasSession.java | 134 +++++---- 4 files changed, 399 insertions(+), 247 deletions(-) diff --git a/src/uk/ac/vamsas/client/simpleclient/ClientDocument.java b/src/uk/ac/vamsas/client/simpleclient/ClientDocument.java index bc7a7e9..316e112 100644 --- a/src/uk/ac/vamsas/client/simpleclient/ClientDocument.java +++ b/src/uk/ac/vamsas/client/simpleclient/ClientDocument.java @@ -23,14 +23,16 @@ import uk.ac.vamsas.objects.utils.AppDataReference; import uk.ac.vamsas.test.objects.Core; /** - * Maintains a collection of vamsas objects, appdatas and states, and provides api for a SimpleClient's client. + * Maintains a collection of vamsas objects, appdatas and states, + * and provides api for a SimpleClient's client. + * TODO: test and migrate ArchiveClient.getAppData methods to here and retest in ExampleApplication * @author jimp */ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implements IClientDocument { private static Log log = LogFactory.getLog(ClientDocument.class); private VamsasDocument doc; protected SimpleClient sclient; - protected VamsasArchive archive = null; + protected VamsasArchive iohandler = null; /** * indicate if new data has been incorporated */ @@ -42,10 +44,9 @@ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implement public boolean isModified() { return isModified; } - private Vector updatedObjects=null; /** * - * prepare Application-side dataset from the vamsas Document archive + * prepare Application-side dataset from the vamsas Document iohandler * @param doc - the dataset * @param docHandler - the sessionFile IO handler * @param Factory - the source of current and new vorbaIds @@ -56,12 +57,12 @@ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implement /** - * prepare Application-side dataset from the vamsas Document archive + * prepare Application-side dataset from the vamsas Document iohandler */ this.sclient = sclient; - archive = docHandler; + iohandler = docHandler; this.doc = doc; - updatedObjects=null; /// TODO: correct this line + _VamsasRoots=doc.getVAMSAS(); } /* @@ -102,7 +103,20 @@ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implement * internal reference to single copy of Document Roots array */ private VAMSAS[] _VamsasRoots=null; - /* + + protected void updateDocumentRoots() { + if (doc==null) { + log.error("updateDocumentRoots called on null document. Probably an implementation error."); + return; + } + if (isModified) { + if (_VamsasRoots!=null) { + doc.setVAMSAS(_VamsasRoots); + _VamsasRoots=null; + } + } + } +/* * (non-Javadoc) * LATER: currently there is only one Vector of roots ever passed to client - decide if this is correct (means this is not thread safe and may behave unexpectedly) * @see uk.ac.vamsas.client.IClientDocument#getVamsasRoots() @@ -112,7 +126,7 @@ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implement log.debug("Null document for getVamsasRoots(), returning null"); return null; } - if (archive==null) { + if (iohandler==null) { // LATER: decide on read-only status of ClientDocument object log.warn("getVamsasRoots() called on possibly read-only document."); } @@ -122,6 +136,7 @@ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implement if (roots == null) { // Make a new one to return to client to get filled. _VamsasRoots = new VAMSAS[] { new VAMSAS() }; + registerObject(_VamsasRoots[0]); // Do provenance now. just in case. doc.getProvenance().addEntry(sclient.getProvenanceEntry("Created new document root [id="+_VamsasRoots[0].getId()+"]")); doc.addVAMSAS(_VamsasRoots[0]); @@ -138,9 +153,9 @@ public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implement return -1; if (docRoots==null || docRoots.length==0) return -1; - String r_id = root.getId(); + VorbaId d_id=null,r_id = root.getVorbaId(); for (int i=0,j=docRoots.length; i - * NewValue: uk.ac.vamsas.client.IClient for session. - * - public static final String DOCUMENT_FINALIZEAPPDATA = "uk.ac.vamsas.client.events.DocumentFinalizeAppData"; -*/ - // watch for finalization semaphore (last finalised sessionFile). - - /** - * Generated by Vorba stub after the penultimate client makes a call to - * closeDocument(). Sequence is as follows : 1. All other vamsas clients have - * called closeDocument() 2. Final living client monitors closures, and - * realises that it is last. 3. Final client generates event to prompt - * associated application to inquire if the user wishes to save the document - * for future reference. - * * Any call to closeDocument in a thread other than the registered - * EventListener will block until the RequestToClose handler has exited. - * - */ - // public static final String DOCUMENT_REQUESTTOCLOSE = "org.vamas.client.DocumentRequestToCloseEvent"; - - return raised; - } - - private void initEvents() { - + return true; } /** * Events raised by IClient and propagated to others in session @@ -176,7 +169,7 @@ public class EventGeneratorThread extends Thread implements Runnable { private boolean block_document_updates=false; int STORE_WAIT=5; // how many units before we decide all clients have finalized their appdatas - + private boolean in_want_to_store_phase=false; /** * client App requests offline storage of vamsas data. * Call blocks whilst other apps do any appData finalizing @@ -187,16 +180,28 @@ public class EventGeneratorThread extends Thread implements Runnable { * @param STORE_WAIT indicates how lock the call will block for when nothing appears to be happening to the session. */ protected Lock want_to_store() { - log.debug("Setting flag for document_update requests to be ignored"); - block_document_updates=true; - log.debug("Waiting for other apps to do FinalizeApp handling."); + if (in_want_to_store_phase) { + log.error("client error: want_to_store called again before first call has completed."); + return null; + } + in_want_to_store_phase=true; + // TODO: test the storeDocumentRequest mechanism + /*/ watchThread.haltWatchers(); + */ + log.debug("Stopping document_update watcher"); + vamsasfile.haltWatch(); + // block_document_updates=true; + log.debug("Cleared flag for ignoring document_update requests"); + + log.debug("Sending Store Document Request"); try { session.addStoreDocumentRequest(client.getClientHandle(), client.getUserHandle()); } catch (Exception e) { log.warn("Whilst writing StoreDocumentRequest for "+client.getClientHandle().getClientUrn()+" "+client.getUserHandle(), e); - log.info("trying to continue."); + log.info("trying to continue after storeDocumentRequest exception."); } + log.debug("Waiting for other apps to do FinalizeApp handling."); // LATER: refine this semaphore process // to make a robust signalling mechanism: // app1 requests, app1..n do something (or don't - they may be dead), @@ -204,21 +209,33 @@ public class EventGeneratorThread extends Thread implements Runnable { // this probably needs two files - a request file, // and a response file which is acknowledged by the app1 requestor for each app. // eventually, no more responses are received for the request, and the app can then only continue with its store. - int units = 0; + FileWatcher sfwatcher=session.getStoreWatcher(); + FileWatcher vfwatcher=session.getDocWatcher(); + int units = 0; // zero if updates occured over a sleep period while (units0) { - //TODO: is this application connecting to a newly created session document ? + //TODO: LATER: is this application connecting to a newly created session document ? //evgen.raise(Events.DOCUMENT_CREATE); } + } @@ -424,12 +472,20 @@ public class SimpleClient implements IClient { protected VamsasSession get_session() { return this._session; } - + SimplePickManager pickmanager=null; /* (non-Javadoc) * @see uk.ac.vamsas.client.IClient#getPickManager() */ public IPickManager getPickManager() { - // TODO Auto-generated method stub - return null; + createPickManager(); + return pickmanager; + } + + private void createPickManager() { + if (pickmanager==null){ + // TODO: Construct PickManager for session using details from sessionURN! + log.debug("Creating PickManager (not from sessionURN yet)"); + pickmanager = new SimplePickManager(new uk.ac.vamsas.client.picking.SocketManager()); + } } } diff --git a/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java b/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java index 1c77d66..c849893 100644 --- a/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java +++ b/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java @@ -1,18 +1,19 @@ package uk.ac.vamsas.client.simpleclient; -import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.io.Writer; +import java.util.Enumeration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.Appender; import org.apache.log4j.Logger; import org.apache.log4j.FileAppender; +import org.apache.log4j.PatternLayout; import uk.ac.vamsas.client.ClientHandle; import uk.ac.vamsas.client.IClient; @@ -119,22 +120,22 @@ public class VamsasSession { * @throws IOException */ private void initLog() throws IOException { + // TODO: fix session event logging // LATER: make dedicated appender format for session log. - Appender app = slog.getAppender("SESSION_LOG"); - // slog.addAppender(new FileAppender(app.getLayout(), new File(sessionDir, SESSION_LOG).getAbsolutePath())); - - //Appender app = slog.getAppender("SESSION_LOG"); - if (app == null) log.info("No appender for SESSION_LOG"); + /*Appender app = slog.getAppender("log4j.appender.SESSIONLOG"); + // slog.addAppender(new FileAppender(app.getLayout(), new File(sessionDir, SESSION_LOG).getAbsolutePath())); + // slog.addAppender(new FileAppender(app.getLayout(), new File(sessionDir, SESSION_LOG).getAbsolutePath())); + for (Enumeration e = slog.getAllAppenders() ; e.hasMoreElements() ;) { + System.out.println(e.nextElement()); + + }*/ - if (slog!= null && app != null) - { - if (app instanceof FileAppender) - { - File sessionLogFile = new File(this.sessionDir, ((FileAppender)app).getFile()); - slog.addAppender(new FileAppender(app.getLayout(), sessionLogFile.getAbsolutePath())); - } - // slog.removeAppender("SESSION_LOG"); - } + if (slog!= null ) { + File sessionLogFile = new File(this.sessionDir, SESSION_LOG); + slog.addAppender(new FileAppender(new PatternLayout("%-4r [%t] %-5p %c %x - %m%n"), sessionLogFile.getAbsolutePath(), true)); + } else { + log.info("No appender for SessionLog"); + } } /** @@ -162,22 +163,17 @@ public class VamsasSession { if (sessionDir1.exists()) { if (!sessionDir1.isDirectory() || !sessionDir1.canWrite() || !sessionDir1.canRead()) throw new IOException("Cannot access '"+sessionDir1+"' as a read/writable Directory."); - this.sessionDir = sessionDir1;//createSessionFiles, need sessionDir attribute set - if (!checkSessionFiles(sessionDir1)) - { - createSessionFiles(); - } - // session files exist in the directory - - initSessionObjects(); - slog.debug("Initialising additional VamsasSession instance"); - log.debug("Attached to VamsasSession in "+sessionDir1); + if (!checkSessionFiles(sessionDir1)) + log.warn("checkSessionFiles() returned false. Possible client implementation error"); + this.sessionDir = sessionDir1; + initSessionObjects(); + slog.debug("Initialising additional VamsasSession instance"); + log.debug("Attached to VamsasSession in "+sessionDir1); //} } else { // start from scratch if (!sessionDir1.mkdir()) throw new IOException("Failed to make VamsasSession directory in "+sessionDir1); - this.sessionDir = sessionDir1; createSessionFiles(); initSessionObjects(); slog.debug("Session directory created."); @@ -205,19 +201,21 @@ public class VamsasSession { throw new IOException("Invalid call to createSessionFiles() with null sessionDir"); File c_file = new File(sessionDir,CLIENT_LIST); File v_doc = new File(sessionDir,VAMSAS_OBJ); - if (c_file.createNewFile()) + if (!c_file.exists() && c_file.createNewFile()) log.debug("Created new ClientFile "+c_file); // don't care if this works or not - if (v_doc.createNewFile()) + if (!v_doc.exists() && v_doc.createNewFile()) log.debug("Created new Vamsas Session Document File "+v_doc); } /** * construct SessionFile objects and watchers for each */ private void initSessionObjects() throws IOException { + createSessionFiles(); if (clist!=null || vamArchive!=null) throw new IOException("initSessionObjects called for initialised VamsasSession object."); clist = new ClientsFile(new File(sessionDir,CLIENT_LIST)); vamArchive = new VamsasFile(new File(sessionDir,VAMSAS_OBJ)); + storedocfile=new ClientsFile(new File(sessionDir, CLOSEANDSAVE_FILE)); initLog(); } /** @@ -227,26 +225,21 @@ public class VamsasSession { public FileWatcher getClientWatcher() { return new FileWatcher(clist.sessionFile); } - FileWatcher session_doc_watcher=null; /** * make a new watcher object for the vamsas Document * @return new ClientFile watcher instance */ public FileWatcher getDocWatcher() { - if (session_doc_watcher==null) - return session_doc_watcher = new FileWatcher(vamArchive.sessionFile); return new FileWatcher(vamArchive.sessionFile); } FileWatcher store_doc_file=null; + public ClientsFile storedocfile=null; /** * make a new watcher object for the messages file - * (thread safe - keeps a reference to the first watcher) * @return new watcher instance */ public FileWatcher getStoreWatcher() { - if (store_doc_file==null) - return store_doc_file = new FileWatcher(new File(CLOSEANDSAVE_FILE)); - return new FileWatcher(new File(CLOSEANDSAVE_FILE)); + return new FileWatcher(new File(sessionDir,CLOSEANDSAVE_FILE)); } /** @@ -257,6 +250,7 @@ public class VamsasSession { * @return */ public void addStoreDocumentRequest(ClientHandle client, UserHandle user) throws IOException { + // TODO: replace this with clientsFile mechanism SessionFile sfw = new SessionFile(new File(sessionDir, CLOSEANDSAVE_FILE)); while (!sfw.lockFile()) log.debug("Trying to get lock for "+CLOSEANDSAVE_FILE); @@ -293,7 +287,7 @@ public class VamsasSession { if (extlock==null && !vamArchive.lockFile()) while (!vamArchive.lockFile()) log.info("Trying to get lock for "+vamArchive.sessionFile); - // TODO: LATER: decide if session archive provenance should be written in vamsasDocument file for this export. + // TODO: LATER: decide if a provenance entry should be written in the exported document recording the export from the session newdoc.updateFrom(extlock, vamArchive); // LATER: LATER: fix use of updateFrom for file systems where locks cannot be made (because they don't have a lockManager, ie NFS/Unix, etc). vamArchive.unLock(); @@ -308,15 +302,29 @@ public class VamsasSession { * @throws IOException if locks fail or vamsas document read fails. */ protected VamsasArchive getVamsasDocument() throws IOException { - // TODO: check we haven't already done this once - if (!vamArchive.lockFile()) + // TODO: check we haven't already done this once - probably should be done by caller + // patiently wait for a lock on the document. (from ArchiveClient.getUpdateable()) + long tries=5000; + while (vamArchive.getLock()==null && --tries>0) { +// Thread.sleep(1); + log.debug("Trying to get a document lock for the "+tries+"'th time."); + } + if (tries==0) throw new IOException("Failed to get lock for vamsas archive."); - + VamsasArchive va = new VamsasArchive(vamArchive.sessionFile, false, true, vamArchive); - + return va; } /** + * Unlocks the vamsas archive session document after it has been closed. + * @throws IOException + */ + protected void unlockVamsasDocument() throws IOException { + if (vamArchive!=null) + vamArchive.unLock(); + } + /** * create a uniquely named uk.ac.vamsas.client.simpleclient.ClientsFile.addClient(ClientHandle)ile in the session Directory * @see java.io.File.createTempFile * @param pref Prefix for name @@ -339,9 +347,14 @@ public class VamsasSession { protected void addClient(IClient client) { if (client == null) - this.slog.error("Try to add a null client to the session "); - else - this.clist.addClient(client.getClientHandle(), getClientWatcher().getChangedState()); + slog.error("Try to add a null client to the session "); + else { + log.debug("Adding client "+client.getClientHandle().getClientUrn()); + getClientWatcherElement().haltWatch(); + clist.addClient(client.getClientHandle()); + getClientWatcherElement().enableWatch(); + log.debug("Added."); + } } /** @@ -357,20 +370,30 @@ public class VamsasSession { { if (client == null) { - //System.out.println("Try to remove a null client."); - this.slog.error("Try to remove a null client."); + log.error("Null client passed to removeClient"); return; } - this.clist.removeClient(client.getClientHandle(), getClientWatcher().getChangedState()); + SessionFileWatcherElement cwe=getClientWatcherElement(); + if (cwe!=null && cwe.isWatchEnabled()) { + cwe.haltWatch(); + } else { + cwe=null; + } + 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 - System.out.println("last client removed: removing session"); + slog.info("last client removed: removing session"); + log.debug("last client removed: removing session"); this.getSessionManager().removeSession(client.getSessionHandle()); } else { - this.slog.debug("Still "+this.clist.retrieveClientList().length +" active clients"); - System.out.println("Still "+(this.clist.retrieveClientList()==null?"null":this.clist.retrieveClientList().length+"") +" active clients"); + int active=clist.retrieveClientList().length; + log.debug("Still "+active+" active clients"); + slog.info("Still "+active+" active clients"); + } + if (cwe!=null) { + cwe.enableWatch(); } } /** @@ -385,6 +408,19 @@ protected SimpleSessionManager getSessionManager() { protected void setSessionManager(SimpleSessionManager sessionManager) { this.sessionManager = sessionManager; } +public ClientsFile getStoreDocFile() { + if (storedocfile==null) { + + } + return storedocfile; +} +SessionFileWatcherElement clistWatchElement=null; +public SessionFileWatcherElement getClientWatcherElement() { + if (clistWatchElement==null) { + clistWatchElement=new SessionFileWatcherElement(clist,null); + } + return clistWatchElement; +} } -- 1.7.10.2