untested vamsasArchive class with additional method for transferring data between...
authorjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 29 Nov 2005 14:20:41 +0000 (14:20 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 29 Nov 2005 14:20:41 +0000 (14:20 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@98 be28352e-c001-0410-b1a7-c7978e42abec

src/org/vamsas/client/simpleclient/SessionFile.java
src/org/vamsas/client/simpleclient/VamsasArchive.java

index b43b1a9..e7b450f 100644 (file)
@@ -5,6 +5,10 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.Log4jFactory;
+
 /**
  * Basic methods for classes handling locked IO on files 
  * monitored by all (simpleclient) clients in a vamsas session.
@@ -12,7 +16,7 @@ import java.io.IOException;
  *
  */
 public class SessionFile {
-
+  private static Log log = LogFactory.getLog(SessionFile.class);
   protected File sessionFile;
   protected Lock fileLock = null;
 
@@ -55,8 +59,7 @@ public class SessionFile {
         return fileLock.isLocked();
       }
     } else
-      throw new Error(
-          "org.vamsas.client.simpleclient.SessionFile.lockFile called for non-initialised SessionFile!");
+      log.error("lockFile called for non-initialised SessionFile!");
   
     // no lock possible
     return false;
@@ -92,17 +95,30 @@ public class SessionFile {
             fileLock.rafile.length());
         tos.close();
       } catch (FileNotFoundException e1) {
-        System.err.println("Can't create temp file for "+sessionFile.getName());
-        e1.printStackTrace(System.err);
+        log.warn("Can't create temp file for "+sessionFile.getName(),e1);
         tempfile=null;
       } catch (IOException e1) {
-        System.err
-            .println("Error when copying content to temp file for "+sessionFile.getName());
-        e1.printStackTrace(System.err);
+        log.warn("Error when copying content to temp file for "+sessionFile.getName(),e1);
         tempfile=null;
       }
     }
     return tempfile;
   }
-
+  /**
+   * Replaces data in sessionFile with data from file handled by another sessionFile
+   * passes up any exceptions.
+   * @param newData source for new data
+   */
+  protected void updateFrom(Lock extantLock, SessionFile newData) throws IOException {
+    log.debug("Updating "+sessionFile.getAbsolutePath()+" from "+newData.sessionFile.getAbsolutePath());
+    if (newData==null)
+      throw new IOException("Null newData object.");
+    if (newData.sessionFile!=null)
+      throw new IOException("Null SessionFile in newData.");
+      
+    lockFile(extantLock);  
+    newData.lockFile();
+    fileLock.rafile.getChannel().transferFrom(newData.fileLock.rafile.getChannel(), 0, 
+        newData.fileLock.rafile.length());
+  }
 }
