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);
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 ?");
}
}
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 {
}
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);
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;
+ }
}