applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / FileLock.java
index 8a340c3..b5ddbf3 100644 (file)
-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