From ae10f862d226e3dec3fb836246959a3827608445 Mon Sep 17 00:00:00 2001 From: jprocter Date: Tue, 29 Nov 2005 14:20:41 +0000 Subject: [PATCH] untested vamsasArchive class with additional method for transferring data between session files. git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@98 be28352e-c001-0410-b1a7-c7978e42abec --- .../vamsas/client/simpleclient/SessionFile.java | 34 +++- .../vamsas/client/simpleclient/VamsasArchive.java | 190 ++++++++++++-------- 2 files changed, 144 insertions(+), 80 deletions(-) diff --git a/src/org/vamsas/client/simpleclient/SessionFile.java b/src/org/vamsas/client/simpleclient/SessionFile.java index b43b1a9..e7b450f 100644 --- a/src/org/vamsas/client/simpleclient/SessionFile.java +++ b/src/org/vamsas/client/simpleclient/SessionFile.java @@ -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()); + } } diff --git a/src/org/vamsas/client/simpleclient/VamsasArchive.java b/src/org/vamsas/client/simpleclient/VamsasArchive.java index c3dc225..8ef72f0 100644 --- a/src/org/vamsas/client/simpleclient/VamsasArchive.java +++ b/src/org/vamsas/client/simpleclient/VamsasArchive.java @@ -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 { -- 1.7.10.2