implementing minimal set : SimpleClientFactory createSession method -> SimpleClient...
authorjprocter <jprocter@compbio.dundee.ac.uk>
Mon, 23 Jan 2006 19:10:43 +0000 (19:10 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Mon, 23 Jan 2006 19:10:43 +0000 (19:10 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@166 be28352e-c001-0410-b1a7-c7978e42abec

src/org/vamsas/client/IClient.java
src/org/vamsas/client/simpleclient/EventGeneratorThread.java
src/org/vamsas/client/simpleclient/SessionUrn.java
src/org/vamsas/client/simpleclient/SimpleClient.java
src/org/vamsas/client/simpleclient/SimpleClientFactory.java
src/org/vamsas/client/simpleclient/SimpleDocument.java
src/org/vamsas/client/simpleclient/VamsasSession.java

index 5c538b1..a8d122e 100644 (file)
@@ -5,6 +5,7 @@
 package org.vamsas.client;
 
 import java.beans.PropertyChangeListener;
+import java.io.IOException;
 
 /**
  * Defines the methods availabable to a vamsas
@@ -71,8 +72,10 @@ public interface IClient {
      * get vamsas document with 
      * user and app specific data
      * IClientDocuments are not thread-safe.
+     * TODO: New exception for failed document lock.
+     * @throws IOException if lock is not obtainable for the document in the session
      */
-    public IClientDocument getClientDocument();
+    public IClientDocument getClientDocument() throws IOException;
     /**
      * Queue new Vorba objects for storage and propagation 
      * to other clients (via Event.DOCUMENT_UPDATE based 
index e60a674..a643ae1 100644 (file)
@@ -16,9 +16,18 @@ public class EventGeneratorThread extends Thread implements Runnable {
   private SimpleClient client;
   private Hashtable handlers; // manager object
   private VamsasSession session;
-  
+
+  /** 
+   * list with all the clientHandles for the session
+   */
   protected FileWatcher clientfile=null;
+  /**
+   * the session's vamsasDocument
+   */
   protected FileWatcher vamsasfile=null;
+  /**
+   * written to by client when its app calls storeDocument.
+   */
   protected FileWatcher storeFile=null;
   
   private boolean watch=false;
@@ -70,17 +79,129 @@ public class EventGeneratorThread extends Thread implements Runnable {
     }
     if ((watchlock=clientfile.getChangedState())!=null) {
       // see what happened to the clientfile - compare our internal version with the one in the file, or just send the updated list out...?
-      raised++;
+      //
+      /**
+       * Generated when a new vamsas client is attached to a session (Handle is
+       * passed) Note: the newly created client does not receive the event.
+       *
+      public static final String CLIENT_CREATION = "org.vamsas.client.events.clientCreateEvent";
+  */ // as the test
+      /**
+       * Generated when a vamsas client leaves a session (Handle is passed to all
+       * others).
+      public static final String CLIENT_FINALIZATION = "org.vamsas.client.events.clientFinalizationEvent";
+       */ // again - as the test.
+          raised++;
     }
     if ((watchlock=vamsasfile.getChangedState())!=null) {
-      // pass IClientDocument instance to app handler ?
+      
+      /**
+       * Generated when a client has finished updating the document. Passes
+       * applicationHandle of client so the updating client can recognise its own
+       * updates.
+      public static final String DOCUMENT_UPDATE = "org.vamsas.client.events.documentUpdateEvent";
+       */
+      // read apphandle from 'lastUpdate' session file.
+      // pass apphandle name to appHandler ?
+      
     }
+    /**
+     * Generated when a new vamsas document is created (perhaps from some existing
+     * Vamsas data) so an application may do its own data space initialization.
+     * TODO: decide if this is called when an app is connected to a stored
+     * session...
+     public static final String DOCUMENT_CREATE = "org.vamsas.client.events.documentCreateEvent";
+    */
+    // check if this session's appInit flag is set - if not - generate event for this app.
+    // prolly don't need this at the moment - when an app does getDocument it can to the initing then.
+    
+
+    /**
+     * Generated prior to session Shutdown, after the last participating vamsas
+     * client has finalized.
+     *  TODO: decide on purpose of this ?  is this for benefit of multi-session Apps only ?
+    public static final String SESSION_SHUTDOWN = "org.vamsas.client.events.SessionShutdownEvent";
+     */
+
+    /**
+     * Generated for all clients when any client calls IClient.storeDocument() to
+     * allow them to store any updates before an offline copy of the session is
+     * created. Any client that handles this should call the
+     * IClient.getDocument(), update and then IClient.updateDocument in the same
+     * handler thread.
+     * EventName: <Vamsas-session URN>
+     * NewValue: org.vamsas.client.IClient for session.
+     *
+    public static final String DOCUMENT_FINALIZEAPPDATA = "org.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() {
     
   }
+  /**
+   * Events raised by IClient and propagated to others in session
+   */
+  
+  /**
+   * number of milliseconds between any file state check.
+   */
+  long POLL_UNIT = 20;
+  protected void wait(int u) {
+    if (u<=0)
+      u=1;
+    long l = System.currentTimeMillis()+POLL_UNIT*u;
+      while (System.currentTimeMillis()<l)
+        ;
+  }
+    
+  
+  
+  int STORE_WAIT=5; // how many units before we decide all clients have finalized their appdatas
+  
+  /**
+   * client App requests offline storage of vamsas data. 
+   * Call blocks whilst other apps do any appData finalizing
+   * and then returns (after locking the vamsasDocument in the session)
+   * @return Lock for session.vamArchive 
+   */
+  protected Lock want_to_store() {
+    log.debug("Waiting for other apps to do FinalizeApp handling.");
+    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.");
+    }
+    
+    int units = 0;
+    while (units<STORE_WAIT) {
+      wait(1);
+      if (storeFile.hasChanged() || vamsasfile.hasChanged())
+        units=0;
+      else
+        units++;
+    }  
+    log.debug("finished waiting.");
+    return session.vamArchive.getLock();
+  }
   
   /**
    * probably don't need any of these below.
index 55edb24..f96c74c 100644 (file)
@@ -18,8 +18,14 @@ public class SessionUrn extends org.vamsas.client.SessionUrn {
     TYPES.put(SIMPLECLIENT, SessionUrn.class);
     TYPES.put(SessionUrn.VAMSASDOCUMENT, SessionUrn.class);
   }
-
+  
   public SessionUrn(File sessionLocation) {
+  // TODO: LATER: implement switch to have vamsas document or simpleclient sessions for same constructor
     super(SIMPLECLIENT, sessionLocation);
+    //else
+      // super(VAMSASDOCUMENT, sessionLocation);
+  }
+  public SessionUrn(VamsasSession session) {
+    super(SIMPLECLIENT, session.sessionDir);
   }
 }
index cbf5c0d..37595b4 100644 (file)
@@ -12,36 +12,88 @@ import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.IOException;
 import java.util.Hashtable;
 import java.util.Vector;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.vamsas.client.ClientHandle;
 import org.vamsas.client.Events;
 import org.vamsas.client.IClient;
 import org.vamsas.client.IClientDocument;
 import org.vamsas.client.SessionHandle;
 import org.vamsas.client.UserHandle;
+import org.vamsas.objects.core.VamsasDocument;
 
 /**
  * @author jimp
  */
 public class SimpleClient implements IClient {
-
-  UserHandle user = null;
-
-  SessionHandle session = null;
-
-  ClientHandle client = null;
   
+  private static Log log = LogFactory.getLog(SimpleClient.class);
+  
+  protected UserHandle user = null;
+  
+  protected SessionUrn session = null;
+  protected VamsasSession _session;
+  protected ClientHandle client = null;
+  protected EventGeneratorThread evgen = null;
+  IdFactory vorba = null;
+  private void makeVorbaIdFactory() {
+    if (vorba==null) {
+      vorba = new IdFactory(getSessionHandle(), client, user);
+    } else
+      log.debug("Vorba Id factory exists already.");
+  }
+  
+  /**
+   * construct SimpleClient for user, client and VamsasSession directory
+   * use the SimpleClientFactory rather than this constructor directly. 
+   * @param user
+   * @param client
+   * @param sess
+   */
+  protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess) {
+    // TODO: validate user/client/session
+    _session = sess;
+    this.user = user;
+    this.client = client;
+    session = new SessionUrn(_session);
+  }
+  /**
+   * construct new session by importing objects from an existing vamsas document
+   * @param user
+   * @param client
+   * @param sess
+   * @param importingArchive
+   * @throws Exception IOExceptions for Session IO problems, and general Exception if importing document is invalid.
+   */
+  protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess, File importingArchive) throws Exception {
+    this(user, client, sess);
+    makeVorbaIdFactory();
+    VamsasArchive sessdoc = _session.getVamsasDocument();
+    try {
+      VamsasArchiveReader odoc = new VamsasArchiveReader(importingArchive);
+      SimpleDocument sdoc = new SimpleDocument(vorba);
+      VamsasDocument doc = sdoc.getVamsasDocument(odoc);
+      sessdoc.putVamsasDocument(doc, vorba);
+      sessdoc.closeArchive();
+    } catch (Exception e) {
+      sessdoc.cancelArchive();
+      // write a dummy archive
+      throw new Exception("Failed to import data from "+importingArchive, e);
+    }
+  }
   /*
    * (non-Javadoc)
-   * TODO: check that build substitution variables are correct
+   * TODO: LATER: check that build substitution variables are correct
    * @see org.vamsas.client.IClient#getAbout()
    */
   public String getAbout() {
     return new String("VORBA SimpleClient version $version$ build $build$");
   }
