X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Forg%2Fvamsas%2Fclient%2Fsimpleclient%2FFileLock.java;fp=src%2Forg%2Fvamsas%2Fclient%2Fsimpleclient%2FFileLock.java;h=53688ace2c25bbeeb6ec7ad53c568adf70376e65;hb=30801ef84cde704404d052f00c70ae129820bb0b;hp=8cb680860bea2f95dba9b88e804eba27c2cde7d1;hpb=4f11373ddecd53546b3b22e0358f3df01b24a6e6;p=vamsas.git diff --git a/src/org/vamsas/client/simpleclient/FileLock.java b/src/org/vamsas/client/simpleclient/FileLock.java index 8cb6808..53688ac 100644 --- a/src/org/vamsas/client/simpleclient/FileLock.java +++ b/src/org/vamsas/client/simpleclient/FileLock.java @@ -7,41 +7,71 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; - +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +/** + * File based Locking mechanism to get around some bizarre limitations of JarEntry seeking. + * Abstract locks have a target file, to which access is controlled when a lock is held. Native locks on WindowsXP seem to conflict with Jar seek operations, so a file lock creates an advisory lock. + * Method: + * A lock file is created, if it doesn't already exist - the naming convention is TargetFile+suffixSeparator+_LockSuffix. + * A lock is obtained by locking the lock file with a native lock. The NativeLock is used for this. + * @author JimP + * + */ public class FileLock extends Lock { - File _lock = null; + private File _lock = null; protected static String _LockSuffix="lck"; + private NativeLock advisory=null; + /** + * ensure that the _lock file exists + * and create a lock + */ + private boolean ensureLockFile(boolean block) { + if (_lock==null) + return false; + if (advisory!=null && advisory.isLocked()) + return true; + try { + advisory=new NativeLock(_lock, block); + } catch (Exception e) { + log.fatal("Failed to create advisory lock file "+_lock,e); + throw new Error("Failed to create advisory lock file "+_lock); + } + return advisory.isLocked(); + } /** * call to clear up a filelock file after its been made * */ private void tidy() { - if (_lock!=null) { - _lock.delete(); + if (_lock!=null) { + if ( advisory!=null) + advisory.release(true); + advisory=null; _lock=null; } } /** * @param lockfile + * @param block true means thread blocks until FileLock is obtained. */ - public FileLock(File lockfile) { + public FileLock(File lockfile, boolean block) { 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; + if (!ensureLockFile(block)) { + log.debug("Couldn't get lock on "+_lock); + tidy(); 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(); + //openRaFile(); } catch (FileNotFoundException e) { // log.debug("FileLock failed with target="+lockfile+" and lockfile suffix of "+_LockSuffix); @@ -56,18 +86,22 @@ public class FileLock extends Lock { private boolean openRaFile() throws IOException { if (target==null) return false; - if (_lock==null || !_lock.exists()) + if (advisory==null || !advisory.isLocked()) return false; - if (rafile==null) + if (rafile==null || rafile.getFD()==null || !rafile.getFD().valid()) { rafile=new RandomAccessFile(target,"rw"); + } else { + if (log.isDebugEnabled()) + log.debug("Reusing existing RandomAccessFile on "+target); + } return (rafile.getChannel()!=null) && rafile.getChannel().isOpen(); } public boolean isLocked() { - if (_lock != null) { - if (_lock.exists()) + if (advisory != null) { + if (advisory.isLocked()) return true; - _lock=null; + advisory=null; if (log.isDebugEnabled()) log.debug("Lockfile "+_lock+" unexpectedly deleted ?"); } @@ -79,8 +113,10 @@ public class FileLock extends Lock { } public void release(boolean closeChannel) { - if (_lock==null) + if (!isLocked()) return; + if (log.isDebugEnabled()) + log.debug("Releasing advisory lock on "+target); if (closeChannel) { if (rafile!=null) try { @@ -94,8 +130,10 @@ public class FileLock extends Lock { } public FileInputStream getFileInputStream(boolean atStart) throws IOException { - if (!isLocked()) + if (!isLocked()) { + log.debug("Don't hold lock on "+target+" to get locked FileInputStream."); return null; + } openRaFile(); if (atStart) rafile.seek(0); @@ -104,27 +142,63 @@ public class FileLock extends Lock { public FileOutputStream getFileOutputStream(boolean clear) throws IOException { - if (!isLocked()) + if (!isLocked()) { + log.debug("Don't hold lock on "+target+" to get locked FileOutputStream."); return null; + } openRaFile(); - if (clear) + if (clear) { + rafile.seek(0); rafile.setLength(0); - else + } else rafile.seek(rafile.length()); return new LockedFileOutputStream(rafile.getFD()); } public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException { + log.debug("Getting BufferedOutputStream (clear="+clear+")"); FileOutputStream fos = getFileOutputStream(clear); if (fos!=null) return new BufferedOutputStream(fos); return null; } + /* (non-Javadoc) + * @see org.vamsas.client.simpleclient.Lock#getLength() + */ + public long length() { + if (isLocked()) { + if (!target.exists()) { + try { + target.createNewFile(); + } catch (Exception e) { + log.error("Invalid lock:Failed to create target file "+target); + tidy(); + return -1; + } + return 0; + } + return target.length(); + } + return -1; + } protected void finalize() throws Throwable { release(true); // we explicitly lose the lock here. super.finalize(); } - + public RandomAccessFile getRaFile() throws IOException { + if (isLocked() && openRaFile()) { + return rafile; + } + log.debug("Failed to getRaFile on target "+target); + return null; + } + public FileChannel getRaChannel() throws IOException { + if (isLocked() && openRaFile()) { + return rafile.getChannel(); + } + log.debug("Failed to getRaChannel on target "+target); + return null; + } }