-package uk.ac.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;
-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 {
- 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) {
- if (!_lock.exists()) {
- // advisory cannot be created. this is serious.
- log.fatal("Failed to create advisory lock file "+_lock,e);
- throw new Error("Failed to create advisory lock file "+_lock);
- }
- }
- return (advisory!=null) && advisory.isLocked();
- }
- /**
- * call to clear up a filelock file after its been made
- *
- */
- private void tidy() {
- if (_lock!=null) {
- if ( advisory!=null) {
- // TODO: fix occasional exceptions raised here (usually on JVM shutdown)
- if (advisory.target!=null) {
- advisory.target.deleteOnExit(); // release will null the target
- }
- advisory.release(true);
- }
- advisory=null;
- _lock=null;
- }
- }
- /**
- * @param lockfile
- * @param block true means thread blocks until FileLock is obtained.
- */
- public FileLock(File lockfile, boolean block) {
- super(lockfile);
- // try and get a lock.
- try {
- _lock = make_lockForTarget(lockfile);
- if (!ensureLockFile(block)) {
- log.debug("Couldn't get lock on "+_lock);
- tidy();
- return;
- }
- // 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);
- }
- }
- /**
- *
- * @param lockfile target of lock
- * @return file object that will be locked for lockfile
- */
- private File make_lockForTarget(File lockfile) {
- return new File(lockfile.getParentFile(), lockfile.getName()+"."+_LockSuffix);
- }
- private boolean openRaFile() throws IOException {
- if (target==null)
- return false;
- if (advisory==null || !advisory.isLocked())
- return false;
- 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 (advisory != null) {
- if (advisory.isLocked())
- return true;
- advisory=null;
- if (log.isDebugEnabled())
- log.debug("Lockfile "+_lock+" unexpectedly deleted ?");
- }
- return false;
- }
-
- public void release() {
- release(true);
- }
-
- public void release(boolean closeChannel) {
- if (!isLocked())
- return;
- if (rafile!=null) {
- if (closeChannel) {
- try {
- rafile.close();
- } catch (Exception e) {
- log.debug("Unexpected exception whilst closing RandomAccessFile on "+target, e);
- }
- rafile=null; // do not hold reference to rafile anymore either
- }
- if (log.isDebugEnabled())
- log.debug("Releasing advisory lock on "+target);
- // TODO: LATER: verify this change in closeChannel semantics really is correct - ArchiveClient works correctly
- }
- tidy();
- }
-
- public FileInputStream getFileInputStream(boolean atStart) throws IOException {
- if (!isLocked()) {
- log.debug("Don't hold lock on "+target+" to get locked FileInputStream.");
- return null;
- }
- openRaFile();
- if (atStart)
- rafile.seek(0);
- return new FileInputStream(rafile.getFD());
- }
-
-
- public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
- if (!isLocked()) {
- log.debug("Don't hold lock on "+target+" to get locked FileOutputStream.");
- return null;
- }
- openRaFile();
- if (clear) {
- rafile.seek(0);
- rafile.setLength(0);
- } 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 uk.ac.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;
- }
- public boolean isTargetLockFile(File afile) {
- if (isLocked())
- {
- if (target.equals(afile) || make_lockForTarget(target).equals(afile))
- return true;
- }
- return false;
- }
-}
+/*\r
+ * This file is part of the Vamsas Client version 0.1. \r
+ * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
+ * Andrew Waterhouse and Dominik Lindner.\r
+ * \r
+ * Earlier versions have also been incorporated into Jalview version 2.4 \r
+ * since 2008, and TOPALi version 2 since 2007.\r
+ * \r
+ * The Vamsas Client is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU Lesser General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * The Vamsas Client is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with the Vamsas Client. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+import java.io.BufferedOutputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.RandomAccessFile;\r
+import java.nio.channels.FileChannel;\r
+import java.nio.channels.ReadableByteChannel;\r
+\r
+/**\r
+ * File based Locking mechanism to get around some bizarre limitations of\r
+ * JarEntry seeking. Abstract locks have a target file, to which access is\r
+ * controlled when a lock is held. Native locks on WindowsXP seem to conflict\r
+ * with Jar seek operations, so a file lock creates an advisory lock. Method: A\r
+ * lock file is created, if it doesn't already exist - the naming convention is\r
+ * TargetFile+suffixSeparator+_LockSuffix. A lock is obtained by locking the\r
+ * lock file with a native lock. The NativeLock is used for this.\r
+ * \r
+ * @author JimP\r
+ * \r
+ */\r
+public class FileLock extends Lock {\r
+ private File _lock = null;\r
+\r
+ protected static String _LockSuffix = "lck";\r
+\r
+ private NativeLock advisory = null;\r
+\r
+ /**\r
+ * ensure that the _lock file exists and create a lock\r
+ */\r
+ private boolean ensureLockFile(boolean block) {\r
+ if (_lock == null)\r
+ return false;\r
+ if (advisory != null && advisory.isLocked())\r
+ return true;\r
+ try {\r
+ advisory = new NativeLock(_lock, block);\r
+ } catch (Exception e) {\r
+ if (!_lock.exists()) {\r
+ // advisory cannot be created. this is serious.\r
+ log.fatal("Failed to create advisory lock file " + _lock, e);\r
+ throw new Error("Failed to create advisory lock file " + _lock);\r
+ }\r
+ }\r
+ return (advisory != null) && advisory.isLocked();\r
+ }\r
+\r
+ /**\r
+ * call to clear up a filelock file after its been made\r
+ * \r
+ */\r
+ private void tidy() {\r
+ if (_lock != null) {\r
+ if (advisory != null) {\r
+ // TODO: fix occasional exceptions raised here (usually on JVM shutdown)\r
+ if (advisory.target != null) {\r
+ advisory.target.deleteOnExit(); // release will null the target\r
+ }\r
+ advisory.release(true);\r
+ }\r
+ advisory = null;\r
+ _lock = null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param lockfile\r
+ * @param block\r
+ * true means thread blocks until FileLock is obtained.\r
+ */\r
+ public FileLock(File lockfile, boolean block) {\r
+ super(lockfile);\r
+ // try and get a lock.\r
+ try {\r
+ _lock = make_lockForTarget(lockfile);\r
+ if (!ensureLockFile(block)) {\r
+ log.debug("Couldn't get lock on " + _lock);\r
+ tidy();\r
+ return;\r
+ }\r
+ // create target file ready to be written to if necessary.\r
+ if (!lockfile.exists())\r
+ if (!lockfile.createNewFile()) {\r
+ log.warn("Failed to create locked file " + lockfile);\r
+ return;\r
+ }\r
+ // openRaFile();\r
+ } catch (FileNotFoundException e) {\r
+ //\r
+ log.debug("FileLock failed with target=" + lockfile\r
+ + " and lockfile suffix of " + _LockSuffix);\r
+ // log.error("Error! Couldn't create a lockfile at "\r
+ // + lockfile.getAbsolutePath(), e);\r
+ } catch (IOException e) {\r
+ log.error("Error! Problems with IO when creating a lock on "\r
+ + lockfile.getAbsolutePath(), e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param lockfile\r
+ * target of lock\r
+ * @return file object that will be locked for lockfile\r
+ */\r
+ private File make_lockForTarget(File lockfile) {\r
+ return new File(lockfile.getParentFile(), lockfile.getName() + "."\r
+ + _LockSuffix);\r
+ }\r
+\r
+ private boolean openRaFile() throws IOException {\r
+ if (target == null)\r
+ return false;\r
+ if (advisory == null || !advisory.isLocked())\r
+ return false;\r
+ if (rafile == null || rafile.getFD() == null || !rafile.getFD().valid()) {\r
+ rafile = new RandomAccessFile(target, "rw");\r
+ } else {\r
+ if (log.isDebugEnabled())\r
+ log.debug("Reusing existing RandomAccessFile on " + target);\r
+ }\r
+ return (rafile.getChannel() != null) && rafile.getChannel().isOpen();\r
+ }\r
+\r
+ public boolean isLocked() {\r
+ if (advisory != null) {\r
+ if (advisory.isLocked())\r
+ return true;\r
+ advisory = null;\r
+ if (log.isDebugEnabled())\r
+ log.debug("Lockfile " + _lock + " unexpectedly deleted ?");\r
+ }\r
+ return false;\r
+ }\r
+\r
+ public void release() {\r
+ release(true);\r
+ }\r
+\r
+ public void release(boolean closeChannel) {\r
+ if (!isLocked())\r
+ return;\r
+ if (rafile != null) {\r
+ if (closeChannel) {\r
+ try {\r
+ rafile.close();\r
+ } catch (Exception e) {\r
+ log.debug("Unexpected exception whilst closing RandomAccessFile on "\r
+ + target, e);\r
+ }\r
+ rafile = null; // do not hold reference to rafile anymore either\r
+ }\r
+ if (log.isDebugEnabled())\r
+ log.debug("Releasing advisory lock on " + target);\r
+ // TODO: LATER: verify this change in closeChannel semantics really is\r
+ // correct - ArchiveClient works correctly\r
+ }\r
+ tidy();\r
+ }\r
+\r
+ public FileInputStream getFileInputStream(boolean atStart) throws IOException {\r
+ if (!isLocked()) {\r
+ log.debug("Don't hold lock on " + target\r
+ + " to get locked FileInputStream.");\r
+ return null;\r
+ }\r
+ openRaFile();\r
+ if (atStart)\r
+ rafile.seek(0);\r
+ return new FileInputStream(rafile.getFD());\r
+ }\r
+\r
+ public FileOutputStream getFileOutputStream(boolean clear) throws IOException {\r
+ if (!isLocked()) {\r
+ log.debug("Don't hold lock on " + target\r
+ + " to get locked FileOutputStream.");\r
+ return null;\r
+ }\r
+ openRaFile();\r
+ if (clear) {\r
+ rafile.seek(0);\r
+ rafile.setLength(0);\r
+ } else\r
+ rafile.seek(rafile.length());\r
+ return new LockedFileOutputStream(rafile.getFD());\r
+ }\r
+\r
+ public BufferedOutputStream getBufferedOutputStream(boolean clear)\r
+ throws IOException {\r
+ log.debug("Getting BufferedOutputStream (clear=" + clear + ")");\r
+ FileOutputStream fos = getFileOutputStream(clear);\r
+ if (fos != null)\r
+ return new BufferedOutputStream(fos);\r
+ return null;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see uk.ac.vamsas.client.simpleclient.Lock#getLength()\r
+ */\r
+ public long length() {\r
+ if (isLocked()) {\r
+ if (!target.exists()) {\r
+ try {\r
+ target.createNewFile();\r
+ } catch (Exception e) {\r
+ log.error("Invalid lock:Failed to create target file " + target);\r
+ tidy();\r
+ return -1;\r
+ }\r
+ return 0;\r
+ }\r
+ return target.length();\r
+ }\r
+ return -1;\r
+ }\r
+\r
+ protected void finalize() throws Throwable {\r
+ release(true); // we explicitly lose the lock here.\r
+ super.finalize();\r
+ }\r
+\r
+ public RandomAccessFile getRaFile() throws IOException {\r
+ if (isLocked() && openRaFile()) {\r
+ return rafile;\r
+ }\r
+ log.debug("Failed to getRaFile on target " + target);\r
+ return null;\r
+ }\r
+\r
+ public FileChannel getRaChannel() throws IOException {\r
+ if (isLocked() && openRaFile()) {\r
+ return rafile.getChannel();\r
+ }\r
+ log.debug("Failed to getRaChannel on target " + target);\r
+ return null;\r
+ }\r
+\r
+ public boolean isTargetLockFile(File afile) {\r
+ if (isLocked()) {\r
+ if (target.equals(afile) || make_lockForTarget(target).equals(afile))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+}\r