-
+  
   /*
    * (non-Javadoc)
    * 
@@ -50,16 +102,18 @@ public class SimpleClient implements IClient {
   public String getSessionUrn() {
     return session.getSessionUrn();
   }
-
+  
   /*
    * (non-Javadoc)
    * 
    * @see org.vamsas.client.IClient#getSessionHandle()
    */
   public SessionHandle getSessionHandle() {
-    return session;
+    // TODO: eliminate SessionHandle ? need to refactor interfaces.
+    SessionHandle sh = new SessionHandle(session.getSessionUrn());
+    return sh;
   }
-
+  
   /*
    * (non-Javadoc)
    * 
@@ -68,7 +122,7 @@ public class SimpleClient implements IClient {
   public ClientHandle getClientHandle() {
     return client;
   }
-
+  
   /*
    * (non-Javadoc)
    * 
@@ -77,11 +131,11 @@ public class SimpleClient implements IClient {
   public UserHandle getUserHandle() {
     return user;
   }
-
+  
   private Hashtable handlers = initHandlers();
-
+  
   private Vector listeners = new Vector();
-
+  
   /**
    * make all the PropertyChangeSupport objects for the
    * events described in org.vamsas.client.Event
@@ -96,7 +150,7 @@ public class SimpleClient implements IClient {
     }
     return events;
   }
-
+  
   /*
    * (non-Javadoc)
    * 
@@ -106,12 +160,12 @@ public class SimpleClient implements IClient {
     if (handlers.containsKey(Events.DOCUMENT_UPDATE)) {
       Object handler;
       ((PropertyChangeSupport) (handler = handlers.get(Events.DOCUMENT_UPDATE)))
-          .addPropertyChangeListener(evt);
+      .addPropertyChangeListener(evt);
       listeners.add(handler);
       listeners.add((Object) evt);
     }
   }
-
+  boolean finalized=false;
   /*
    * (non-Javadoc)
    * 
@@ -126,7 +180,7 @@ public class SimpleClient implements IClient {
     // deregister listeners.
     // mark this instance as finalized
   }
-
+  
   /**
    * extract data appropriate for client, session and user
    * from vamsas document.
@@ -142,34 +196,61 @@ public class SimpleClient implements IClient {
    * 
    * @see org.vamsas.client.IClient#getClientDocument()
    */
