introducing Lock File based locking (for portability) - part implemented.
[vamsas.git] / src / org / vamsas / client / simpleclient / NativeLock.java
diff --git a/src/org/vamsas/client/simpleclient/NativeLock.java b/src/org/vamsas/client/simpleclient/NativeLock.java
new file mode 100644 (file)
index 0000000..96d9b6b
--- /dev/null
@@ -0,0 +1,129 @@
+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.FileLock;
+
+public class NativeLock extends Lock {
+
+  protected FileLock lock = null;
+
+  /**
+   * @param lockfile
+   */
+  public NativeLock(File lockfile) {
+    super(lockfile);
+    // try and get a lock.
+    lock = null;
+    
+    try {
+      if (!lockfile.exists())
+        if (!lockfile.createNewFile()) {
+          log.warn("Failed to create locked file "+lockfile);
+          return;
+        }
+      
+      lock = (rafile=new RandomAccessFile(lockfile,"rw")).getChannel().tryLock();
+      if (lock==null || !lock.isValid()) {
+        // failed to get lock. Close the file channel
+        log.debug("failed to get lock for "+lockfile);
+        rafile.getChannel().close();
+        lock=null;
+      }
+    } catch (FileNotFoundException e) {
+      //
+      log.debug("Lock failed - normal behaviour for windows locking.");
+      //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);
+    }
+  }
+
+  public boolean isLocked() {
+    if (lock != null && lock.isValid()) {
+      return true;
+    }
+    return false;
+  }
+
+  public void release() {
+    release(true);
+  }
+
+  public void release(boolean closeChannel) {
+    try {
+      // channel.close should be called before release() for rigourous locking.
+      if (rafile!=null && rafile.getFD().valid() && rafile.getChannel()!=null && lock.isValid()) {
+        if (closeChannel && rafile.getChannel().isOpen()) {
+            rafile.close();
+            rafile=null; 
+        }
+        if (lock!=null && lock.isValid())
+          lock.release();
+        
+      }
+    } catch (IOException e) {
+      log.warn("Whilst releasing lock",e);
+    }
+    lock=null;
+  }
+
+  /**
+   * gets Locked Stream for reading from
+   * @param atStart true to start reading at beginning of file.
+   * @return null if file not locked
+   * @throws IOException
+   */
+  public FileInputStream getFileInputStream(boolean atStart) throws IOException {
+    if (!isLocked())
+      return null;
+    if (atStart)
+      rafile.seek(0);
+    return new FileInputStream(rafile.getFD());
+  }
+
+  /**
+   * gets Locked stream to write to
+   * FileInput always starts at the *end* of the file (after any truncation)
+   * @param clear true means file will be cleared to zero length
+   * @return null if file is not locked
+   * @throws IOException
+   */
+  public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
+    if (!isLocked())
+      return null;
+    if (clear)
+      rafile.setLength(0);
+    rafile.seek(rafile.length());
+    return new LockedFileOutputStream(rafile.getFD());
+  }
+
+  /**
+   * return buffered output stream to locked file.
+   * @param clear - true means file is truncated to 0 length before writing 
+   * @return
+   */
+  public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
+    FileOutputStream fos = getFileOutputStream(clear);
+    if (fos!=null)
+      return new BufferedOutputStream(fos);
+    return null;
+  }
+  /**
+   * @see org.vamsas.client.simpleclient.Lock#finalize()
+   */
+  protected void finalize() throws Throwable {
+    release(true); // we explicitly lose the lock here.
+    // log.debug("lock closing through garbage collection ?");
+    super.finalize();
+  }
+
+}