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間ロックオブジェクト。
22 * <p>大昔のNFSではうまく動かないかも。
23 * <p>一度でもロックに成功したロックファイルは、
26 public class InterVMLock{
28 /** 所持するロックオブジェクト一覧。 */
29 private static final Collection<InterVMLock> OWNEDLOCKSET =
30 Collections.synchronizedCollection(
31 new LinkedList<InterVMLock>()
33 private static final AtomicBoolean SHUTDOWNGOING =
34 new AtomicBoolean(false);
37 Runtime runtime = Runtime.getRuntime();
38 runtime.addShutdownHook(new Thread(){
47 private final File lockFile;
48 private boolean isFileOwner = false;
49 private InputStream stream = null;
50 private final Object thisLock = new Object();
55 * この時点ではまだロックファイルの存在は確認されない。
56 * @param lockFile ロックファイル
57 * @throws NullPointerException 引数がnull
59 public InterVMLock(File lockFile) throws NullPointerException{
60 if(lockFile == null) throw new NullPointerException();
61 this.lockFile = lockFile;
67 * 所持するロックオブジェクトすべてを解放しロックファイルを削除する。
69 private static void shutdown(){
70 if( ! SHUTDOWNGOING.compareAndSet(false, true) ) return;
72 synchronized(OWNEDLOCKSET){
73 for(InterVMLock lock : OWNEDLOCKSET){
82 * シャットダウン処理進行中or完了済みか否か判定する。
83 * @return 進行中or完了済みならtrue
85 protected static boolean isShutdownGoing(){
86 boolean going = SHUTDOWNGOING.get();
92 * このオブジェクトがロックファイルの作者であるか判定する。
95 public boolean isFileOwner(){
96 boolean result = this.isFileOwner;
101 * ロックファイルがディスク上に存在するか判定する。
104 public boolean isExistsFile(){
105 if(this.lockFile.exists()){
113 * <p>勝手に作ったり消したりしないように。
116 public File getLockFile(){
117 return this.lockFile;
121 * ロックファイルのオープン中のストリームを返す。
123 * 勝手に読み込んだりクローズしたりしないように。
124 * @return オープン中のストリーム。オープンしてなければnull
126 protected InputStream getOpenedStream(){
127 InputStream result = null;
129 synchronized(this.thisLock){
130 if(this.isFileOwner){
131 result = this.stream;
140 * @return 強制削除に成功すればtrue
142 public boolean forceRemove(){
143 synchronized(this.thisLock){
144 if(this.isFileOwner) release();
146 if( ! isExistsFile() ) return true;
149 boolean result = this.lockFile.delete();
150 if( ! result ) return false;
151 }catch(SecurityException e){
155 if(isExistsFile()) return false;
164 * @return すでにロック済みもしくはロックに成功すればtrue
166 public boolean tryLock(){
167 if(isShutdownGoing()) return false;
169 synchronized(this.thisLock){
170 if(hasLockedByMe()) return true;
171 if(touchLockFile()) return true;
178 * 自身によるロックに成功しているか判定する。
179 * @return 自身によるロック中であればtrue
181 public boolean hasLockedByMe(){
183 synchronized(this.thisLock){
184 if( ! this.isFileOwner ){
186 }else if( ! this.lockFile.exists() ){
187 this.isFileOwner = false;
197 * ロックファイルを生成する。{@link #tryLock()}の下請け。
198 * 生成されるロックファイルはVM終了時に削除されるよう登録される。
199 * このメソッド実行中にVM終了が重なると、
200 * ロックファイルが正しく削除されない場合がありうる。
203 protected boolean touchLockFile(){
204 synchronized(this.thisLock){
205 boolean created = false;
207 created = this.lockFile.createNewFile();
208 }catch(IOException e){
209 assert true; // IGNORE
210 }catch(SecurityException e){
211 assert true; // IGNORE
214 this.isFileOwner = true;
215 this.lockFile.deleteOnExit();
217 this.isFileOwner = false;
221 if( ! created ) return false;
224 this.stream = new FileInputStream(this.lockFile);
225 }catch(FileNotFoundException e){
226 this.isFileOwner = false;
229 this.lockFile.delete();
230 }catch(SecurityException e2){
231 assert true; // IGNORE
236 synchronized(OWNEDLOCKSET){
237 OWNEDLOCKSET.add(this);
246 * <p>自分が作者であるロックファイルは閉じられ削除される。
248 * <p>シャットダウン処理進行中の場合は何もしない。
250 public void release(){
251 if(isShutdownGoing()) return;
255 synchronized(OWNEDLOCKSET){
256 OWNEDLOCKSET.remove(this);
263 * ロックを解除する。{@link #release()}の下請け。
264 * <p>自分が作者であるロックファイルは閉じられ削除される。
266 * <p>シャットダウン処理進行中か否かは無視される。
268 protected void releaseImpl(){
269 synchronized(this.thisLock){
270 if( ! this.isFileOwner ) return;
274 }catch(IOException e){
275 assert true; // IGNORE
279 this.lockFile.delete();
280 }catch(SecurityException e){
281 assert true; // IGNORE
283 this.isFileOwner = false;
291 // TODO {@link java.nio.channels.FileChannnel}によるロック機構の併用。