-  public IClientDocument getClientDocument() {
+  public IClientDocument getClientDocument() throws IOException {
+    
+    makeVorbaIdFactory();
+    VamsasArchive va = _session.getVamsasDocument();
+    // TODO: reduce size of vorba ids generated from these parameters to IdFactory (mainly sessionHandle rationalization ?)
+    try {
+      va.getOriginalVamsasDocument(va, vorba);
+      // if session currently holds data - read it in.
+    }
+    catch (Exception e) {
+      
+    }
+    //ClientDocument cdoc = new ClientDocument();
+    
     Object[] vdoc;//  TODO: = getVamsasDocument(new Reader());
     // ClientDocument cdoc = new ClientDocument(getApplicationData(),
-        // ((VamsasDocument) vdoc[0]).getVAMSAS(), (Hashtable) vdoc[1], this);
+    // ((VamsasDocument) vdoc[0]).getVAMSAS(), (Hashtable) vdoc[1], this);
     // 
     return null;
   }
-
+  
   /*
    * (non-Javadoc)
    * 
    * @see org.vamsas.client.IClient#updateDocument(org.vamsas.client.IClientDocument)
    */
   public void updateDocument(IClientDocument newdoc) {
-    // TODO Auto-generated method stub
-    // 
+    if (!(newdoc instanceof ClientDocument)) {
+      throw new Error("Invalid IClientDocument instance for SimpleClient.");
+    }
+    
+    // try to update the sessionFile
+    
+    // write the appHandle to the lastupdate file.
+    
   }
-
+  
   /*
    * (non-Javadoc)
    * 
    * @see org.vamsas.client.IClient#storeDocument(java.io.File)
    */
   public void storeDocument(File location) {
-    // TODO Auto-generated method stub
 
+    // write storeDocument file to inform other clients that they should raise
+    Lock vamlock = evgen.want_to_store();
+    // Events.DOCUMENT_FINALIZEAPPDATA
+    try {
+      _session.writeVamsasDocument(location, vamlock);
+    } catch (Exception e) {
+      log.warn("Exception whilst trying to store document in "+location,e);
+    }
+    vamlock.release();
   }
-
+  
   /*
    * (non-Javadoc)
    * 
@@ -180,28 +261,55 @@ public class SimpleClient implements IClient {
     if (handlers.containsKey(EventChain)) {
       Object handler;
       ((PropertyChangeSupport) (handler = handlers.get(EventChain)))
-          .addPropertyChangeListener(evt);
+      .addPropertyChangeListener(evt);
       listeners.add(handler);
       listeners.add((Object) evt);
     }
   }
-
+  
   /* (non-Javadoc)
    * @see org.vamsas.client.IClient#pollUpdate()
    */
   public void pollUpdate() {
-    // TODO wake up UpdateWatcher thread to check for updates.
 
-  }
-
-  public static void main(String[] args) {
+    if (evgen==null) {
+      log.warn("pollUpdate called on incomplete SimpleClient object.");
+      return;
+    }
+    //TODO ensure event generator robustly handles these interrupts.
+    log.debug("interrrupting event generator.");
+    evgen.interrupt();
+    log.debug("interrrupted event generator.");
   }
 
   /* (non-Javadoc)
    * @see org.vamsas.client.IClient#joinSession()
    */
   public void joinSession() throws Exception {
-    // TODO Auto-generated method stub
+    // start the EventGenerator thread.
+    if (evgen==null) {
+      log.warn("joinSession called on incomplete SimpleClient object.");
+      return;
+    }
+    if (evgen.isAlive())
+      throw new Error("Join session called twice for the same SimpleClient (IClient instance).");
+    evgen.start();
+    if (evgen.isAlive())
+      log.debug("Started EventGenerator thread.");
+    else {
+      log.warn("Failed to start EventGenerator thread.");
+      throw new Exception("Failed to start event generator thread - client cannot be instantiated.");
+    }
     
   }
+  
+  
+  
+  /* (non-Javadoc)
+   * @see org.vamsas.client.IClient#importDocument(java.io.File)
+   */
+  public void importDocument(File location) {
+    // TODO LATER: implement SimpleClient.importDocument()
+    log.error("importDocument is not implemented for a SimpleClient Session.");
+  }
 }