index c3dc225..8ef72f0 100644 (file)
@@ -25,17 +25,45 @@ import org.apache.commons.logging.LogFactory;
  */
 public class VamsasArchive {
   private static Log log = LogFactory.getLog(VamsasArchive.class);
-  java.io.File archive;
+  /**
+   * destination of new archive data
+   */
+  java.io.File archive=null;
+  /**
+   * locked IO handler for new archive file
+   */
   SessionFile rchive=null; 
+  /**
+   * original archive file that is to be updated
+   */
   java.io.File original=null;
+  /**
+   * original archive IO handler
+   */
   SessionFile odoclock = null;
+  /**
+   * Original archive reader class
+   */
   VamsasArchiveReader odoc = null;
-  boolean vamsasdocument=true;  // make a document archive (rather than a vamsas.xml archive)
+  /**
+   * true if a real vamsas document is being written.
+   */
+  boolean vamsasdocument=true;
+  /**
+   * Output stream for archived data
+   */
   JarOutputStream newarchive=null;
+  /**
+   * JarEntries written to archive
+   */
   Hashtable entries = null;
-  
+  /**
+   * true if we aren't just updating an archive
+   */
+  private boolean virginArchive=false;
   /**
    * Create a new vamsas archive
+   * nb. No file locks are made until open() is called.
    * @param archive - file spec for new vamsas archive
    * @param vamsasdocument true if archive is to be a fully fledged vamsas document archive
    */
@@ -48,20 +76,56 @@ public class VamsasArchive {
     this.vamsasdocument = vamsasdocument;
     if (archive.exists()) {
       this.original = archive;
-      this.archive = null;
-      // make the archive temp file when the open method is called
+      this.archive = null;       // archive will be a temp file when the open method is called
+      virginArchive=false;
     } else {
       this.original = null;
-      this.archive = archive; // write directly to the new archive
+      this.archive = archive;
+      virginArchive = true;
     }
   }
   /**
-   * called by app to determine if a backup will be made or not.
-   * @return
+   * name of backup of existing archive that has been updated/overwritten.
+   */
+  File originalBackup = null;
+  
+  private void makeBackup() {
+    if (!virginArchive) {
+      if (originalBackup==null && original!=null && original.exists()) {
+        try {
+          accessBackup();
+          originalBackup = odoclock.backupSessionFile(null, original.getName(), ".bak", original.getParentFile());
+          // rchive.fileLock.rafile.getChannel().truncate(0);
+        }
+        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
+   * TODO: FINISH original should have sessionFile, and archive should also have sessionFile
+   */
+  private void updateOriginal() {
+    if (original!=null) {
+      if (!virginArchive) {
+        if (!archive.getAbsolutePath().equals(original)) {
+          if (originalBackup==null) 
+            makeBackup();
+        }
+      } else {
+        archive.renameTo(original);
+      }
+    }
+  }
+  /**
+   * called by app to get name of backup if it was made.
+   * @return null or a valid file object
    */
   public File backupFile() {
     
-    if (original!=null) {
+    if (virginArchive) {
       makeBackup();
       return ((original==null) ? originalBackup : null);
     
@@ -74,6 +138,9 @@ public class VamsasArchive {
       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.");
@@ -110,58 +177,34 @@ public class VamsasArchive {
     return true;
   }
   
-  File originalBackup = null;
-  
-  private void makeBackup() {
-    if (originalBackup!=null && original!=null && original.exists()) {
-      try {
-        accessBackup();
-        originalBackup = odoclock.backupSessionFile(null, original.getName(), ".bak", original.getParentFile());
-        // rchive.fileLock.rafile.getChannel().truncate(0);
-      }
-      catch (IOException e) {
-        log.warn("Problem whilst making a backup of original archive.",e);
-      }
-    }
-  }
   File tempoutput = null;
   SessionFile trchive = null;
   private void openArchive() throws IOException {
     
-    if (newarchive!=null)
+    if (newarchive!=null) {
+      log.warn("openArchive() called multiple times.");
       throw new IOException("Vamsas Archive '"+archive.getAbsolutePath()+"' is already open.");
-
+    }
+    
     if (archive==null) {
       if (original==null) {
-        throw new IOException("Badly initialised VamsasArchive object - null archive file.");
+        log.warn("openArchive called on uninitialised VamsasArchive object.");
+        throw new IOException("Badly initialised VamsasArchive object - no archive file specified.");
       }
+      // lock the original
+      accessBackup();
       // make a temporary file to write to 
-      // TODO: finish
-        
-    } else {
-      // tempfile is real archive
+      archive = File.createTempFile(original.getName(), "new");
+      
     }
     
-    /* if (archive.exists()) 
-      if (original==null) {
-        original = rchive.backupSessionFile(null, archive.getName(), ".bak", archive.getParentFile());
-        rchive.fileLock.rafile.getChannel().truncate(0);
-      } else
-        throw new IOException("Backup of current VamsasArchive already exists. Fix this BUG");
-    */
-    
+    rchive = new SessionFile(archive);
     rchive.lockFile();
     newarchive = new JarOutputStream(new BufferedOutputStream(new java.io.FileOutputStream(archive)));  
     entries = new Hashtable();
   }
   
   /**
-    if (archive.exists()) 
-      if (original==null) {
-        original = rchive.backupSessionFile(null, archive.getName(), ".bak", archive.getParentFile());
-        rchive.fileLock.rafile.getChannel().truncate(0);
-      } else
-    
    * 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. 
@@ -199,39 +242,43 @@ public class VamsasArchive {
   
   /**
    * Stops any current write to archive, and reverts to the backup if it exists.
-   * 
+   * All existing locks on the original will be released.
    */
   public boolean cancelArchive() {
     if (newarchive!=null) {
       try { 
         newarchive.close();
       } catch (Exception e) {};
-      if (original!=null) {
-        if (rchive!=null) {
-          try {
-            // recover from backup file.
-            rchive.fileLock.rafile.getChannel().truncate(0);
-            SessionFile bck = new SessionFile(original);
-            if (bck.lockFile()) {
-              rchive.fileLock.rafile.getChannel().transferFrom(
-                  bck.fileLock.rafile.getChannel(), 
-                  0, bck.fileLock.rafile.getChannel().size());
-              bck.unlockFile();
-              closeAndReset();
-              return true;
-            } else {
-              log.warn("Could not get lock on backup file to recover");
-            }
-          }
-          catch (Exception e) {
-            log.warn("Problems when trying to cancel Archive "+archive.getAbsolutePath(), e);
-            return false;
+      if (!virginArchive) {
+        // then there is something to recover.
+        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);
+          
+            try {
+              rchive.updateFrom(null,bckup); // recover from backup file.
+              bckup.unlockFile();
+              bckup=null;
+              originalBackup.delete();
+            }
+            catch (Exception e) {
+              log.warn("Problems when trying to cancel Archive "+archive.getAbsolutePath(), e);
+              return false;
+            }
         }
-        log.fatal("Attempt to backup from Archive Backup without valid write lock! ('"+archive.getAbsolutePath()+"') - BUG!");
-      }
+        // original is untouched
+        // just delete temp files
+        
+        }
+    } else {
+      log.info("cancelArchive called before archive("+original.getAbsolutePath()+") has been opened!");
     }
-    return false;
+    closeAndReset();
+    return true;
   }
   
   /**
@@ -246,7 +293,7 @@ public class VamsasArchive {
         odoc.close();
         odoc=null;
       }
-      original.delete();
+      archive.delete();
       if (odoclock!=null) {
         odoclock.unlockFile();
         odoclock = null;
@@ -271,6 +318,7 @@ public class VamsasArchive {
         odoc = new VamsasArchiveReader(original);
     }
   }
+
   /**
    * 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 
@@ -320,13 +368,13 @@ public class VamsasArchive {
   
   /**
    * Tidies up and closes archive, removing any backups that were created.
-   * NOTE: It is up to the caller to 
+   * NOTE: It is up to the caller to delete the original archive backup obtained from backupFile()
    */
   public void closeArchive() throws IOException {
     if (newarchive!=null) {
       newarchive.closeEntry();
       if (!isDocumentWritten())
-        log.warn("Premature closure of archive '"+archive.getAbsolutePath()+"'");
+        log.warn("Premature closure of archive '"+archive.getAbsolutePath()+"': No document has been written.");
       newarchive.close();
       closeAndReset();
     } else {