applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / NativeLock.java
1 /*\r
2  * This file is part of the Vamsas Client version 0.1. \r
3  * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
4  *  Andrew Waterhouse and Dominik Lindner.\r
5  * \r
6  * Earlier versions have also been incorporated into Jalview version 2.4 \r
7  * since 2008, and TOPALi version 2 since 2007.\r
8  * \r
9  * The Vamsas Client is free software: you can redistribute it and/or modify\r
10  * it under the terms of the GNU Lesser General Public License as published by\r
11  * the Free Software Foundation, either version 3 of the License, or\r
12  * (at your option) any later version.\r
13  *  \r
14  * The Vamsas Client is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU Lesser General Public License for more details.\r
18  * \r
19  * You should have received a copy of the GNU Lesser General Public License\r
20  * along with the Vamsas Client.  If not, see <http://www.gnu.org/licenses/>.\r
21  */\r
22 package uk.ac.vamsas.client.simpleclient;\r
23 \r
24 import java.io.BufferedInputStream;\r
25 import java.io.BufferedOutputStream;\r
26 import java.io.File;\r
27 import java.io.FileInputStream;\r
28 import java.io.FileNotFoundException;\r
29 import java.io.FileOutputStream;\r
30 import java.io.IOException;\r
31 import java.io.OutputStream;\r
32 import java.io.RandomAccessFile;\r
33 import java.nio.channels.FileChannel;\r
34 import java.nio.channels.FileLock;\r
35 import java.nio.channels.ReadableByteChannel;\r
36 \r
37 /**\r
38  * @author JimP\r
39  * \r
40  */\r
41 public class NativeLock extends Lock {\r
42 \r
43   protected FileLock lock = null;\r
44 \r
45   /**\r
46    * @param lockfile\r
47    * @param block\r
48    *          true means thread will block until a lock is obtained.\r
49    */\r
50   public NativeLock(File lockfile, boolean block) {\r
51     super(lockfile);\r
52     // try and get a lock.\r
53     lock = null;\r
54 \r
55     try {\r
56       /*\r
57        * if (!lockfile.createNewFile()) {\r
58        * log.warn("Failed to create locked file "+lockfile); return; }\r
59        */\r
60       rafile = new RandomAccessFile(lockfile, "rw");\r
61       if (block)\r
62         lock = rafile.getChannel().lock();\r
63       else\r
64         lock = rafile.getChannel().tryLock();\r
65       if (lock == null || !lock.isValid()) {\r
66         // failed to get lock. Close the file channel\r
67         log.debug("failed to get lock for " + lockfile);\r
68         rafile.getChannel().close();\r
69         lock = null;\r
70       }\r
71     } catch (FileNotFoundException e) {\r
72       //\r
73       log.debug("Lock failed - normal behaviour for windows locking.");\r
74       // log.error("Error! Couldn't create a lockfile at "\r
75       // + lockfile.getAbsolutePath(), e);\r
76     } catch (IOException e) {\r
77       log.error("Error! Problems with IO when creating a lock on "\r
78           + lockfile.getAbsolutePath(), e);\r
79     } // catch (Exception )\r
80   }\r
81 \r
82   public boolean isLocked() {\r
83     if (lock != null && lock.isValid()) {\r
84       return true;\r
85     }\r
86     return false;\r
87   }\r
88 \r
89   public void release() {\r
90     release(true);\r
91   }\r
92 \r
93   public void release(boolean closeChannel) {\r
94     if (lock == null)\r
95       return;\r
96     try {\r
97       // channel.close should be called before release() for rigourous locking.\r
98       if (lock.isValid() && rafile != null && rafile.getFD().valid()\r
99           && rafile.getChannel() != null) {\r
100         if (closeChannel && rafile.getChannel().isOpen()) {\r
101           rafile.close();\r
102           rafile = null;\r
103         } else {\r
104           // just release the lock without doing anything to the channe;l\r
105           if (lock != null && lock.isValid())\r
106             lock.release();\r
107         }\r
108       }\r
109     } catch (IOException e) {\r
110       log.warn("Whilst releasing lock", e);\r
111     }\r
112     lock = null;\r
113   }\r
114 \r
115   /**\r
116    * gets Locked Stream for reading from\r
117    * \r
118    * @param atStart\r
119    *          true to start reading at beginning of file.\r
120    * @return null if file not locked\r
121    * @throws IOException\r
122    */\r
123   public FileInputStream getFileInputStream(boolean atStart) throws IOException {\r
124     if (!isLocked())\r
125       return null;\r
126     if (atStart)\r
127       rafile.seek(0);\r
128     return new FileInputStream(rafile.getFD());\r
129   }\r
130 \r
131   /**\r
132    * gets Locked stream to write to FileInput always starts at the *end* of the\r
133    * file (after any truncation)\r
134    * \r
135    * @param clear\r
136    *          true means file will be cleared to zero length\r
137    * @return null if file is not locked\r
138    * @throws IOException\r
139    */\r
140   public FileOutputStream getFileOutputStream(boolean clear) throws IOException {\r
141     if (!isLocked())\r
142       return null;\r
143     if (clear) {\r
144       rafile.seek(0);\r
145       rafile.setLength(0);\r
146     } else\r
147       rafile.seek(rafile.length());\r
148     return new LockedFileOutputStream(rafile.getFD());\r
149   }\r
150 \r
151   /**\r
152    * return buffered output stream to locked file.\r
153    * \r
154    * @param clear\r
155    *          - true means file is truncated to 0 length before writing\r
156    * @return\r
157    */\r
158   public BufferedOutputStream getBufferedOutputStream(boolean clear)\r
159       throws IOException {\r
160     OutputStream fos = getFileOutputStream(clear);\r
161     if (fos != null)\r
162       return new BufferedOutputStream(fos);\r
163     return null;\r
164   }\r
165 \r
166   /**\r
167    * @see uk.ac.vamsas.client.simpleclient.Lock#finalize()\r
168    */\r
169   protected void finalize() throws Throwable {\r
170     release(true); // we explicitly lose the lock here.\r
171     // log.debug("lock closing through garbage collection ?");\r
172     super.finalize();\r
173   }\r
174 \r
175   /*\r
176    * (non-Javadoc)\r
177    * \r
178    * @see uk.ac.vamsas.client.simpleclient.Lock#getLength()\r
179    */\r
180   public long length() {\r
181     if (isLocked()) {\r
182       try {\r
183         return rafile.length();\r
184       } catch (Exception e) {\r
185         log.debug("getLength exception:", e);\r
186       }\r
187     }\r
188     return -1;\r
189   }\r
190 \r
191   public RandomAccessFile getRaFile() throws IOException {\r
192     if (isLocked())\r
193       return rafile;\r
194     else\r
195       log.debug("Failed to getRaFile on " + target);\r
196     return null;\r
197   }\r
198 \r
199   public FileChannel getRaChannel() throws IOException {\r
200     if (isLocked())\r
201       return rafile.getChannel();\r
202     else\r
203       log.debug("Failed to getRaChannel on " + target);\r
204     return null;\r
205   }\r
206 \r
207   public boolean isTargetLockFile(File afile) {\r
208     if (isLocked() && target.equals(afile))\r
209       return true;\r
210     return false;\r
211   }\r
212 \r
213 }\r