// first write for this application - add a new section in document
ApplicationData appd = scappd.appsGlobal = new ApplicationData();
appd.setName(client.getClientName());
- appd.setUrn(client.getClientUrn());
+ // appd.setUrn(client.getClientUrn());
appd.setVersion(client.getVersion());
doc.addApplicationData(appd);
// embed or jarEntry ? - for now only jarEntry's are dealt with.
*/
protected int addClient(ClientHandle me, boolean disambiguate) {
int newclient = 0;
+ int tries=5;
+ while (tries-->0 && !lockFile())
+ try { Thread.sleep(1); } catch (Exception e){};
if (lockFile()) {
ClientHandle[] clients = retrieveClientHandles();
if (me.getClientUrn()==null) {
--- /dev/null
+package org.vamsas.client.simpleclient;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+public class FileLock extends Lock {
+ File _lock = null;
+ protected static String _LockSuffix="lck";
+ /**
+ * call to clear up a filelock file after its been made
+ *
+ */
+ private void tidy() {
+ if (_lock!=null) {
+ _lock.delete();
+ _lock=null;
+ }
+ }
+ /**
+ * @param lockfile
+ */
+ public FileLock(File lockfile) {
+ super(lockfile);
+ // try and get a lock.
+ try {
+ _lock = new File(lockfile.getParentFile(), lockfile.getName()+"."+_LockSuffix);
+ if (_lock.exists() || !_lock.createNewFile()) {
+ log.debug("Failed to get lock for "+lockfile+" using lockfile "+_lock);
+ _lock=null;
+ return;
+ }
+ _lock.deleteOnExit(); // safe - all locks should be removed on finalization.
+ // create target file ready to be written to if necessary.
+ if (!lockfile.exists())
+ if (!lockfile.createNewFile()) {
+ log.warn("Failed to create locked file "+lockfile);
+ return;
+ }
+ openRaFile();
+ } catch (FileNotFoundException e) {
+ //
+ log.debug("FileLock failed with target="+lockfile+" and lockfile suffix of "+_LockSuffix);
+ //log.error("Error! Couldn't create a lockfile at "
+ // + lockfile.getAbsolutePath(), e);
+ } catch (IOException e) {
+ log.error("Error! Problems with IO when creating a lock on "
+ + lockfile.getAbsolutePath(),e);
+ }
+ }
+
+ private boolean openRaFile() throws IOException {
+ if (target==null)
+ return false;
+ if (_lock==null || !_lock.exists())
+ return false;
+ if (rafile==null)
+ rafile=new RandomAccessFile(target,"rw");
+ return (rafile.getChannel()!=null) && rafile.getChannel().isOpen();
+ }
+
+ public boolean isLocked() {
+ if (_lock != null) {
+ if (_lock.exists())
+ return true;
+ _lock=null;
+ if (log.isDebugEnabled())
+ log.debug("Lockfile "+_lock+" unexpectedly deleted ?");
+ }
+ return false;
+ }
+
+ public void release() {
+ release(true);
+ }
+
+ public void release(boolean closeChannel) {
+ if (_lock==null)
+ return;
+ if (closeChannel) {
+ if (rafile!=null)
+ try {
+ rafile.close();
+ } catch (Exception e) {
+ log.debug("Unexpected exception whilst closing RandomAccessFile on "+target, e);
+ }
+ rafile=null;
+ }
+ tidy();
+ }
+
+ public FileInputStream getFileInputStream(boolean atStart) throws IOException {
+ if (!isLocked())
+ return null;
+ openRaFile();
+ if (atStart)
+ rafile.seek(0);
+ return new FileInputStream(rafile.getFD());
+ }
+
+
+ public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
+ if (!isLocked())
+ return null;
+ openRaFile();
+ if (clear)
+ rafile.setLength(0);
+ else
+ rafile.seek(rafile.length());
+ return new LockedFileOutputStream(rafile.getFD());
+ }
+
+
+ public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
+ FileOutputStream fos = getFileOutputStream(clear);
+ if (fos!=null)
+ return new BufferedOutputStream(fos);
+ return null;
+ }
+
+ protected void finalize() throws Throwable {
+ release(true); // we explicitly lose the lock here.
+ super.finalize();
+ }
+
+}
if (subjectLock!=null) {
subjectLock.release();
}
- subjectLock = new Lock(subject);
+ subjectLock = LockFactory.getLock(subject);
if (subjectLock.isLocked()) {
return false;
}
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
+import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.nio.channels.FileLock;
import org.apache.commons.logging.LogFactory;
/**
* transient object representing a file lock
* This lock should hold for all processes interacting in a session.
- * TODO: currently implemented for local filesystem style locking - need a fallback mechanism for systems without file locks.
* @author jimp
- *
*/
-public class Lock {
- org.apache.commons.logging.Log log = LogFactory.getLog(Lock.class);
- FileLock lock = null;
- RandomAccessFile rafile=null;
+public abstract class Lock {
+ protected org.apache.commons.logging.Log log = LogFactory.getLog(Lock.class);
+ File target = null; // The file that is being locked
+ protected RandomAccessFile rafile=null;
+
/**
* creates a valid Lock (test with <method>isLocked</method>)
* if a lock could be obtained for <param>lockfile</param>
* @param lockfile
*/
- public Lock(java.io.File lockfile) {
- // try and get a lock.
- lock = null;
-
- try {
- if (!lockfile.exists())
- if (!lockfile.createNewFile()) {
- log.warn("Failed to create locked file "+lockfile);
- return;
- }
-
- lock = (rafile=new RandomAccessFile(lockfile,"rw")).getChannel().tryLock();
- if (lock==null || !lock.isValid()) {
- // failed to get lock. Close the file channel
- log.debug("failed to get lock for "+lockfile);
- rafile.getChannel().close();
- lock=null;
- }
- } catch (FileNotFoundException e) {
- //
- log.debug("Lock failed - normal behaviour for windows locking.");
- //log.error("Error! Couldn't create a lockfile at "
- // + lockfile.getAbsolutePath(), e);
- } catch (IOException e) {
- log.error("Error! Problems with IO when creating a lock on "
- + lockfile.getAbsolutePath(),e);
- }
- }
-
- boolean isLocked() {
- if (lock != null && lock.isValid()) {
- return true;
- }
- return false;
+ protected Lock(java.io.File lockfile) {
+ target = lockfile;
}
- public void release() {
- release(true);
- }
- public void release(boolean closeChannel) {
- try {
- // channel.close should be called before release() for rigourous locking.
- if (rafile!=null && rafile.getChannel()!=null) {
- if (rafile.getChannel().isOpen()) {
- if (closeChannel && rafile.getChannel().isOpen())
- rafile.getChannel().close();
- if (lock!=null && lock.isValid())
- lock.release();
- }
- }
- } catch (IOException e) {
- log.warn("Whilst releasing lock",e);
- }
- lock=null;
- rafile=null;
- }
-
+ /**
+ *
+ * @return true if lock is held on the target
+ */
+ public abstract boolean isLocked();
+ /**
+ * release lock and close all managed channels to file
+ *
+ */
+ public abstract void release();
+ /**
+ * optionally close the open random access channel on the file when releasing lock
+ * @param closeChannel
+ */
+ public abstract void release(boolean closeChannel);
+
/**
* gets Locked Stream for reading from
* @param atStart true to start reading at beginning of file.
* @return null if file not locked
* @throws IOException
*/
- public FileInputStream getFileInputStream(boolean atStart) throws IOException {
- if (!isLocked())
- return null;
- if (atStart)
- rafile.seek(0);
- return new FileInputStream(rafile.getFD());
- }
+ public abstract FileInputStream getFileInputStream(boolean atStart) throws IOException;
+
/**
* gets Locked stream to write to
* FileInput always starts at the *end* of the file (after any truncation)
* @return null if file is not locked
* @throws IOException
*/
- public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
- if (!isLocked())
- return null;
- if (clear)
- rafile.setLength(0);
- rafile.seek(rafile.length());
- return new LockedFileOutputStream(rafile.getFD());
- }
+ public abstract FileOutputStream getFileOutputStream(boolean clear) throws IOException;
/**
* return buffered output stream to locked file.
* @param clear - true means file is truncated to 0 length before writing
* @return
*/
- public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
- FileOutputStream fos = getFileOutputStream(clear);
- if (fos!=null)
- return new BufferedOutputStream(fos);
- return null;
+ public abstract BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException;
+
+ protected void finalize() throws Throwable {
+ target=null;
}
-
/**
* return buffered input stream for locked file.
* @param atStart - true means read from begining of file
return new BufferedInputStream(fis);
return null;
}
- /* Explicitly release lock (probably don't need to do this!)
- * @see java.lang.Object#finalize()
- */
- protected void finalize() throws Throwable {
- release(true); // we explicitly lose the lock here.
- // log.debug("lock closing through garbage collection ?");
- super.finalize();
- }
-
}
--- /dev/null
+package org.vamsas.client.simpleclient;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class LockFactory {
+ protected static Log log = LogFactory.getLog(LockFactory.class);
+ public static int locktype=0; // use file lock by default
+ public static String[] locktypes = {"file","native"};
+ {
+ String lockt = System.getProperty("vamsas.locktype");
+ if (lockt!=null) {
+ int i,j;
+ for (i=0, j=locktypes.length; i<j && locktypes[i].equalsIgnoreCase(lockt); i++)
+ ;
+ if (i>=j) {
+ String lt = "'"+locktypes[0]+"'";
+ for (i=1; i<j; i++)
+ lt += ",'"+locktypes[i]+"'";
+ log.warn("System property vamsas.locktype takes one of "+lt);
+ log.warn("Defaulting to Locktype of "+locktypes[locktype]);
+ }
+ }
+ }
+
+ public static Lock getLock(java.io.File target) {
+ if (locktype==0)
+ return new FileLock(target);
+ if (locktype==1)
+ return new NativeLock(target);
+ log.fatal("Implementation Error! No valid Locktype value");
+ return null;
+ }
+}
--- /dev/null
+package org.vamsas.client.simpleclient;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
+
+public class NativeLock extends Lock {
+
+ protected FileLock lock = null;
+
+ /**
+ * @param lockfile
+ */
+ public NativeLock(File lockfile) {
+ super(lockfile);
+ // try and get a lock.
+ lock = null;
+
+ try {
+ if (!lockfile.exists())
+ if (!lockfile.createNewFile()) {
+ log.warn("Failed to create locked file "+lockfile);
+ return;
+ }
+
+ lock = (rafile=new RandomAccessFile(lockfile,"rw")).getChannel().tryLock();
+ if (lock==null || !lock.isValid()) {
+ // failed to get lock. Close the file channel
+ log.debug("failed to get lock for "+lockfile);
+ rafile.getChannel().close();
+ lock=null;
+ }
+ } catch (FileNotFoundException e) {
+ //
+ log.debug("Lock failed - normal behaviour for windows locking.");
+ //log.error("Error! Couldn't create a lockfile at "
+ // + lockfile.getAbsolutePath(), e);
+ } catch (IOException e) {
+ log.error("Error! Problems with IO when creating a lock on "
+ + lockfile.getAbsolutePath(),e);
+ }
+ }
+
+ public boolean isLocked() {
+ if (lock != null && lock.isValid()) {
+ return true;
+ }
+ return false;
+ }
+
+ public void release() {
+ release(true);
+ }
+
+ public void release(boolean closeChannel) {
+ try {
+ // channel.close should be called before release() for rigourous locking.
+ if (rafile!=null && rafile.getFD().valid() && rafile.getChannel()!=null && lock.isValid()) {
+ if (closeChannel && rafile.getChannel().isOpen()) {
+ rafile.close();
+ rafile=null;
+ }
+ if (lock!=null && lock.isValid())
+ lock.release();
+
+ }
+ } catch (IOException e) {
+ log.warn("Whilst releasing lock",e);
+ }
+ lock=null;
+ }
+
+ /**
+ * gets Locked Stream for reading from
+ * @param atStart true to start reading at beginning of file.
+ * @return null if file not locked
+ * @throws IOException
+ */
+ public FileInputStream getFileInputStream(boolean atStart) throws IOException {
+ if (!isLocked())
+ return null;
+ if (atStart)
+ rafile.seek(0);
+ return new FileInputStream(rafile.getFD());
+ }
+
+ /**
+ * gets Locked stream to write to
+ * FileInput always starts at the *end* of the file (after any truncation)
+ * @param clear true means file will be cleared to zero length
+ * @return null if file is not locked
+ * @throws IOException
+ */
+ public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
+ if (!isLocked())
+ return null;
+ if (clear)
+ rafile.setLength(0);
+ rafile.seek(rafile.length());
+ return new LockedFileOutputStream(rafile.getFD());
+ }
+
+ /**
+ * return buffered output stream to locked file.
+ * @param clear - true means file is truncated to 0 length before writing
+ * @return
+ */
+ public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
+ FileOutputStream fos = getFileOutputStream(clear);
+ if (fos!=null)
+ return new BufferedOutputStream(fos);
+ return null;
+ }
+ /**
+ * @see org.vamsas.client.simpleclient.Lock#finalize()
+ */
+ protected void finalize() throws Throwable {
+ release(true); // we explicitly lose the lock here.
+ // log.debug("lock closing through garbage collection ?");
+ super.finalize();
+ }
+
+}
fileLock=null;
}
if (extantlock!=null)
- fileLock=extantlock;
+ fileLock=extantlock; // THIS IS BROKEN - lockFile then nulls the lock.
return lockFile();
}
else
// lock failed for some reason.
fileLock.release();
- fileLock = null;
if (sessionFile != null) {
if (!sessionFile.exists()) {
// create new file
long tries=500;
do {
tries--;
- if (fileLock!=null && !fileLock.isLocked())
+ if (fileLock!=null && !fileLock.isLocked()) {
fileLock.release();
- fileLock = new Lock(sessionFile); // TODO: wait around if we can't get the lock.
+ try { Thread.sleep(5); } catch (Exception e) {};
+ }
+ fileLock = LockFactory.getLock(sessionFile); // TODO: wait around if we can't get the lock.
} while (tries>0 && !fileLock.isLocked());
if (!fileLock.isLocked())
log.error("Failed to get lock for "+sessionFile);
if (newData.sessionFile==null)
throw new IOException("Null SessionFile in newData.");
- lockFile(extantLock);
- newData.lockFile();
+ if (!lockFile(extantLock))
+ log.error("Failed to get write lock for "+sessionFile);
+ if (!newData.lockFile())
+ log.warn("Failed to get lock for updateFrom "+newData.sessionFile);
fileLock.rafile.getChannel().transferFrom(newData.fileLock.rafile.getChannel(), 0,
newData.fileLock.rafile.length());
}
* @return user field for a provenance entry
*/
protected String getProvenanceUser() {
- return new String(user.getFullName()+" ["+client.getClientUrn()+"]");
+ return new String(user.getFullName());
}
/**
* construct a provenance entry for this client with the specified action string.
* @return properly completed provenance entry
*/
protected Entry getProvenanceEntry(String action) {
- // VAMSAS: modify schema to allow referencing of user field (plus other issues, ClientUrn field, machine readable action, input parameters, additional data generated notes
- Entry prov = ProvenanceStuff.newProvenanceEntry(getProvenanceUser(), action);
+ Entry prov = ProvenanceStuff.newProvenanceEntry(client.getClientUrn(), getProvenanceUser(), action);
return prov;
}
private Hashtable handlers = initHandlers();
d = docb.getVamsasDocument(vreader);
if (d!=null) {
- ClientDoc creader = new ClientDoc(d, null, vreader, getProvenanceUser(), getVorbaIdHash());
+ ClientDoc creader = new ClientDoc(d, null, vreader, getClientHandle().getClientUrn(), getProvenanceUser(), getVorbaIdHash());
return creader;
}
}
varc.cancelArchive();
return null;
}
- ClientDoc cdoc = new ClientDoc(d, varc, varc.getOriginalArchiveReader(), getProvenanceUser(), getVorbaIdHash());
+ ClientDoc cdoc = new ClientDoc(d, varc, varc.getOriginalArchiveReader(), getClientHandle().getClientUrn(), getProvenanceUser(), getVorbaIdHash());
return cdoc;
// do appHandle?
} catch (Exception e) {
import org.apache.commons.logging.LogFactory;
import org.vamsas.client.simpleclient.VamsasArchive;
import org.vamsas.client.simpleclient.VamsasArchiveReader;
+import org.vamsas.objects.core.Alignment;
import org.vamsas.objects.core.ApplicationData;
import org.vamsas.objects.core.Entry;
+import org.vamsas.objects.core.Instance;
import org.vamsas.objects.core.Provenance;
import org.vamsas.objects.core.VAMSAS;
import org.vamsas.objects.core.VamsasDocument;
}
// Merge appDataReferences require transfer of jar entries, perhaps with a renaming of the entry.
// Merge appDatas require eventually unique URNS
+ // TODO: merging global appdata from different documents where same app has written them causes conflict
- public static Hashtable hashOfAppDatas(Hashtable ht, ApplicationData[] appdatas) {
+ public static Hashtable hashOfAppDatas(Hashtable ht, Instance[] appdatas) {
if (ht==null)
ht = new Hashtable();
for (int i=0, j=appdatas.length; i<j; i++) {
* @param entry application data to be copied from source archive
*/
public static void addAppDataEntry(VamsasArchive darc, VamsasDocument dest, VamsasArchiveReader sarc, ApplicationData entry) {
-
- // check uniqueness of entry.urn amongst dest.ApplicationData[].urn
+ // TODO: fix instances
+ // check uniqueness of instance's[] entry.urn amongst dest.ApplicationData[].getInstances[].urn
// check uniqueness of entry.user[].urn amongst dest.ApplicationData[].user[].urn
// check uniqueness of entry.user
// entry.getAppDataChoice().getData() or getDataReference is unique
for (int i=0, j=dest.getApplicationDataCount(); i<j; i++) {
ApplicationData o = dest.getApplicationData()[i];
// ensure new urn is really unique
- String urn = entry.getUrn();
+ //String urn = entry.getUrn();
int v = 1;
- while (o.getUrn().equals(urn)) {
- urn = entry.getUrn()+v++;
- }
+ //while (o.getUrn().equals(urn)) {
+ // urn = entry.getUrn()+v++;
+ // }
// uniqueness of urn
// check each user ApplicationData
// uniqueness (again)
VamsasArchive varc = new VamsasArchive(newarch, true);
VamsasDocument docroot;
docroot = new VamsasDocument();
- docroot.setProvenance(ProvenanceStuff.newProvenance("ArchiveWriter", "Created new Vamsas Document"));
+ docroot.setProvenance(ProvenanceStuff.newProvenance("ArchiveWriter", "user", "Created new Vamsas Document"));
while (++argpos<argv.length) {
File archive = new File(argv[argpos]);
InputStream istream;
if ((istream = vdoc.getVamsasXmlStream())!=null) {
// make a new vamsas document from the vamsas.xml entry
VAMSAS root = VAMSAS.unmarshal(new InputStreamReader(istream)); // TODO: verify only one VAMSAS element per vamsas.xml entry.
- docroot.getProvenance().addEntry(ProvenanceStuff.newProvenanceEntry("user", "added vamsas.xml from "+argv[argpos-1]));
+ docroot.getProvenance().addEntry(ProvenanceStuff.newProvenanceEntry("ArchiveWriter", "user", "added vamsas.xml from "+argv[argpos-1]));
docroot.addVAMSAS(root);
}
}
protected VamsasArchive iohandler=null;
protected VamsasArchiveReader reader=null;
private String user=null;
+ private String app=null;
/**
* @param doc
* @param iohandler
* @param reader
+ * @param app
* @param user
*/
- public ClientDoc(VamsasDocument doc, VamsasArchive iohandler, VamsasArchiveReader reader, String user, Hashtable objrefs) {
+ public ClientDoc(VamsasDocument doc, VamsasArchive iohandler, VamsasArchiveReader reader, String app, String user, Hashtable objrefs) {
super();
this.doc = doc;
this.iohandler = iohandler;
this.reader = reader;
+ this.app = app;
this.user = user;
this.objrefs = objrefs;
_VamsasRoots = doc.getVAMSAS();
*/
protected Entry getProvenanceEntry(String action) {
// VAMSAS: modify schema to allow referencing of user field (plus other issues, ClientUrn field, machine readable action, input parameters, additional data generated notes
- Entry prov = ProvenanceStuff.newProvenanceEntry(user, action);
+ Entry prov = ProvenanceStuff.newProvenanceEntry(app, user, action);
return prov;
}
public VAMSAS[] getVamsasRoots() {
apuser.setDataReference(appdata_ref);
appdata.addUser(apuser);
appdata.setVersion("noggin");
- appdata.setUrn("program:/the.nog/");
+ //TODO: write instance appdata appdata.setUrn("program:/the.nog/");
try {
ObjectOutputStream ost = new ObjectOutputStream(va.getAppDataStream(appdata_ref));
ost.writeObject(appdata);