View Javadoc

1   /*
2    * Copyright (C) 2007 u6k.yu1@gmail.com, All Rights Reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions
6    * are met:
7    *
8    *    1. Redistributions of source code must retain the above copyright
9    *       notice, this list of conditions and the following disclaimer.
10   *
11   *    2. Redistributions in binary form must reproduce the above copyright
12   *       notice, this list of conditions and the following disclaimer in the
13   *       documentation and/or other materials provided with the distribution.
14   *
15   *    3. Neither the name of Clarkware Consulting, Inc. nor the names of its
16   *       contributors may be used to endorse or promote products derived
17   *       from this software without prior written permission. For written
18   *       permission, please contact clarkware@clarkware.com.
19   *
20   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
21   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
23   * CLARKWARE CONSULTING OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
26   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28   * NEGLIGENCE OR OTHERWISE) ARISING IN  ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   */
31  
32  package jp.gr.java_conf.u6k.filelock;
33  
34  import java.io.Closeable;
35  import java.io.File;
36  import java.io.IOException;
37  import java.io.RandomAccessFile;
38  import java.nio.channels.FileChannel;
39  import java.nio.channels.FileLock;
40  import java.util.ArrayList;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.TreeMap;
44  
45  /**
46   * <p>
47   * 指定したファイルをロックします。ディレクトリを指定した場合、子ファイルを再帰的に検索し、ロックします。ロックに失敗しても例外はスローしません。
48   * </p>
49   * 
50   * @version $Id: FileLockUtil.java 27 2008-03-05 14:44:06Z u6k $
51   */
52  public final class FileLockUtil implements Closeable {
53  
54      /**
55       * <p>
56       * ロックしたファイルのパスと{@link FileLock}インスタンスのマップ。
57       * </p>
58       */
59      private Map<String, FileLock>    lockMap          = new TreeMap<String, FileLock>();
60  
61      /**
62       * <p>
63       * ファイルとチャネルのマップ。
64       * </p>
65       */
66      private Map<String, FileChannel> channelMap       = new TreeMap<String, FileChannel>();
67  
68      /**
69       * <p>
70       * ロックに成功したパスのリスト。
71       * </p>
72       */
73      private List<String>             lockFileList     = new ArrayList<String>();
74  
75      /**
76       * <p>
77       * ロックに失敗したパスのリスト。
78       * </p>
79       */
80      private List<String>             lockFailFileList = new ArrayList<String>();
81  
82      /**
83       * <p>
84       * 指定したファイルをロックし、{@link FileLockUtil}インスタンスを初期化します。ディレクトリを指定した場合、子ファイルを再帰的に検索し、ロックします。ロックに失敗しても例外はスローしません。ロックに成功したパスは{@link #lockFiles()}メソッドで、失敗したパスは{@link #lockFailFiles()}メソッドで取得できます。
85       * </p>
86       * 
87       * @param paths
88       *            ロックするファイルの配列。
89       * @throws NullPointerException
90       *             paths引数がnullの場合。paths配列中にnullが混入していた場合。
91       */
92      public FileLockUtil(String[] paths) {
93          /*
94           * 引数を確認します。
95           */
96          if (paths == null) {
97              throw new NullPointerException("paths");
98          }
99          for (int i = 0; i < paths.length; i++) {
100             if (paths[i] == null) {
101                 throw new NullPointerException("paths[" + i + "] == null");
102             }
103         }
104 
105         /*
106          * ファイルをロックします。
107          */
108         for (String path : paths) {
109             this.lock(path);
110         }
111     }
112 
113     private void lock(String path) {
114         // 正規化したファイルを取得します。
115         File file;
116         try {
117             file = new File(path).getCanonicalFile();
118         } catch (IOException e) {
119             this.lockFailFileList.add(path);
120             return;
121         }
122 
123         if (file.isFile()) {
124             // ファイルであればロックします。
125             try {
126                 FileChannel fch = new RandomAccessFile(file, "rw").getChannel();
127                 this.channelMap.put(file.getAbsolutePath(), fch);
128 
129                 FileLock l = fch.tryLock();
130                 this.lockMap.put(file.getAbsolutePath(), l);
131 
132                 this.lockFileList.add(file.getAbsolutePath());
133             } catch (IOException e) {
134                 this.lockFailFileList.add(file.getAbsolutePath());
135                 return;
136             }
137         } else if (file.isDirectory()) {
138             // ディレクトリであれば、再帰的にファイルをロックします。
139             for (File child : file.listFiles()) {
140                 this.lock(child.getAbsolutePath());
141             }
142         }
143     }
144 
145     /**
146      * <p>
147      * ロックに成功したファイルのパスの配列を返します。
148      * </p>
149      * 
150      * @return ロックに成功したファイルのパスの配列。
151      */
152     public String[] lockFiles() {
153         return this.lockFileList.toArray(new String[0]);
154     }
155 
156     /**
157      * <p>
158      * ロックに失敗したファイルのパスの配列を返します。
159      * </p>
160      * 
161      * @return ロックに失敗したファイルのパスの配列。
162      */
163     public String[] lockFailFiles() {
164         return this.lockFailFileList.toArray(new String[0]);
165     }
166 
167     /**
168      * <p>
169      * インスタンスが保持している全てのリソースを開放します。つまり、ロックしている全てのファイルは開放され、{@link #lockFiles()}、{@link #lockFailFiles()}メソッドは空配列を返すようになります。
170      * </p>
171      */
172     public void close() {
173         for (FileChannel fch : this.channelMap.values()) {
174             try {
175                 fch.close();
176             } catch (IOException e) {
177                 e.printStackTrace();
178             }
179         }
180 
181         this.channelMap.clear();
182         this.lockMap.clear();
183         this.lockFileList.clear();
184         this.lockFailFileList.clear();
185     }
186 
187 }