added overwrite flag to VamsasArchive writer class (avoids loss of locks on file...
authorjprocter <jprocter@compbio.dundee.ac.uk>
Fri, 20 Jan 2006 12:00:23 +0000 (12:00 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Fri, 20 Jan 2006 12:00:23 +0000 (12:00 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@154 be28352e-c001-0410-b1a7-c7978e42abec

src/org/vamsas/client/simpleclient/VamsasArchive.java
src/org/vamsas/client/simpleclient/VamsasFile.java
src/org/vamsas/test/simpleclient/ArchiveWatcher.java
src/org/vamsas/test/simpleclient/VamsasArchive.java

index ea11a81..6e86407 100644 (file)
@@ -44,13 +44,78 @@ import org.vamsas.objects.utils.document.VersionEntries;
 public class VamsasArchive {
   private static Log log = LogFactory.getLog(VamsasArchive.class);
   /**
+   * Access original document if it exists, and get VAMSAS root objects.
+   * @return vector of vamsas roots from original document
+   * @throws IOException
+   */
+  public static object[] getOriginalRoots(VamsasArchive ths) throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+    VamsasArchiveReader oReader = ths.getOriginalArchiveReader();
+    if (oReader!=null) {
+      
+      if (oReader.isValid()) {
+        InputStreamReader vdoc = new InputStreamReader(oReader.getVamsasDocumentStream());
+        VamsasDocument doc = VamsasDocument.unmarshal(vdoc);
+        if (doc!=null) 
+          return doc.getVAMSAS();
+        // TODO ensure embedded appDatas are garbage collected to save memory
+      } else {
+        InputStream vxmlis = oReader.getVamsasXmlStream();
+        if (vxmlis!=null) { // Might be an old vamsas file.
+          BufferedInputStream ixml = new BufferedInputStream(oReader.getVamsasXmlStream());
+          InputStreamReader vxml = new InputStreamReader(ixml);
+          VAMSAS root[] = new VAMSAS[1];
+          root[0] = VAMSAS.unmarshal(vxml);
+          if (root[0]!=null)
+            return root;
+        }
+      }
+    }
+    return null;
+  }
+  /**
+   * Access the original vamsas document for a VamsasArchive class, and return it.
+   * Users of the VamsasArchive class should use the getVamsasDocument method to retrieve
+   * the current document - only use this one if you want the 'backup' version.
+   * TODO: catch OutOfMemoryError - they are likely to occur here.
+   * NOTE: vamsas.xml datastreams are constructed as 'ALPHA_VERSION' vamsas documents.
+   * @param ths
+   * @return null if no document exists.
+   * @throws IOException
+   * @throws org.exolab.castor.xml.MarshalException
+   * @throws org.exolab.castor.xml.ValidationException
+   */
+  public static VamsasDocument getOriginalVamsasDocument(VamsasArchive ths) throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+    return VamsasArchive.getOriginalVamsasDocument(ths, null);
+  } 
+  /**
+   * Uses VorbaXmlBinder to retrieve the VamsasDocument from the original archive referred to by ths
+   * @param ths
+   * @param vorba
+   * @return
+   * @throws IOException
+   * @throws org.exolab.castor.xml.MarshalException
+   * @throws org.exolab.castor.xml.ValidationException
+   */
+  public static VamsasDocument getOriginalVamsasDocument(VamsasArchive ths, VorbaIdFactory vorba) throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+    VamsasArchiveReader oReader = ths.getOriginalArchiveReader();
+    if (oReader!=null) {
+      ths.setVorba(vorba);
+      return ths.vorba.getVamsasDocument(oReader);
+    }
+    // otherwise - there was no valid original document to read.
+    return null;    
+  }
+  /**
    * destination of new archive data (tempfile if virginarchive=true, original archive location otherwise)
    */
   java.io.File archive=null;
   /**
    * locked IO handler for new archive file
    */
-  SessionFile rchive=null; 
+  SessionFile rchive=null;
   /**
    * original archive file to be updated (or null if virgin) where new data will finally reside
    */
@@ -59,6 +124,7 @@ public class VamsasArchive {
    * original archive IO handler
    */
   SessionFile odoclock = null;
+  Lock destinationLock = null;
   /**
    * Original archive reader class
    */
@@ -75,10 +141,35 @@ public class VamsasArchive {
    * JarEntries written to archive
    */
   Hashtable entries = null;
+  
   /**
    * true if we aren't just updating an archive
    */
   private boolean virginArchive=false;
+  
+  /**
+   * name of backup of existing archive that has been updated/overwritten.
+   * onlu one backup will be made - and this is it.
+   */
+  File originalBackup = null;
+  
+  boolean donotdeletebackup=false;
+  private final int _TRANSFER_BUFFER=4096*4;
+  protected SimpleDocument vorba = null;
+  /**
+   * Access and return current vamsas Document, if it exists, or create a new one 
+   * (without affecting VamsasArchive object state - so is NOT THREAD SAFE)
+   * TODO: possibly modify internal state to lock low-level files 
+   * (like the IClientDocument interface instance constructer would do) 
+   * @see org.vamsas.simpleclient.VamsasArchive.getOriginalVamsasDocument for additional caveats
+   * 
+   * @return
+   * @throws IOException
+   * @throws org.exolab.castor.xml.MarshalException
+   * @throws org.exolab.castor.xml.ValidationException
+   */
+  private VamsasDocument _doc=null;
+  
   /**
    * Create a new vamsas archive
    * File locks are made immediately to avoid contention
@@ -88,21 +179,35 @@ public class VamsasArchive {
    * @throws IOException if call to accessOriginal failed for updates, or openArchive failed.
    */
   public VamsasArchive(File archive, boolean vamsasdocument) throws IOException {
-    this(archive, vamsasdocument, null);
+    this(archive, false, vamsasdocument, null);
   }
-  public VamsasArchive(File archive, boolean vamsasdocument, Lock extantLock) throws IOException {
+  public VamsasArchive(File archive, boolean vamsasdocument, boolean overwrite) throws IOException {
+    this(archive, overwrite, vamsasdocument, null);
+  }
+  /**
+   * 
+   * @param archive file to write
+   * @param overwrite true if original contents should be deleted
+   * @param vamsasdocument true if a proper VamsasDocument archive is to be written.
+   * @param extantLock SessionFile object holding a lock for the <object>archive</object> 
+   * @throws IOException
+   */
+  public VamsasArchive(File archive, boolean overwrite, boolean vamsasdocument, SessionFile extantLock) throws IOException {
     super();
-    
     if (archive==null || (archive!=null && !(archive.getParentFile().canWrite() && (!archive.exists() || archive.canWrite())))) {
       log.fatal("Expect Badness! -- Invalid parameters for VamsasArchive constructor:"+((archive!=null) 
           ? "File cannot be overwritten." : "Null Object not valid constructor parameter"));
       return;
     }
+
     this.vamsasdocument = vamsasdocument;
-    if (archive.exists()) {
+    if (archive.exists() && !overwrite) {
       this.original = archive;
-      this.odoclock = new SessionFile(archive); // lock the file *immediatly*
-      odoclock.lockFile(extantLock);
+      if (extantLock!=null)
+        this.odoclock = extantLock;
+      else 
+        this.odoclock = new SessionFile(archive); 
+      odoclock.lockFile(); // lock the file *immediatly*
       this.archive = null;       // archive will be a temp file when the open method is called
       virginArchive=false;
       try {
@@ -113,101 +218,31 @@ public class VamsasArchive {
     } else {
       this.original = null;
       this.archive = archive; // archive is written in place.
-      if (archive!=null) {
-        archive.createNewFile();
-        rchive=new SessionFile(archive); // lock the file *immediatly*
-        rchive.lockFile(extantLock);
-      }
+      if (extantLock!=null)
+        rchive=extantLock;
+      else
+        rchive = new SessionFile(archive);
+      rchive.lockFile();
+      rchive.fileLock.rafile.setLength(0); // empty the archive.
       virginArchive = true;
     }
     this.openArchive(); // open archive
   }
   /**
-   * name of backup of existing archive that has been updated/overwritten.
-   * onlu one backup will be made - and this is it.
-   */
-  File originalBackup = null;
-  
-  private void makeBackup() {
-    if (!virginArchive) {
-      if (originalBackup==null && original!=null && original.exists()) {
-        try {
-          accessOriginal();
-          originalBackup = odoclock.backupSessionFile(null, original.getName(), ".bak", original.getParentFile());
-        }
-        catch (IOException e) {
-          log.warn("Problem whilst making a backup of original archive.",e);
-        }
-      }
-    }
-  }
-  
-  /**
-   * called after archive is written to put file in its final place
-   */
-  private void updateOriginal() {
-    if (!virginArchive) {
-      // make sure original document really is backed up and then overwrite it.
-      if (odoc!=null) {
-        // try to shut the odoc reader.
-        odoc.close();
-        odoc = null;
-      }
-      // Make a backup if it isn't done already
-      makeBackup();
-      try {
-        // copy new Archive data that was writen to a temporary file
-        odoclock.updateFrom(null, rchive);
-      }
-      catch (IOException e) {
-        // TODO: LATER: decide if leaving nastily named backup files around is necessary. 
-        log.error("Problem updating archive from temporary file! - backup left in '"
-            +backupFile().getAbsolutePath()+"'",e);
-      }
-      // Tidy up if necessary.
-      removeBackup();
-    } else {
-      
-    }
-  }
-  boolean donotdeletebackup=false;
-  /**
-   * called by app to get name of backup if it was made.
-   * If this is called, the caller app *must* delete the backup themselves.
-   * @return null or a valid file object
+   * open original archive file for exclusive (locked) reading.
+   * @throws IOException
    */
-  public File backupFile() {
-    
-    if (!virginArchive) {
-      makeBackup();
-      donotdeletebackup=false; // external reference has been made.
-      return ((original!=null) ? originalBackup : null);
+  private void accessOriginal() throws IOException {
+    if (original!=null && original.exists()) {
+      if (odoclock==null) 
+        odoclock = new SessionFile(original);
+      odoclock.lockFile();
+      if (odoc == null) 
+        odoc = new VamsasArchiveReader(original);
     }
-    return null;
-  }
-  /**
-   * 
-   * @return JarEntry name for the vamsas XML stream in this archive
-   */
-  protected String getDocumentJarEntry() {
-    if (vamsasdocument)
-      return VamsasArchiveReader.VAMSASDOC;
-    return VamsasArchiveReader.VAMSASXML;
   }
   
   /**
-   * @return true if Vamsas Document has been written to archive
-   */
-  protected boolean isDocumentWritten() {
-    if (newarchive==null)
-      log.warn("isDocumentWritten() called for unopened archive.");
-    if (entries!=null) {
-      if (entries.containsKey(getDocumentJarEntry()))
-        return true;
-    }
-    return false;
-  }
-  /**
    * Add unique entry strings to internal JarEntries list.
    * @param entry
    * @return true if entry was unique and was added.
@@ -233,72 +268,17 @@ public class VamsasArchive {
     newarchive.putNextEntry(je);
     return true;
   }
-  
   /**
-   * opens the new archive ready for writing. If the new archive is replacing an existing one, 
-   * then the existing archive will be locked, and the new archive written to a temporary file. 
-   * The new archive will be put in place once close() is called.
-   * @param doclock TODO
-   * @throws IOException
+   * called by app to get name of backup if it was made.
+   * If this is called, the caller app *must* delete the backup themselves.
+   * @return null or a valid file object
    */
-  private void openArchive() throws IOException {
+  public File backupFile() {
     
-    if (newarchive!=null) {
-      log.warn("openArchive() called multiple times.");
-      throw new IOException("Vamsas Archive '"+archive.getAbsolutePath()+"' is already open.");
-    }
-    if (archive==null && (virginArchive || original==null)) {
-      log.warn("openArchive called on uninitialised VamsasArchive object.");
-      throw new IOException("Badly initialised VamsasArchive object - no archive file specified.");
-    }
     if (!virginArchive) {
-      // lock the original
-      accessOriginal();
-      // make a temporary file to write to
-      archive = File.createTempFile(original.getName(), ".new",original.getParentFile());
-    } else {
-      if (archive.exists())
-        log.warn("New archive file name already in use! Possible lock failure imminent?");
-    }
-    
-    if (rchive==null)
-      rchive = new SessionFile(archive);
-    if (!rchive.lockFile()) 
-      throw new IOException("Failed to get lock on file "+archive);
-    newarchive = new JarOutputStream(new BufferedOutputStream(new java.io.FileOutputStream(archive)));  
-    entries = new Hashtable();
-  }
-  /**
-   * Safely initializes the VAMSAS XML document Jar Entry. 
-   * @return Writer to pass to the marshalling function.
-   * @throws IOException if a document entry has already been written. 
-   */
-  public PrintWriter getDocumentOutputStream() throws IOException {
-    if (newarchive==null)
-      openArchive();
-    if (!isDocumentWritten()) {
-      try {
-        if (addValidEntry(getDocumentJarEntry())) 
-          return new PrintWriter(new java.io.OutputStreamWriter(newarchive, "UTF-8"));
-      } catch (Exception e) {
-        log.warn("Problems opening XML document JarEntry stream",e);
-      }
-    } else {
-      throw new IOException("Vamsas Document output stream is already written.");
-    }
-    return null;
-  }
-  /**
-   * Opens and returns the applicationData output stream for the appdataReference string.
-   * @param appdataReference
-   * @return Output stream to write to
-   * @throws IOException
-   */
-  public AppDataOutputStream getAppDataStream(String appdataReference) throws IOException {
-    if (newarchive==null)
-      throw new IOException("Attempt to write to closed VamsasArchive object.");
-    if (addValidEntry(appdataReference)) {
-      return new AppDataOutputStream(newarchive);
+      makeBackup();
+      donotdeletebackup=false; // external reference has been made.
+      return ((original!=null) ? originalBackup : null);
     }
     return null;
   }
@@ -334,37 +314,6 @@ public class VamsasArchive {
   }
   
   /**
-   * recovers the original file's contents from the (temporary) backup. 
-   * @throws Exception if any SessionFile or file removal operations fail.
-   */
-  private void recoverBackup() throws Exception {
-    if (originalBackup!=null) {
-      // backup has been made.
-      // revert from backup and delete it (changing backup filename)
-      if (rchive==null) {
-        rchive = new SessionFile(original);
-      }
-      SessionFile bckup = new SessionFile(originalBackup);
-      
-      rchive.updateFrom(null, bckup); // recover from backup file.
-      bckup.unlockFile();
-      bckup=null;
-      removeBackup();
-    }
-  }
-  /**
-   * forget about any backup that was made - removing it first if it was only temporary.
-   */
-  private void removeBackup() {
-    if (originalBackup!=null) {
-      log.debug("Removing backup in "+originalBackup.getAbsolutePath());
-      if (!donotdeletebackup)
-        if (!originalBackup.delete())
-          log.info("VamsasArchive couldn't remove temporary backup "+originalBackup.getAbsolutePath());
-      originalBackup=null;
-    }
-  }
-  /**
    * only do this if you want to destroy the current file output stream
    *
    */
@@ -390,23 +339,228 @@ public class VamsasArchive {
     original=null;
     entries=null;
   }
+  /**
+   * Tidies up and closes archive, removing any backups that were created.
+   * NOTE: It is up to the caller to delete the original archive backup obtained from backupFile()
+   * TODO: ensure all extant AppDataReference jar entries are transferred to new Jar
+   * TODO: provide convenient mechanism for generating new unique AppDataReferences and adding them to the document
+   */
+  public void closeArchive() throws IOException {
+    if (newarchive!=null) {
+      newarchive.closeEntry();
+      if (!isDocumentWritten())
+        log.warn("Premature closure of archive '"+archive.getAbsolutePath()+"': No document has been written.");
+      newarchive.close();
+      updateOriginal();
+      closeAndReset();
+    } else {
+      log.warn("Attempt to close archive that has not been opened for writing.");
+    }
+  }
+  /**
+   * Opens and returns the applicationData output stream for the appdataReference string.
+   * @param appdataReference
+   * @return Output stream to write to
+   * @throws IOException
+   */
+  public AppDataOutputStream getAppDataStream(String appdataReference) throws IOException {
+    if (newarchive==null)
+      throw new IOException("Attempt to write to closed VamsasArchive object.");
+    if (addValidEntry(appdataReference)) {
+      return new AppDataOutputStream(newarchive);
+    }
+    return null;
+  }
   
-  private final int _TRANSFER_BUFFER=4096*4;
   /**
-   * open original archive file for exclusive (locked) reading.
+   * 
+   * @return JarEntry name for the vamsas XML stream in this archive
+   */
+  protected String getDocumentJarEntry() {
+    if (vamsasdocument)
+      return VamsasArchiveReader.VAMSASDOC;
+    return VamsasArchiveReader.VAMSASXML;
+  }
+  /**
+   * Safely initializes the VAMSAS XML document Jar Entry. 
+   * @return Writer to pass to the marshalling function.
+   * @throws IOException if a document entry has already been written. 
+   */
+  public PrintWriter getDocumentOutputStream() throws IOException {
+    if (newarchive==null)
+      openArchive();
+    if (!isDocumentWritten()) {
+      try {
+        if (addValidEntry(getDocumentJarEntry())) 
+          return new PrintWriter(new java.io.OutputStreamWriter(newarchive, "UTF-8"));
+      } catch (Exception e) {
+        log.warn("Problems opening XML document JarEntry stream",e);
+      }
+    } else {
+      throw new IOException("Vamsas Document output stream is already written.");
+    }
+    return null;
+  }
+  
+  /**
+   * Access original archive if it exists, pass the reader to the client
+   * Note: this is NOT thread safe and a call to closeArchive() will by necessity 
+   * close and invalidate the VamsasArchiveReader object.
+   * @return null if no original archive exists.
+   */
+  public VamsasArchiveReader getOriginalArchiveReader() throws IOException {
+    if (!virginArchive) {
+      accessOriginal();
+      return odoc;
+    }
+    return null;
+  }
+  /**
+   * returns original document's root vamsas elements.
+   * @return
    * @throws IOException
+   * @throws org.exolab.castor.xml.MarshalException
+   * @throws org.exolab.castor.xml.ValidationException
    */
-  private void accessOriginal() throws IOException {
-    if (original!=null && original.exists()) {
-      if (odoclock==null) 
-        odoclock = new SessionFile(original);
-      odoclock.lockFile();
-      if (odoc == null) 
-        odoc = new VamsasArchiveReader(original);
+  public object[] getOriginalRoots() throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException  {
+    return VamsasArchive.getOriginalRoots(this);
+  }
+  public VamsasDocument getVamsasDocument() throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+    if (_doc!=null)
+      return _doc;
+    _doc = getOriginalVamsasDocument(this, getVorba());
+    if (_doc!=null)
+      return _doc;
+    // Create a new document and return it
+    _doc = DocumentStuff.newVamsasDocument(new VAMSAS[] { new VAMSAS()}, 
+        ProvenanceStuff.newProvenance("org.vamsas.simpleclient.VamsasArchive", "Created new empty document")
+        , VersionEntries.latestVersion());
+    return _doc;
+  }
+  /**
+   * @return Returns the current VorbaIdFactory for the archive.
+   */
+  public VorbaIdFactory getVorba() {
+    if (vorba==null)
+      vorba = new SimpleDocument("simpleclient.VamsasArchive");
+    return vorba.getVorba();
+  }
+  /**
+   * @return true if Vamsas Document has been written to archive
+   */
+  protected boolean isDocumentWritten() {
+    if (newarchive==null)
+      log.warn("isDocumentWritten() called for unopened archive.");
+    if (entries!=null) {
+      if (entries.containsKey(getDocumentJarEntry()))
+        return true;
+    }
+    return false;
+  }
+  private void makeBackup() {
+    if (!virginArchive) {
+      if (originalBackup==null && original!=null && original.exists()) {
+        try {
+          accessOriginal();
+          originalBackup = odoclock.backupSessionFile(null, original.getName(), ".bak", original.getParentFile());
+        }
+        catch (IOException e) {
+          log.warn("Problem whilst making a backup of original archive.",e);
+        }
+      }
+    }
+  }
+  /**
+   * opens the new archive ready for writing. If the new archive is replacing an existing one, 
+   * then the existing archive will be locked, and the new archive written to a temporary file. 
+   * The new archive will be put in place once close() is called.
+   * @param doclock TODO
+   * @throws IOException
+   */
+  private void openArchive() throws IOException {
+    
+    if (newarchive!=null) {
+      log.warn("openArchive() called multiple times.");
+      throw new IOException("Vamsas Archive '"+archive.getAbsolutePath()+"' is already open.");
+    }
+    if (archive==null && (virginArchive || original==null)) {
+      log.warn("openArchive called on uninitialised VamsasArchive object.");
+      throw new IOException("Badly initialised VamsasArchive object - no archive file specified.");
+    }
+    if (!virginArchive) {
+      // lock the original
+      accessOriginal();
+      // make a temporary file to write to
+      archive = File.createTempFile(original.getName(), ".new",original.getParentFile());
+    } else {
+      if (archive.exists())
+        log.warn("New archive file name already in use! Possible lock failure imminent?");
+    }
+    
+    if (rchive==null)
+      rchive = new SessionFile(archive);
+    if (!rchive.lockFile()) 
+      throw new IOException("Failed to get lock on file "+archive);
+    newarchive = new JarOutputStream(new BufferedOutputStream(new java.io.FileOutputStream(archive)));  
+    entries = new Hashtable();
+  }
+  public void putVamsasDocument(VamsasDocument doc) throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+    putVamsasDocument(doc, getVorba());
+  }
+  
+  public void putVamsasDocument(VamsasDocument doc, VorbaIdFactory vorba) throws IOException, 
+  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+    VorbaXmlBinder.putVamsasDocument(getDocumentOutputStream(), vorba, doc);
+  }
+  
+  /**
+   * recovers the original file's contents from the (temporary) backup. 
+   * @throws Exception if any SessionFile or file removal operations fail.
+   */
+  private void recoverBackup() throws Exception {
+    if (originalBackup!=null) {
+      // backup has been made.
+      // revert from backup and delete it (changing backup filename)
+      if (rchive==null) {
+        rchive = new SessionFile(original);
+      }
+      SessionFile bckup = new SessionFile(originalBackup);
+      
+      rchive.updateFrom(null, bckup); // recover from backup file.
+      bckup.unlockFile();
+      bckup=null;
+      removeBackup();
     }
   }
   
   /**
+   * forget about any backup that was made - removing it first if it was only temporary.
+   */
+  private void removeBackup() {
+    if (originalBackup!=null) {
+      log.debug("Removing backup in "+originalBackup.getAbsolutePath());
+      if (!donotdeletebackup)
+        if (!originalBackup.delete())
+          log.info("VamsasArchive couldn't remove temporary backup "+originalBackup.getAbsolutePath());
+      originalBackup=null;
+    }
+  } 
+  /**
+   * @param vorba the VorbaIdFactory to use for accessing vamsas objects.
+   */
+  public void setVorba(VorbaIdFactory Vorba) {
+    if (Vorba!=null) {
+      if (vorba==null)
+        vorba = new SimpleDocument(Vorba);
+      else
+        vorba.setVorba(Vorba);
+    } else
+      getVorba();
+  }
+  /**
    * Convenience method to copy over the referred entry from the backup to the new version.
    * Warning messages are raised if no backup exists or the 
    * entry doesn't exist in the backed-up original.
@@ -418,6 +572,7 @@ public class VamsasArchive {
   public boolean transferAppDataEntry(String AppDataReference) throws IOException {
     return transferAppDataEntry(AppDataReference, AppDataReference);
   }
+  
   /**
    * Transfers an AppDataReference from old to new vamsas archive, with a name change.
    * @see transferAppDataEntry(String AppDataReference)
@@ -464,6 +619,7 @@ public class VamsasArchive {
         +AppDataReference+"' as '"+NewAppDataReference+"' ("+count+" bytes)");
     return true;
   }
+  
   /**
    * transfers any AppDataReferences existing in the old document 
    * that haven't already been transferred to the new one
@@ -499,170 +655,31 @@ public class VamsasArchive {
     return transfered;
   }
   /**
-   * Tidies up and closes archive, removing any backups that were created.
-   * NOTE: It is up to the caller to delete the original archive backup obtained from backupFile()
-   * TODO: ensure all extant AppDataReference jar entries are transferred to new Jar
-   * TODO: provide convenient mechanism for generating new unique AppDataReferences and adding them to the document
-   */
-  public void closeArchive() throws IOException {
-    if (newarchive!=null) {
-      newarchive.closeEntry();
-      if (!isDocumentWritten())
-        log.warn("Premature closure of archive '"+archive.getAbsolutePath()+"': No document has been written.");
-      newarchive.close();
-      updateOriginal();
-      closeAndReset();
-    } else {
-      log.warn("Attempt to close archive that has not been opened for writing.");
-    }
-  }
-  /**
-   * Access original archive if it exists, pass the reader to the client
-   * Note: this is NOT thread safe and a call to closeArchive() will by necessity 
-   * close and invalidate the VamsasArchiveReader object.
-   * @return null if no original archive exists.
+   * called after archive is written to put file in its final place
    */
-  public VamsasArchiveReader getOriginalArchiveReader() throws IOException {
+  private void updateOriginal() {
     if (!virginArchive) {
-      accessOriginal();
-      return odoc;
-    }
-    return null;
-  }
-  /**
-   * returns original document's root vamsas elements.
-   * @return
-   * @throws IOException
-   * @throws org.exolab.castor.xml.MarshalException
-   * @throws org.exolab.castor.xml.ValidationException
-   */
-  public object[] getOriginalRoots() throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException  {
-    return VamsasArchive.getOriginalRoots(this);
-  }
-  /**
-   * Access original document if it exists, and get VAMSAS root objects.
-   * @return vector of vamsas roots from original document
-   * @throws IOException
-   */
-  public static object[] getOriginalRoots(VamsasArchive ths) throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
-    VamsasArchiveReader oReader = ths.getOriginalArchiveReader();
-    if (oReader!=null) {
-      
-      if (oReader.isValid()) {
-        InputStreamReader vdoc = new InputStreamReader(oReader.getVamsasDocumentStream());
-        VamsasDocument doc = VamsasDocument.unmarshal(vdoc);
-        if (doc!=null) 
-          return doc.getVAMSAS();
-        // TODO ensure embedded appDatas are garbage collected to save memory
-      } else {
-        InputStream vxmlis = oReader.getVamsasXmlStream();
-        if (vxmlis!=null) { // Might be an old vamsas file.
-          BufferedInputStream ixml = new BufferedInputStream(oReader.getVamsasXmlStream());
-          InputStreamReader vxml = new InputStreamReader(ixml);
-          VAMSAS root[] = new VAMSAS[1];
-          root[0] = VAMSAS.unmarshal(vxml);
-          if (root[0]!=null)
-            return root;
-        }
+      // make sure original document really is backed up and then overwrite it.
+      if (odoc!=null) {
+        // try to shut the odoc reader.
+        odoc.close();
+        odoc = null;
       }
+      // Make a backup if it isn't done already
+      makeBackup();
+      try {
+        // copy new Archive data that was writen to a temporary file
+        odoclock.updateFrom(null, rchive);
+      }
+      catch (IOException e) {
+        // TODO: LATER: decide if leaving nastily named backup files around is necessary. 
+        log.error("Problem updating archive from temporary file! - backup left in '"
+            +backupFile().getAbsolutePath()+"'",e);
+      }
+      // Tidy up if necessary.
+      removeBackup();
+    } else {
+      
     }
-    return null;
-  }
-  protected SimpleDocument vorba = null;
-  
-  /**
-   * @return Returns the current VorbaIdFactory for the archive.
-   */
-  public VorbaIdFactory getVorba() {
-    if (vorba==null)
-      vorba = new SimpleDocument("simpleclient.VamsasArchive");
-    return vorba.getVorba();
-  }
-  
-  /**
-   * @param vorba the VorbaIdFactory to use for accessing vamsas objects.
-   */
-  public void setVorba(VorbaIdFactory Vorba) {
-    if (Vorba!=null) {
-      if (vorba==null)
-        vorba = new SimpleDocument(Vorba);
-      else
-        vorba.setVorba(Vorba);
-    } else
-      getVorba();
-  }
-  
-  /**
-   * Access and return current vamsas Document, if it exists, or create a new one 
-   * (without affecting VamsasArchive object state - so is NOT THREAD SAFE)
-   * TODO: possibly modify internal state to lock low-level files 
-   * (like the IClientDocument interface instance constructer would do) 
-   * @see org.vamsas.simpleclient.VamsasArchive.getOriginalVamsasDocument for additional caveats
-   * 
-   * @return
-   * @throws IOException
-   * @throws org.exolab.castor.xml.MarshalException
-   * @throws org.exolab.castor.xml.ValidationException
-   */
-  private VamsasDocument _doc=null; 
-  public VamsasDocument getVamsasDocument() throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
-    if (_doc!=null)
-      return _doc;
-    _doc = getOriginalVamsasDocument(this, getVorba());
-    if (_doc!=null)
-      return _doc;
-    // Create a new document and return it
-    _doc = DocumentStuff.newVamsasDocument(new VAMSAS[] { new VAMSAS()}, 
-        ProvenanceStuff.newProvenance("org.vamsas.simpleclient.VamsasArchive", "Created new empty document")
-        , VersionEntries.latestVersion());
-    return _doc;
-  }
-  /**
-   * Access the original vamsas document for a VamsasArchive class, and return it.
-   * Users of the VamsasArchive class should use the getVamsasDocument method to retrieve
-   * the current document - only use this one if you want the 'backup' version.
-   * TODO: catch OutOfMemoryError - they are likely to occur here.
-   * NOTE: vamsas.xml datastreams are constructed as 'ALPHA_VERSION' vamsas documents.
-   * @param ths
-   * @return null if no document exists.
-   * @throws IOException
-   * @throws org.exolab.castor.xml.MarshalException
-   * @throws org.exolab.castor.xml.ValidationException
-   */
-  public static VamsasDocument getOriginalVamsasDocument(VamsasArchive ths) throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
-    return VamsasArchive.getOriginalVamsasDocument(ths, null);
-  }
-  
-  /**
-   * Uses VorbaXmlBinder to retrieve the VamsasDocument from the original archive referred to by ths
-   * @param ths
-   * @param vorba
-   * @return
-   * @throws IOException
-   * @throws org.exolab.castor.xml.MarshalException
-   * @throws org.exolab.castor.xml.ValidationException
-   */
-  public static VamsasDocument getOriginalVamsasDocument(VamsasArchive ths, VorbaIdFactory vorba) throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
-    VamsasArchiveReader oReader = ths.getOriginalArchiveReader();
-    if (oReader!=null) {
-      ths.setVorba(vorba);
-      return ths.vorba.getVamsasDocument(oReader);
-    }
-    // otherwise - there was no valid original document to read.
-    return null;    
-  }
-  
-  public void putVamsasDocument(VamsasDocument doc) throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
-    putVamsasDocument(doc, getVorba());
-  }
-  public void putVamsasDocument(VamsasDocument doc, VorbaIdFactory vorba) throws IOException, 
-  org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
-    VorbaXmlBinder.putVamsasDocument(getDocumentOutputStream(), vorba, doc);
   }
 }
index dbff158..6d5f13c 100644 (file)
@@ -19,6 +19,7 @@ import org.vamsas.objects.core.LockFileDescriptor;
 /**
  * low level vamsas document management routines
  * analogous to ClientsFile
+ * Grew out of io tests on VamsasArchive class in org.vamsas.test.simpleclient.VamsasArchive
  * This class is not thread safe.
  * @author jimp
  *
@@ -64,8 +65,7 @@ public class VamsasFile extends SessionFile {
    * @return reader for vamsasdocument.xml enrty
    */
   public Lock getLock() {
-    while (!lockFile())
-      ;
+    lockFile();
     return fileLock;
   }
   public void unLock() {
index 8340413..c1c7422 100644 (file)
@@ -4,10 +4,12 @@ import java.io.File;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.vamsas.client.ClientHandle;
 import org.vamsas.client.simpleclient.FileWatcher;
 import org.vamsas.client.simpleclient.Lock;
 import org.vamsas.client.simpleclient.SimpleDocument;
 import org.vamsas.client.simpleclient.VamsasArchiveReader;
+import org.vamsas.client.simpleclient.VamsasFile;
 import org.vamsas.objects.core.VamsasDocument;
 /**
  * demo of archive watching process - should mimic the clientsfileTest watcher/monitor process.
@@ -15,37 +17,84 @@ import org.vamsas.objects.core.VamsasDocument;
  *
  */
 public class ArchiveWatcher {
-  private static Log log = LogFactory.getLog(ArchiveWatcher.class); 
+  private static Log log = LogFactory.getLog(ArchiveWatcher.class);
+  private static CommandProcessor cproc=new CommandProcessor();
+  static {
+    cproc.addCommand("new", 0, "no args");
+    cproc.addCommand("delete", 0, "no args");    
+    cproc.addCommand("watch", 0, "no args");
+    cproc.addCommand("file", 1, "Need vamsas archive as argument.");    
+  }
+  
   public static void main(String[] args) {
     try {
+      
       if (args!=null && args.length>0) {
-        
         File archive = new File(args[0]);
         log.info("Watching file "+args[0]);
-/*        if (!archive.exists())
-          archive.createNewFile();
- */       // watch the new file... - taken straight from ClientsFileTest
-        FileWatcher w = new FileWatcher(archive);
-        while (true) {
-          
-          // get watcher's lock to ensure state change is fixed for retrieval
-          Lock chlock = w.getChangedState();
-          if (chlock != null)
-            if (archive.length()>0) {
-              log.info("Noticed Testing update: ");
-              VamsasArchiveReader vreader = new VamsasArchiveReader(archive);
-              SimpleDocument sdoc = new SimpleDocument("testing vamsas watcher");
-              try {
-                VamsasDocument d = sdoc.getVamsasDocument(vreader);
-                if (d!=null) {
-                  ArchiveReports.reportDocument(d, vreader, false, System.out);
+        int argc=1;
+        while (argc < args.length) {
+          // vars needed for operations
+          ClientHandle ch;
+          int com = cproc.getCommand(args, argc);
+          argc++;
+          switch (com) {
+          case 0:
+            // new
+            log.info("Doing locked deletion and new-file creation.");
+            {
+              if (!archive.exists())
+                archive.createNewFile();
+              VamsasFile sf = new VamsasFile(archive);
+              Lock l = sf.getLock();
+              archive.delete();
+              archive.createNewFile();
+              sf.unLock();
+            }
+            break;
+          case 1:
+            // delete
+            log.info("Deleting "+archive+" without locking it first.");
+            archive.delete();
+            break;
+          case 2:
+            // watch
+            log.info("Endlessly Watching file "+archive);
+            /*        if (!archive.exists())
+                      archive.createNewFile();
+             */       // watch the new file... - taken straight from ClientsFileTest
+            FileWatcher w = new FileWatcher(archive);
+            while (true) {              
+              // get watcher's lock to ensure state change is fixed for retrieval
+              Lock chlock = w.getChangedState();
+              if (chlock != null) {
+                log.info("Got lock on "+archive+(archive.exists() ? " exists l="+archive.length() : "(non existant)"));
+                if (archive.length()>0) {
+                  VamsasArchiveReader vreader = new VamsasArchiveReader(archive);
+                  SimpleDocument sdoc = new SimpleDocument("testing vamsas watcher");
+                  try {
+                    VamsasDocument d = sdoc.getVamsasDocument(vreader);
+                    if (d!=null) {
+                      ArchiveReports.reportDocument(d, vreader, false, System.out);
+                    }
+                    System.out.println("Update at "+System.currentTimeMillis()+"\n\n********************************************************\n");
+                  } catch (Exception e) {
+                    log.error("Unmarshalling failed.",e);
+                  }
+                  vreader.close();
+                  w.setState();
                 }
-                System.out.println("Update at "+System.currentTimeMillis()+"\n\n********************************************************\n");
-              } catch (Exception e) {
-                log.error("Unmarshalling failed.",e);
               }
-              vreader.close();
             }
+            // break;
+          case 3: // set file
+            archive = new File(args[argc++]);
+            break;
+          case 4:
+            break;
+            default:
+              log.warn("Unknown command  + "+args[argc++]);
+          }
         }
       }
     } catch (Exception e) {
index 354f9af..9b242c0 100644 (file)
@@ -128,9 +128,9 @@ public class VamsasArchive {
       log.info("Now writing new Archive into "+newf.getAbsolutePath());
       org.vamsas.client.simpleclient.VamsasArchive va=null;
       { // hold lock over deletion and write of new archive.
-        Lock wlock = sfile.getLock();
-        newf.delete(); // clear out old file.
-        va = new org.vamsas.client.simpleclient.VamsasArchive(newf, true, wlock);
+        //Lock wlock = sfile.getLock();
+        //newf.delete(); // clear out old file.
+        va = new org.vamsas.client.simpleclient.VamsasArchive(newf, true, true); // , sfile);
         // open another and...
         ApplicationData appdata = makeDemoAppdata(va, 
             "org.vamsas.test.simpleclient.VamsasArchive", "arnold Bugger esq", "disOrganised");
@@ -146,7 +146,7 @@ public class VamsasArchive {
       {
         Lock lock=sfile.getLock();
         if (lock==null)
-          while ((lock=sfile.getLock())!=null)
+          while ((lock=sfile.getLock())==null)
             log.info("Waiting for lock.");
         VamsasArchiveReader vreader = new VamsasArchiveReader(newf);
         SimpleDocument sdoc = new SimpleDocument("testing new vamsas write");
@@ -160,9 +160,9 @@ public class VamsasArchive {
         log.info("Successfully cancelled.");
       else
         log.info("Didn't cancel.");
-      
+      long t=System.currentTimeMillis()+200; while (t>System.currentTimeMillis());
       log.info("Now testing archive update.");
-      va = new org.vamsas.client.simpleclient.VamsasArchive(newf, true);
+      va = new org.vamsas.client.simpleclient.VamsasArchive(newf, false, true, sfile);
       doc = va.getVamsasDocument();
       doc.addVAMSAS(Core.getDemoVamsas());
       doc.addApplicationData(makeDemoAppdata(va, 
@@ -177,7 +177,7 @@ public class VamsasArchive {
       {
         Lock lock=sfile.getLock();
         if (lock==null)
-          while ((lock=sfile.getLock())!=null)
+          while ((lock=sfile.getLock())==null)
             log.info("Waiting for lock.");
         VamsasArchiveReader vreader = new VamsasArchiveReader(newf);
         SimpleDocument sdoc = new SimpleDocument("testing vamsas update");