2 * inter-VM file locking
4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sfjp.jindolf.config;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.LinkedList;
18 import java.util.concurrent.atomic.AtomicBoolean;
21 * ロックファイルを用いたVM間ロックオブジェクト。
23 * <p>大昔のNFSではうまく動かないかも。
25 * <p>一度でもロックに成功したロックファイルは、
28 public class InterVMLock{
30 /** 所持するロックオブジェクト一覧。 */
31 private static final Collection<InterVMLock> OWNEDLOCKSET =
32 Collections.synchronizedCollection(
33 new LinkedList<InterVMLock>()
35 private static final AtomicBoolean SHUTDOWNGOING =
36 new AtomicBoolean(false);
39 Runtime runtime = Runtime.getRuntime();
40 runtime.addShutdownHook(new Thread(){
50 private final File lockFile;
51 private boolean isFileOwner = false;
52 private InputStream stream = null;
53 private final Object thisLock = new Object();
58 * この時点ではまだロックファイルの存在は確認されない。
59 * @param lockFile ロックファイル
60 * @throws NullPointerException 引数がnull
62 public InterVMLock(File lockFile) throws NullPointerException{
63 if(lockFile == null) throw new NullPointerException();
64 this.lockFile = lockFile;
70 * 所持するロックオブジェクトすべてを解放しロックファイルを削除する。
72 private static void shutdown(){
73 if( ! SHUTDOWNGOING.compareAndSet(false, true) ) return;
75 synchronized(OWNEDLOCKSET){
76 for(InterVMLock lock : OWNEDLOCKSET){
85 * シャットダウン処理進行中or完了済みか否か判定する。
86 * @return 進行中or完了済みならtrue
88 protected static boolean isShutdownGoing(){
89 boolean going = SHUTDOWNGOING.get();
95 * このオブジェクトがロックファイルの作者であるか判定する。
98 public boolean isFileOwner(){
99 boolean result = this.isFileOwner;
104 * ロックファイルがディスク上に存在するか判定する。
107 public boolean isExistsFile(){
108 if(this.lockFile.exists()){
117 * <p>勝手に作ったり消したりしないように。
121 public File getLockFile(){
122 return this.lockFile;
126 * ロックファイルのオープン中のストリームを返す。
128 * 勝手に読み込んだりクローズしたりしないように。
129 * @return オープン中のストリーム。オープンしてなければnull
131 protected InputStream getOpenedStream(){
132 InputStream result = null;
134 synchronized(this.thisLock){
135 if(this.isFileOwner){
136 result = this.stream;
145 * @return 強制削除に成功すればtrue
147 public boolean forceRemove(){
148 synchronized(this.thisLock){
149 if(this.isFileOwner) release();
151 if( ! isExistsFile() ) return true;
154 boolean result = this.lockFile.delete();
155 if( ! result ) return false;
156 }catch(SecurityException e){
160 if(isExistsFile()) return false;
169 * @return すでにロック済みもしくはロックに成功すればtrue
171 public boolean tryLock(){
172 if(isShutdownGoing()) return false;
174 synchronized(this.thisLock){
175 if(hasLockedByMe()) return true;
176 if(touchLockFile()) return true;
183 * 自身によるロックに成功しているか判定する。
184 * @return 自身によるロック中であればtrue
186 public boolean hasLockedByMe(){
188 synchronized(this.thisLock){
189 if( ! this.isFileOwner ){
191 }else if( ! this.lockFile.exists() ){
192 this.isFileOwner = false;
202 * ロックファイルを生成する。{@link #tryLock()}の下請け。
203 * 生成されるロックファイルはVM終了時に削除されるよう登録される。
204 * このメソッド実行中にVM終了が重なると、
205 * ロックファイルが正しく削除されない場合がありうる。
208 protected boolean touchLockFile(){
209 synchronized(this.thisLock){
210 boolean created = false;
212 created = this.lockFile.createNewFile();
213 }catch(IOException e){
214 assert true; // IGNORE
215 }catch(SecurityException e){
216 assert true; // IGNORE
219 this.isFileOwner = true;
220 this.lockFile.deleteOnExit();
222 this.isFileOwner = false;
226 if( ! created ) return false;
229 this.stream = new FileInputStream(this.lockFile);
230 }catch(FileNotFoundException e){
231 this.isFileOwner = false;
234 this.lockFile.delete();
235 }catch(SecurityException e2){
236 assert true; // IGNORE
241 synchronized(OWNEDLOCKSET){
242 OWNEDLOCKSET.add(this);
252 * <p>自分が作者であるロックファイルは閉じられ削除される。
256 * <p>シャットダウン処理進行中の場合は何もしない。
258 public void release(){
259 if(isShutdownGoing()) return;
263 synchronized(OWNEDLOCKSET){
264 OWNEDLOCKSET.remove(this);
271 * ロックを解除する。{@link #release()}の下請け。
273 * <p>自分が作者であるロックファイルは閉じられ削除される。
277 * <p>シャットダウン処理進行中か否かは無視される。
279 protected void releaseImpl(){
280 synchronized(this.thisLock){
281 if( ! this.isFileOwner ) return;
285 }catch(IOException e){
286 assert true; // IGNORE
290 this.lockFile.delete();
291 }catch(SecurityException e){
292 assert true; // IGNORE
294 this.isFileOwner = false;
302 // TODO {@link java.nio.channels.FileChannnel}によるロック機構の併用。