46484b13d97e35c753c36e16a050d3d15a2e5f56
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / NativeLock.java
1 package uk.ac.vamsas.client.simpleclient;
2
3 import java.io.BufferedInputStream;
4 import java.io.BufferedOutputStream;
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.FileNotFoundException;
8 import java.io.FileOutputStream;
9 import java.io.IOException;
10 import java.io.OutputStream;
11 import java.io.RandomAccessFile;
12 import java.nio.channels.FileChannel;
13 import java.nio.channels.FileLock;
14 import java.nio.channels.ReadableByteChannel;
15
16 /**
17  * @author JimP
18  *
19  */
20 public class NativeLock extends Lock {
21
22   protected FileLock lock = null;
23
24   /**
25    * @param lockfile
26    * @param block true means thread will block until a lock is obtained.
27    */
28   public NativeLock(File lockfile, boolean block) {
29     super(lockfile);
30     // try and get a lock.
31     lock = null;
32     
33     try {
34       if (!lockfile.exists())
35         if (!lockfile.createNewFile()) {
36           log.warn("Failed to create locked file "+lockfile);
37           return;
38         }
39       
40       rafile=new RandomAccessFile(lockfile,"rw");
41       if (block)
42         lock = rafile.getChannel().lock();
43       else
44         lock = rafile.getChannel().tryLock();
45       if (lock==null || !lock.isValid()) {
46         // failed to get lock. Close the file channel
47         log.debug("failed to get lock for "+lockfile);
48         rafile.getChannel().close();
49         lock=null;
50       }
51     } catch (FileNotFoundException e) {
52       //
53       log.debug("Lock failed - normal behaviour for windows locking.");
54       //log.error("Error! Couldn't create a lockfile at "
55       //  + lockfile.getAbsolutePath(), e);
56     } catch (IOException e) {
57       log.error("Error! Problems with IO when creating a lock on "
58           + lockfile.getAbsolutePath(),e);
59     }
60   }
61
62   public boolean isLocked() {
63     if (lock != null && lock.isValid()) {
64       return true;
65     }
66     return false;
67   }
68
69   public void release() {
70     release(true);
71   }
72
73   public void release(boolean closeChannel) {
74     try {
75       // channel.close should be called before release() for rigourous locking.
76       if (rafile!=null && rafile.getFD().valid() && rafile.getChannel()!=null && lock.isValid()) {
77         if (closeChannel && rafile.getChannel().isOpen()) {
78             rafile.close();
79             rafile=null; 
80         }
81         if (lock!=null && lock.isValid())
82           lock.release();
83         
84       }
85     } catch (IOException e) {
86       log.warn("Whilst releasing lock",e);
87     }
88     lock=null;
89   }
90
91   /**
92    * gets Locked Stream for reading from
93    * @param atStart true to start reading at beginning of file.
94    * @return null if file not locked
95    * @throws IOException
96    */
97   public FileInputStream getFileInputStream(boolean atStart) throws IOException {
98     if (!isLocked())
99       return null;
100     if (atStart)
101       rafile.seek(0);
102     return new FileInputStream(rafile.getFD());
103   }
104
105   /**
106    * gets Locked stream to write to
107    * FileInput always starts at the *end* of the file (after any truncation)
108    * @param clear true means file will be cleared to zero length
109    * @return null if file is not locked
110    * @throws IOException
111    */
112   public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
113     if (!isLocked())
114       return null;
115     if (clear) {
116       rafile.seek(0);
117       rafile.setLength(0);
118     } else
119       rafile.seek(rafile.length());
120     return new LockedFileOutputStream(rafile.getFD());
121   }
122
123   /**
124    * return buffered output stream to locked file.
125    * @param clear - true means file is truncated to 0 length before writing 
126    * @return
127    */
128   public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
129     OutputStream fos = getFileOutputStream(clear);
130     if (fos!=null)
131       return new BufferedOutputStream(fos);
132     return null;
133   }
134   /**
135    * @see uk.ac.vamsas.client.simpleclient.Lock#finalize()
136    */
137   protected void finalize() throws Throwable {
138     release(true); // we explicitly lose the lock here.
139     // log.debug("lock closing through garbage collection ?");
140     super.finalize();
141   }
142
143   /* (non-Javadoc)
144    * @see uk.ac.vamsas.client.simpleclient.Lock#getLength()
145    */
146   public long length() {
147     if (isLocked()){
148       try {
149         return rafile.length();
150       } catch (Exception e) {
151         log.debug("getLength exception:",e);
152       }
153     }
154     return -1;
155   }
156
157   public RandomAccessFile getRaFile() throws IOException {
158     if (isLocked())
159       return rafile;
160     else
161       log.debug("Failed to getRaFile on "+target);
162     return null;
163   }  
164   
165   public FileChannel getRaChannel() throws IOException {
166     if (isLocked())
167       return rafile.getChannel();
168     else
169       log.debug("Failed to getRaChannel on "+target);
170     return null;
171   }
172
173 }