index 73d7ae9..c6d1687 100644 (file)
@@ -3,6 +3,8 @@ package org.vamsas.client.simpleclient;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.vamsas.client.ClientHandle;
 import org.vamsas.client.IClient;
 import org.vamsas.client.IClientFactory;
@@ -14,7 +16,8 @@ import org.vamsas.client.UserHandle;
  *
  */
 public class SimpleClientFactory implements IClientFactory {
+  private static Log log = LogFactory.getLog(SimpleClientFactory.class);
+
   File sessionArena;
   
   /**
@@ -81,7 +84,37 @@ public class SimpleClientFactory implements IClientFactory {
     // create client instance
     return null;
   }
-
+  /**
+   * make a new vamsas session from the data in the archive vamsasdocument 
+   * @param applicationHandle
+   * @param userId
+   * @param vamsasdocument
+   * @return
+   */
+  public IClient openSession(ClientHandle applicationHandle, UserHandle userId, ArchiveUrn vamsasdocument) throws IOException {
+    // verify applicationHandle and userId
+    // TODO: verify applicationHandle and userId
+    // verify vamsasdocument is a valid document.
+    File vamdoc = vamsasdocument.asFile();
+    log.debug("Starting new session with data from "+vamsasdocument.getSessionUrn()+"(File is : "+vamdoc+")");
+    VamsasArchiveReader archive = new VamsasArchiveReader(vamdoc);
+    // TODO: a real validity test. The below just checks it can be read.
+    if (!archive.isValid())
+      throw new IOException(vamsasdocument.getSessionUrn()+" is not a valid vamsasDocument archive.");
+    // create new session directory
+    if (sessionArena==null)
+      throw new Error("Improperly initialised SimpleClientFactory object - null sessionArena.");
+    File sessdir = File.createTempFile("sess", ".simpleclient", sessionArena);
+    if (!(sessdir.delete() && sessdir.mkdir()))
+        throw new IOException("Could not make session directory "+sessdir);
+    VamsasSession sess = new VamsasSession(sessdir);
+    // copy document into session directory
+    sess.setVamsasDocument(vamsasdocument.asFile());
+    // create client instance and return.
+    SimpleClient client = new SimpleClient(userId, applicationHandle, sess);
+    
+    return client;
+  }
   public static void main(String[] args) {
   }
 }
