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(){
49 private final File lockFile;
50 private boolean isFileOwner = false;
51 private InputStream stream = null;
52 private final Object thisLock = new Object();
57 * この時点ではまだロックファイルの存在は確認されない。
58 * @param lockFile ロックファイル
59 * @throws NullPointerException 引数がnull
61 public InterVMLock(File lockFile) throws NullPointerException{
62 if(lockFile == null) throw new NullPointerException();
63 this.lockFile = lockFile;
69 * 所持するロックオブジェクトすべてを解放しロックファイルを削除する。
71 private static void shutdown(){
72 if( ! SHUTDOWNGOING.compareAndSet(false, true) ) return;
74 synchronized(OWNEDLOCKSET){
75 for(InterVMLock lock : OWNEDLOCKSET){
84 * シャットダウン処理進行中or完了済みか否か判定する。
85 * @return 進行中or完了済みならtrue
87 protected static boolean isShutdownGoing(){
88 boolean going = SHUTDOWNGOING.get();
94 * このオブジェクトがロックファイルの作者であるか判定する。
97 public boolean isFileOwner(){
98 boolean result = this.isFileOwner;
103 * ロックファイルがディスク上に存在するか判定する。
106 public boolean isExistsFile(){
107 if(this.lockFile.exists()){
116 * <p>勝手に作ったり消したりしないように。
120 public File getLockFile(){
121 return this.lockFile;
125 * ロックファイルのオープン中のストリームを返す。
127 * 勝手に読み込んだりクローズしたりしないように。
128 * @return オープン中のストリーム。オープンしてなければnull
130 protected InputStream getOpenedStream(){
131 InputStream result = null;
133 synchronized(this.thisLock){
134 if(this.isFileOwner){
135 result = this.stream;
144 * @return 強制削除に成功すればtrue
146 public boolean forceRemove(){
147 synchronized(this.thisLock){
148 if(this.isFileOwner) release();
150 if( ! isExistsFile() ) return true;
153 boolean result = this.lockFile.delete();
154 if( ! result ) return false;
155 }catch(SecurityException e){
159 if(isExistsFile()) return false;
168 * @return すでにロック済みもしくはロックに成功すればtrue
170 public boolean tryLock(){
171 if(isShutdownGoing()) return false;
173 synchronized(this.thisLock){
174 if(hasLockedByMe()) return true;
175 if(touchLockFile()) return true;
182 * 自身によるロックに成功しているか判定する。
183 * @return 自身によるロック中であればtrue
185 public boolean hasLockedByMe(){
187 synchronized(this.thisLock){
188 if( ! this.isFileOwner ){
190 }else if( ! this.lockFile.exists() ){
191 this.isFileOwner = false;
201 * ロックファイルを生成する。{@link #tryLock()}の下請け。
202 * 生成されるロックファイルはVM終了時に削除されるよう登録される。
203 * このメソッド実行中にVM終了が重なると、
204 * ロックファイルが正しく削除されない場合がありうる。
207 protected boolean touchLockFile(){
208 synchronized(this.thisLock){
209 boolean created = false;
211 created = this.lockFile.createNewFile();
212 }catch(IOException e){
213 assert true; // IGNORE
214 }catch(SecurityException e){
215 assert true; // IGNORE
218 this.isFileOwner = true;
219 this.lockFile.deleteOnExit();
221 this.isFileOwner = false;
225 if( ! created ) return false;
228 this.stream = new FileInputStream(this.lockFile);
229 }catch(FileNotFoundException e){
230 this.isFileOwner = false;
233 this.lockFile.delete();
234 }catch(SecurityException e2){
235 assert true; // IGNORE
240 synchronized(OWNEDLOCKSET){
241 OWNEDLOCKSET.add(this);
251 * <p>自分が作者であるロックファイルは閉じられ削除される。
255 * <p>シャットダウン処理進行中の場合は何もしない。
257 public void release(){
258 if(isShutdownGoing()) return;
262 synchronized(OWNEDLOCKSET){
263 OWNEDLOCKSET.remove(this);
270 * ロックを解除する。{@link #release()}の下請け。
272 * <p>自分が作者であるロックファイルは閉じられ削除される。
276 * <p>シャットダウン処理進行中か否かは無視される。
278 protected void releaseImpl(){
279 synchronized(this.thisLock){
280 if( ! this.isFileOwner ) return;
284 }catch(IOException e){
285 assert true; // IGNORE
289 this.lockFile.delete();
290 }catch(SecurityException e){
291 assert true; // IGNORE
293 this.isFileOwner = false;
301 // TODO {@link java.nio.channels.FileChannnel}によるロック機構の併用。