--- /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.ReadableByteChannel;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Basic methods for classes handling locked IO on files
+ * monitored by all (simpleclient) clients in a vamsas session.
+ * @author jimp
+ *TODO: support non nio file locking capable systems
+ */
+public class SessionFile {
+ private static Log log = LogFactory.getLog(SessionFile.class);
+ protected File sessionFile;
+ protected Lock fileLock = null;
+
+ protected SessionFile(File file) {
+ super();
+ sessionFile = file;
+ }
+
+ protected boolean lockFile(Lock extantlock) {
+ if (fileLock!=null && !fileLock.isLocked()) {
+ fileLock.release();// tidy up invalid lock
+ fileLock=null;
+ }
+ if (extantlock!=null && extantlock.isLocked())
+ fileLock=extantlock; // THIS IS BROKEN - lockFile then nulls the lock.
+ return lockFile();
+ }
+ private boolean ensureSessionFile() {
+ if (sessionFile != null) {
+ if (!sessionFile.exists()) {
+ // create new file
+ try {
+ if (!sessionFile.createNewFile()) {
+ log.error("Failed to create file prior to locking: "+sessionFile);
+ return false;
+ }
+ } catch (IOException e) {
+ log.error("Exception when trying to create file "+sessionFile, e);
+ return false;
+ }
+ }
+ return true;
+ }
+ log.error("ensureSessionFile called for non-initialised SessionFile!");
+ return false;
+ }
+ /**
+ * Get a lock for the SessionFile
+ *
+ * @return true if lock was made
+ */
+ protected boolean lockFile() {
+ if (fileLock != null) {
+ if (fileLock.isLocked()) {
+ if (!ensureSessionFile())
+ return false;
+ return true;
+ } else {
+ // lock failed for some reason.
+ fileLock.release();
+ log.info("Unexpected session file lock failure. Trying to get it again.");
+ fileLock=null;
+ }
+ }
+ if (!ensureSessionFile())
+ return false;
+ // TODO: see if we need to loop-wait for locks or they just block until
+ // lock is made...
+ long tries=5000;
+ do {
+ tries--;
+ if (fileLock==null || !fileLock.isLocked()) {
+ //try { Thread.sleep(1); } catch (Exception e) {};
+ fileLock = LockFactory.getLock(sessionFile,true); // 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);
+ // fileLock = new Lock(sessionFile);
+ return fileLock.isLocked();
+ }
+
+ /**
+ * Explicitly release the SessionFile's lock.
+ *
+ * @return true if lock was released.
+ */
+ protected void unlockFile() {
+ if (fileLock != null) {
+ fileLock.release();
+ fileLock = null;
+ }
+ }
+
+ /**
+ * Makes a backup of the sessionFile.
+ * @return Backed up SessionFile or null if failed to make backup.
+ */
+ protected File backupSessionFile() {
+ return backupSessionFile(null, sessionFile.getName(),".old", sessionFile.getParentFile());
+ }
+
+ protected File backupSessionFile(Lock extantLock, String backupPrefix, String backupSuffix, File backupDir) {
+ File tempfile=null;
+ if (lockFile(extantLock)) {
+ try {
+ tempfile = File.createTempFile(backupPrefix, backupSuffix, backupDir);
+ if (fileLock.length()>0) {
+ FileOutputStream tos = new FileOutputStream(tempfile);
+ ReadableByteChannel channel;
+ tos.getChannel().transferFrom(channel=fileLock.getRaChannel(), 0,
+ fileLock.length());
+ tos.close();
+ if (!channel.isOpen())
+ throw new Error(tos.getChannel().getClass()+".transferFrom closes source channel!");
+ if (!lockFile(extantLock))
+ throw new Error("Lost lock for "+sessionFile.getName()+" after backup.");
+
+ }
+ } catch (FileNotFoundException e1) {
+ log.warn("Can't create temp file for "+sessionFile.getName(),e1);
+ tempfile=null;
+ } catch (IOException e1) {
+ 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.");
+
+ if (!lockFile(extantLock))
+ throw new IOException("Failed to get write lock for "+sessionFile);
+ if (!newData.lockFile())
+ throw new IOException("Failed to get lock for updateFrom "+newData.sessionFile);
+ RandomAccessFile nrafile = newData.fileLock.getRaFile();
+ nrafile.seek(0);
+ RandomAccessFile trafile = fileLock.getRaFile();
+ /*long tries=5000;
+ while (trafile==null && --tries>0) {
+ log.debug("Lost lock on "+sessionFile+"! Re-trying for a transfer.");
+ lockFile();
+ trafile = fileLock.getRaFile();
+ }*/
+ trafile.seek(0);
+ trafile.getChannel().transferFrom(nrafile.getChannel(), 0,
+ nrafile.length());
+ }
+ /**
+ * remove all trace of the sessionFile file
+ *
+ */
+ protected void eraseExistence() {
+ unlockFile();
+ if (sessionFile!=null) {
+ sessionFile.delete();
+ sessionFile = null;
+ }
+ }
+ /* (non-Javadoc)
+ * @see org.vamsas.client.simpleclient.Lock#getBufferedInputStream(boolean)
+ */
+ public BufferedInputStream getBufferedInputStream(boolean atStart) throws IOException {
+ lockFile();
+ return fileLock.getBufferedInputStream(atStart);
+ }
+
+ /* (non-Javadoc)
+ * @see org.vamsas.client.simpleclient.Lock#getBufferedOutputStream(boolean)
+ */
+ public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
+ lockFile();
+ return fileLock.getBufferedOutputStream(clear);
+ }
+
+ /* (non-Javadoc)
+ * @see org.vamsas.client.simpleclient.Lock#getFileInputStream(boolean)
+ */
+ public FileInputStream getFileInputStream(boolean atStart) throws IOException {
+ lockFile();
+ return fileLock.getFileInputStream(atStart);
+ }
+
+ /* (non-Javadoc)
+ * @see org.vamsas.client.simpleclient.Lock#getFileOutputStream(boolean)
+ */
+ public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
+ lockFile();
+ return fileLock.getFileOutputStream(clear);
+ }
+
+}