index 1fc8fdc..84f2444 100644 (file)
@@ -24,8 +24,8 @@ import org.vamsas.objects.utils.document.VersionEntries;
 /**
  * holds static vamsasDocument from XML routines and
  * state objects for a particular unmarshalled Document instance.
+ * TODO Could be refactored ? only dependence is the IdFactory.getDummyFactory(String) method.
  * @author jimp
- *
  */
 public class SimpleDocument {
   VorbaIdFactory vorba;
index 242cf36..4ea355d 100644 (file)
@@ -1,15 +1,23 @@
 package org.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.Writer;
 
 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.vamsas.client.ClientHandle;
+import org.vamsas.client.UserHandle;
 /**
+ * Holds the file handlers and watchers for a session.
  * 
+ * TODO: delete the stuff below - prolly irrelevant now
  * Vamsas client is intialised with a path to create live session directories. 
  * This path may contain a vamsas.properties file 
  * that sets additional parameters (otherwise client 
@@ -48,17 +56,11 @@ import org.apache.log4j.FileAppender;
 
 public class VamsasSession {
   /**
-   * Holds the file handlers and watchers for a session.
-   */
-  /**
-   * TODO: make sessionDir signature to allow VamsasSession instances to recognise the form of the directory
-   */
-  /**
    * indicator file for informing other processes that 
    * they should finalise their vamsas datasets for 
-   * storing in a vamsas archive.
+   * storing into a vamsas archive.
    */
-  public static final String CLOSEANDSAVE_FILE="exiting";
+  public static final String CLOSEANDSAVE_FILE="stored.log";
   /**
    * log file location
    */
@@ -70,6 +72,7 @@ public class VamsasSession {
    * @throws IOException
    */
   private void initLog() throws IOException {
+    // TODO: 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()));
   }
@@ -112,6 +115,7 @@ public class VamsasSession {
         throw new IOException("Failed to make VamsasSession directory in "+sessionDir);
       this.sessionDir = sessionDir; 
       createSessionFiles();
+      createDummyVamsasDocument();
       initSessionObjects();
       slog.debug("Session directory created.");
       log.debug("Initialised VamsasSession in "+sessionDir);
@@ -151,6 +155,7 @@ public class VamsasSession {
       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));
+    initLog();
   }
   /**
    * make a new watcher object for the clientFile
@@ -166,13 +171,77 @@ public class VamsasSession {
   public FileWatcher getDocWatcher() {
     return new FileWatcher(vamArchive.sessionFile);
   }
-
+  FileWatcher store_doc_file=null;
   /**
    * make a new watcher object for the messages file
    * @return new watcher instance
    */
   public FileWatcher getStoreWatcher() {
-    return new FileWatcher(new File(CLOSEANDSAVE_FILE));
+    return store_doc_file = new FileWatcher(new File(CLOSEANDSAVE_FILE));
+  }
+  /**
+   * write to the StoreWatcher file to indicate that a storeDocumentRequest has been made.
+   * The local client's storeWatcher FileWatcher object is updated so the initial change is not registered.
+   * @param client
+   * @param user
+   * @return
+   */
+  public void addStoreDocumentRequest(ClientHandle client, UserHandle user) throws IOException {
+    SessionFile sfw = new SessionFile(new File(sessionDir, CLOSEANDSAVE_FILE));
+    while (!sfw.lockFile())
+      log.debug("Trying to get lock for "+CLOSEANDSAVE_FILE);
+    sfw.fileLock.rafile.setLength(0); // wipe out any old info.
+    // TODO: rationalise what gets written to this file (ie do we want other clients to read the id of the requestor?)
+    sfw.fileLock.rafile.writeUTF(client.getClientUrn()+":"+user.getFullName()+"@"+user.getOrganization());
+    sfw.unlockFile();
+    if (store_doc_file!=null)
+      store_doc_file.setState();
+    slog.info("FinalizeAppData request from "+user.getFullName()+" using "+client.getClientUrn()+"");
+  }
+  /**
+   * create a new session with an existing vamsas Document - by copying it into the session.
+   * @param archive
+   */
+  protected void setVamsasDocument(File archive) throws IOException {
+    log.debug("Transferring vamsas data from "+archive+" to session:"+vamArchive.sessionFile);
+    SessionFile xtantdoc = new SessionFile(archive);
+    vamArchive.updateFrom(null, xtantdoc);
+    // TODO: LATER: decide if session archive provenance should be updated to reflect access.
+    // TODO: soon! do a proper import objects from external file 
+    log.debug("Transfer complete.");
+  }
+  /**
+   * write session as a new vamsas Document (this will overwrite any existing file without warning)
+   * @param destarchive
+   */
+  protected void writeVamsasDocument(File destarchive, Lock extlock) throws IOException {
+    log.debug("Transferring vamsas data from "+vamArchive.sessionFile+" to session:"+destarchive);
+    SessionFile newdoc = new SessionFile(destarchive);
+    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.
+    newdoc.updateFrom(extlock, vamArchive);
+    // TODO: SOON: 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();
+    newdoc.unlockFile();
+    log.debug("Transfer complete.");
+  }
+  
+  /**
+   * Creates a VamsasArchive object for accessing and updating document
+   * Note: this will lock the Vamsas Document for exclusive access to the client.
+   * @return session vamsas document
+   * @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()) 
+      throw new IOException("Failed to get lock for vamsas archive.");
+    
+    VamsasArchive va = new VamsasArchive(vamArchive.sessionFile, false, true, vamArchive);
+    
+    return va;
   }
   
 }