new method to test if a particular file is or is related to the target of a lock
[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.createNewFile()) {
35           log.warn("Failed to create locked file "+lockfile);
36           return;
37         }
38       */
39       rafile=new RandomAccessFile(lockfile,"rw");
40       if (block)
41         lock = rafile.getChannel().lock();
42       else
43         lock = rafile.getChannel().tryLock();
44       if (lock==null || !lock.isValid()) {
45         // failed to get lock. Close the file channel
46         log.debug("failed to get lock for "+lockfile);
47         rafile.getChannel().close();
48         lock=null;
49       }
50     } catch (FileNotFoundException e) {
51       //
52       log.debug("Lock failed - normal behaviour for windows locking.");
53       //log.error("Error! Couldn't create a lockfile at "
54       //  + lockfile.getAbsolutePath(), e);
55     } catch (IOException e) {
56       log.error("Error! Problems with IO when creating a lock on "
57           + lockfile.getAbsolutePath(),e);
58     } // catch (Exception )
59   }
60
61   public boolean isLocked() {
62     if (lock != null && lock.isValid()) {
63       return true;
64     }
65     return false;
66   }
67
68   public void release() {
69     release(true);
70   }
71
72   public void release(boolean closeChannel) {
73     if (lock==null)
74       return;
75     try {
76       // channel.close should be called before release() for rigourous locking.
77       if (lock.isValid() && rafile!=null && rafile.getFD().valid() && rafile.getChannel()!=null) {
78         if (closeChannel && rafile.getChannel().isOpen()) {
79             rafile.close();
80             rafile=null; 
81         } else {
82           // just release the lock without doing anything to the channe;l
83           if (lock!=null && lock.isValid())
84             lock.release();
85         }
86       }
87     } catch (IOException e) {
88       log.warn("Whilst releasing lock",e);
89     }
90     lock=null;
91   }
92
93   /**
94    * gets Locked Stream for reading from
95    * @param atStart true to start reading at beginning of file.
96    * @return null if file not locked
97    * @throws IOException
98    */
99   public FileInputStream getFileInputStream(boolean atStart) throws IOException {
100     if (!isLocked())
101       return null;
102     if (atStart)
103       rafile.seek(0);
104     return new FileInputStream(rafile.getFD());
105   }
106
107   /**
108    * gets Locked stream to write to
109    * FileInput always starts at the *end* of the file (after any truncation)
110    * @param clear true means file will be cleared to zero length
111    * @return null if file is not locked
112    * @throws IOException
113    */
114   public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
115     if (!isLocked())
116       return null;
117     if (clear) {
118       rafile.seek(0);
119       rafile.setLength(0);
120     } else
121       rafile.seek(rafile.length());
122     return new LockedFileOutputStream(rafile.getFD());
123   }
124
125   /**
126    * return buffered output stream to locked file.
127    * @param clear - true means file is truncated to 0 length before writing 
128    * @return
129    */
130   public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
131     OutputStream fos = getFileOutputStream(clear);
132     if (fos!=null)
133       return new BufferedOutputStream(fos);
134     return null;
135   }
136   /**
137    * @see uk.ac.vamsas.client.simpleclient.Lock#finalize()
138    */
139   protected void finalize() throws Throwable {
140     release(true); // we explicitly lose the lock here.
141     // log.debug("lock closing through garbage collection ?");
142     super.finalize();
143   }
144
145   /* (non-Javadoc)
146    * @see uk.ac.vamsas.client.simpleclient.Lock#getLength()
147    */
148   public long length() {
149     if (isLocked()){
150       try {
151         return rafile.length();
152       } catch (Exception e) {
153         log.debug("getLength exception:",e);
154       }
155     }
156     return -1;
157   }
158
159   public RandomAccessFile getRaFile() throws IOException {
160     if (isLocked())
161       return rafile;
162     else
163       log.debug("Failed to getRaFile on "+target);
164     return null;
165   }  
166   
167   public FileChannel getRaChannel() throws IOException {
168     if (isLocked())
169       return rafile.getChannel();
170     else
171       log.debug("Failed to getRaChannel on "+target);
172     return null;
173   }
174
175   public boolean isTargetLockFile(File afile) {
176     if (isLocked() && target.equals(afile))
177       return true;
178     return false;
179   }
180
181 }