OSDN Git Service

from subversion repository
[jindolf/Jindolf.git] / src / main / java / jp / sourceforge / jindolf / InterVMLock.java
1 /*\r
2  * inter-VM file locking\r
3  *\r
4  * Copyright(c) 2009 olyutorskii\r
5  * $Id: InterVMLock.java 952 2009-12-06 14:29:10Z olyutorskii $\r
6  */\r
7 \r
8 package jp.sourceforge.jindolf;\r
9 \r
10 import java.io.File;\r
11 import java.io.FileNotFoundException;\r
12 import java.io.FileOutputStream;\r
13 import java.io.IOException;\r
14 import java.util.Collections;\r
15 import java.util.HashSet;\r
16 import java.util.Set;\r
17 \r
18 /**\r
19  * ロックファイルを用いたVM間ロックオブジェクト。\r
20  * 大昔のNFSではうまく動かないかも。\r
21  * 一度でもロックに成功したロックファイルはVM終了時に消されてしまうので注意。\r
22  */\r
23 public class InterVMLock{\r
24 \r
25     /** 所持するロックオブジェクト一覧。 */\r
26     private static final Set<InterVMLock> ownedLockSet =\r
27             Collections.synchronizedSet(new HashSet<InterVMLock>());\r
28 \r
29     static{\r
30         Runtime runtime = Runtime.getRuntime();\r
31         runtime.addShutdownHook(new Thread(){\r
32             @Override public void run(){ clearOwnedLockSet(); }\r
33         });\r
34     }\r
35 \r
36     /**\r
37      * 所持するロックオブジェクト一覧への登録。\r
38      * @param lock 登録するロックオブジェクト\r
39      */\r
40     private static void addOwnedLock(InterVMLock lock){\r
41         synchronized(ownedLockSet){\r
42             if( ! lock.isFileOwner() ) return;\r
43             ownedLockSet.add(lock);\r
44             lock.getLockFile().deleteOnExit();\r
45         }\r
46         return;\r
47     }\r
48 \r
49     /**\r
50      * 所持するロックオブジェクト一覧からの脱退。\r
51      * @param lock 脱退対象のロックオブジェクト\r
52      */\r
53     private static void removeOwnedLock(InterVMLock lock){\r
54         synchronized(ownedLockSet){\r
55             ownedLockSet.remove(lock);\r
56         }\r
57         return;\r
58     }\r
59 \r
60     /**\r
61      * 所持するロックオブジェクトすべてを解放しロックファイルを削除する。\r
62      */\r
63     private static void clearOwnedLockSet(){\r
64         synchronized(ownedLockSet){\r
65             for(InterVMLock lock : ownedLockSet){\r
66                 if( ! lock.isFileOwner() ) continue;\r
67                 lock.release();\r
68                 try{\r
69                     lock.getLockFile().delete();\r
70                 }catch(SecurityException e){\r
71                     // NOTHING\r
72                 }\r
73             }\r
74             ownedLockSet.clear();\r
75         }\r
76         return;\r
77     }\r
78 \r
79 \r
80     private final File lockFile;\r
81     private boolean isFileOwner = false;\r
82     private FileOutputStream stream = null;\r
83 \r
84     /**\r
85      * コンストラクタ。\r
86      * この時点ではまだロックファイルの存在は確認されない。\r
87      * @param lockFile ロックファイル\r
88      * @throws NullPointerException 引数がnull\r
89      */\r
90     public InterVMLock(File lockFile) throws NullPointerException{\r
91         if(lockFile == null) throw new NullPointerException();\r
92         this.lockFile = lockFile;\r
93         return;\r
94     }\r
95 \r
96     /**\r
97      * ロック対象のファイルを返す。\r
98      * @return ロック対象ファイル\r
99      */\r
100     public File getLockFile(){\r
101         return this.lockFile;\r
102     }\r
103 \r
104     /**\r
105      * ロックファイルがディスク上に存在するか判定する。\r
106      * @return 存在すればtrue\r
107      */\r
108     public boolean isExistsFile(){\r
109         if(this.lockFile.exists()){\r
110             return true;\r
111         }\r
112         return false;\r
113     }\r
114 \r
115     /**\r
116      * このオブジェクトがロックファイルの作者であるか判定する。\r
117      * @return 作者ならtrue\r
118      */\r
119     public synchronized boolean isFileOwner(){\r
120         return this.isFileOwner;\r
121     }\r
122 \r
123     /**\r
124      * ロックファイルのオープン中のストリームを返す。\r
125      * ※ 排他制御目的のリソースなので、\r
126      * 勝手に書き込んだりクローズしたりしないように。\r
127      * @return オープン中のストリーム。オープンしてなければnull\r
128      */\r
129     protected synchronized FileOutputStream getOpenedStream(){\r
130         if(isFileOwner()) return this.stream;\r
131         return null;\r
132     }\r
133 \r
134     /**\r
135      * ロックファイルの強制削除を試みる。\r
136      * @return 強制削除に成功すればtrue\r
137      */\r
138     public synchronized boolean forceRemove(){\r
139         if(isFileOwner()) release();\r
140 \r
141         if( ! isExistsFile() ) return true;\r
142 \r
143         try{\r
144             boolean result = this.lockFile.delete();\r
145             if( ! result ) return false;\r
146         }catch(SecurityException e){\r
147             return false;\r
148         }\r
149 \r
150         if(isExistsFile()) return false;\r
151 \r
152         return true;\r
153     }\r
154 \r
155     /**\r
156      * ロックファイルを生成する。\r
157      * 生成されるロックファイルはVM終了時に削除されるよう登録される。\r
158      * このメソッド実行中にVM終了が重なると、\r
159      * ロックファイルが正しく削除されない場合がありうる。\r
160      * @return 成功すればtrue\r
161      */\r
162     protected synchronized boolean touchLockFile(){\r
163         boolean result = false;\r
164         try{\r
165             result = this.lockFile.createNewFile();\r
166         }catch(IOException e){\r
167             // NOTHING\r
168         }catch(SecurityException e){\r
169             // NOTHING\r
170         }\r
171         if(result == false){\r
172             return false;\r
173         }\r
174 \r
175         try{\r
176             this.isFileOwner = true;\r
177             this.stream = new FileOutputStream(this.lockFile);\r
178         }catch(FileNotFoundException e){\r
179             assert false;\r
180             this.isFileOwner = false;\r
181             this.stream = null;\r
182             try{\r
183                 this.lockFile.delete();\r
184             }catch(SecurityException e2){\r
185                 // NOTHING\r
186             }\r
187             return false;\r
188         }\r
189 \r
190         addOwnedLock(this);\r
191 \r
192         return true;\r
193     }\r
194 \r
195     /**\r
196      * ロックを試みる。\r
197      * このメソッドはブロックしない。\r
198      * @return すでにロック済みもしくはロックに成功すればtrue\r
199      */\r
200     public synchronized boolean tryLock(){\r
201         if( isFileOwner() ) return true;\r
202 \r
203         if(isExistsFile()) return false;\r
204         if(touchLockFile() != true) return false;\r
205 \r
206         return true;\r
207     }\r
208 \r
209     /**\r
210      * ロックを解除する。\r
211      * 自分が作者であるロックファイルは閉じられ削除される。\r
212      * 削除に失敗しても無視。\r
213      */\r
214     public synchronized void release(){\r
215         if( ! isFileOwner() ) return;\r
216 \r
217         try{\r
218             this.stream.close();\r
219         }catch(IOException e){\r
220             // NOTHING\r
221         }finally{\r
222             this.stream = null;\r
223             try{\r
224                 this.lockFile.delete();\r
225             }catch(SecurityException e){\r
226                 // NOTHING\r
227             }finally{\r
228                 removeOwnedLock(this);\r
229                 this.isFileOwner = false;\r
230             }\r
231         }\r
232 \r
233         return;\r
234     }\r
235 \r
236 }\r