From 25174cde26bdba19676150341182d8dd75e31f4e Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 20 Jan 2006 12:00:23 +0000 Subject: [PATCH] added overwrite flag to VamsasArchive writer class (avoids loss of locks on file deletion) git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@154 be28352e-c001-0410-b1a7-c7978e42abec --- .../vamsas/client/simpleclient/VamsasArchive.java | 727 ++++++++++---------- src/org/vamsas/client/simpleclient/VamsasFile.java | 4 +- .../vamsas/test/simpleclient/ArchiveWatcher.java | 95 ++- .../vamsas/test/simpleclient/VamsasArchive.java | 14 +- 4 files changed, 453 insertions(+), 387 deletions(-) diff --git a/src/org/vamsas/client/simpleclient/VamsasArchive.java b/src/org/vamsas/client/simpleclient/VamsasArchive.java index ea11a81..6e86407 100644 --- a/src/org/vamsas/client/simpleclient/VamsasArchive.java +++ b/src/org/vamsas/client/simpleclient/VamsasArchive.java @@ -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 archive + * @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); } } diff --git a/src/org/vamsas/client/simpleclient/VamsasFile.java b/src/org/vamsas/client/simpleclient/VamsasFile.java index dbff158..6d5f13c 100644 --- a/src/org/vamsas/client/simpleclient/VamsasFile.java +++ b/src/org/vamsas/client/simpleclient/VamsasFile.java @@ -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() { diff --git a/src/org/vamsas/test/simpleclient/ArchiveWatcher.java b/src/org/vamsas/test/simpleclient/ArchiveWatcher.java index 8340413..c1c7422 100644 --- a/src/org/vamsas/test/simpleclient/ArchiveWatcher.java +++ b/src/org/vamsas/test/simpleclient/ArchiveWatcher.java @@ -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) { diff --git a/src/org/vamsas/test/simpleclient/VamsasArchive.java b/src/org/vamsas/test/simpleclient/VamsasArchive.java index 354f9af..9b242c0 100644 --- a/src/org/vamsas/test/simpleclient/VamsasArchive.java +++ b/src/org/vamsas/test/simpleclient/VamsasArchive.java @@ -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"); -- 1.7.10.2