OSDN Git Service

74b474e7bcecff147ff3ff2073944b469d15c4df
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / config / FileManager.java
1 package cx.fbn.nevernote.config;
2
3 import java.io.File;
4 import java.io.FileFilter;
5 import java.util.regex.Pattern;
6
7 /**
8  * Provides access to NeverNote standard runtime directories.
9  *
10  * @author Nick Clarke
11  */
12 public class FileManager {
13
14     private static final Pattern ALL_PATH_SEPARATORS_REGEX = Pattern.compile("[/\\\\]");
15
16     private final String homeDirPath;
17     private final File homeDir;
18
19     private final String dbDirPath;
20     private final File dbDir;
21     private final String logsDirPath;
22     private final File logsDir;
23     private final String imagesDirPath;
24     private final File imagesDir;
25     private final String qssDirPath;
26     private final File qssDir;
27     private final String resDirPath;
28     private final File resDir;
29     private final String xmlDirPath;
30     private final File xmlDir;
31
32     /**
33      * Check or create the db, log and res directories, and purge files from 'res' .
34      *
35      * @param homeDirPath the installation dir containing db/log/res directories, must exist
36      */
37     public FileManager(String homeDirPath) throws InitializationException {
38         if (homeDirPath == null) {
39             throw new IllegalArgumentException("homeDirPath must not be null");
40         }
41
42         this.homeDir = new File(toPlatformPathSeparator(homeDirPath));
43         checkExistingWriteableDir(homeDir);
44         this.homeDirPath = slashTerminatePath(homeDir.getPath());
45
46         // Read-only
47         imagesDir = new File(homeDir, "images");
48         checkExistingReadableDir(imagesDir);
49         imagesDirPath = slashTerminatePath(imagesDir.getPath());
50
51         qssDir = new File(homeDir, "qss");
52         checkExistingReadableDir(qssDir);
53         qssDirPath = slashTerminatePath(qssDir.getPath());
54
55         xmlDir = new File(homeDir, "xml");
56         checkExistingReadableDir(xmlDir);
57         xmlDirPath = slashTerminatePath(xmlDir.getPath());
58
59         // Read-write
60         dbDir = new File(homeDir, "db");
61         createDirOrCheckWriteable(dbDir);
62         dbDirPath = slashTerminatePath(dbDir.getPath());
63
64         logsDir = new File(homeDir, "logs");
65         createDirOrCheckWriteable(logsDir);
66         logsDirPath = slashTerminatePath(logsDir.getPath());
67
68         resDir = new File(homeDir, "res");
69         createDirOrCheckWriteable(resDir);
70         resDirPath = slashTerminatePath(resDir.getPath());
71
72         deleteTopLevelFiles(resDir);
73     }
74
75     /**
76      * Get the path to the base installation directory, terminated with {@link File#separator}.
77      * This will contain backslashes on Windows.
78      */
79     public String getHomeDirPath() {
80         return homeDirPath;
81     }
82
83     /**
84      * Get a file below the 'db' directory.
85      */
86     public File getDbDirFile(String relativePath) {
87         return new File(dbDir, toPlatformPathSeparator(relativePath));
88     }
89
90     /**
91      * Get a file below the base installation directory.
92      */
93     public File getHomeDirFile(String relativePath) {
94         return new File(homeDir, toPlatformPathSeparator(relativePath));
95     }
96
97     /**
98      * Get a path below the base installation directory, using native {@link File#separator}.
99      * This will contain backslashes on Windows.
100      */
101     public String getHomeDirPath(String relativePath) {
102         return homeDirPath + toPlatformPathSeparator(relativePath);
103     }
104
105     /**
106      * Get a path below the 'db' directory, using native {@link File#separator}.
107      * This will contain backslashes on Windows.
108      */
109     public String getDbDirPath(String relativePath) {
110         return dbDirPath + toPlatformPathSeparator(relativePath);
111     }
112
113     /**
114      * Get a file below the 'images' directory.
115      */
116     public File getImageDirFile(String relativePath) {
117         return new File(imagesDir, toPlatformPathSeparator(relativePath));
118     }
119
120     /**
121      * Get a path below the 'images' directory, using native {@link File#separator}.
122      * This will contain backslashes on Windows.
123      */
124     public String getImageDirPath(String relativePath) {
125         return imagesDirPath + toPlatformPathSeparator(relativePath);
126     }
127
128     /**
129      * Get a file below the 'logs' directory.
130      */
131     public File getLogsDirFile(String relativePath) {
132         return new File(logsDir, toPlatformPathSeparator(relativePath));
133     }
134
135     /**
136      * Get a path below the 'qss' directory, using native {@link File#separator}.
137      * This will contain backslashes on Windows.
138      */
139     public String getQssDirPath(String relativePath) {
140         return qssDirPath + toPlatformPathSeparator(relativePath);
141     }
142
143     /**
144      * Get a path to the 'res' directory, terminated with native {@link File#separator}.
145      * This will contain backslashes on Windows.
146      */
147     public String getResDirPath() {
148         return resDirPath;
149     }
150
151     /**
152      * Get a path below the 'res' directory, using native {@link File#separator}.
153      * This will contain backslashes on Windows.
154      */
155     public String getResDirPath(String relativePath) {
156         return resDirPath + toPlatformPathSeparator(relativePath);
157     }
158
159     /**
160      * Get a file below the 'xml' directory.
161      */
162     public File getXMLDirFile(String relativePath) {
163         return new File(xmlDir, toPlatformPathSeparator(relativePath));
164     }
165
166     private static String toPlatformPathSeparator(String relativePath) {
167         return ALL_PATH_SEPARATORS_REGEX.matcher(relativePath).replaceAll(File.separator);
168     }
169
170     private static String slashTerminatePath(String path) {
171         if (!path.substring(path.length() - 1).equals(File.separator)) {
172             return path + File.separator;
173         }
174         return path;
175     }
176
177     /**
178      * Delete first-level files (but not directories) from the directory.
179      *
180      * @throws InitializationException for file deletion failures
181      */
182     private static void deleteTopLevelFiles(File dir) throws InitializationException {
183         File[] toDelete = dir.listFiles(new FileFilter() {
184             @Override
185             public boolean accept(File pathname) {
186                 return pathname.isFile();
187             }
188         });
189         for (File f : toDelete) {
190             if (!f.delete()) {
191                 throw new InitializationException("Failed to delete file: '" + f + "'");
192             }
193         }
194     }
195
196     /**
197      * @throws InitializationException for bad file permissions, or a file instead of a directory
198      */
199     private static void createDirOrCheckWriteable(File dir) throws InitializationException {
200         if (dir.isDirectory()) {
201             // Dir exists, check permissions
202             if (!dir.canRead()) {
203                 throw new InitializationException("Directory '" + dir + "' does not have read permission");
204             }
205             if (!dir.canWrite()) {
206                 throw new InitializationException("Directory '" + dir + "' does not have write permission");
207             }
208         } else if (!dir.exists()) {
209             if (!dir.mkdirs()) {
210                 throw new InitializationException("Failed to create directory '" + dir + "'");
211             }
212         } else {
213             throw new InitializationException("Expected directory '" + dir + "' but found a file instead");
214         }
215     }
216
217     /**
218      * @throws InitializationException if non-existent, bad file permissions, or a file instead of a directory
219      */
220     private static void checkExistingReadableDir(File dir) throws InitializationException {
221         if (dir.isDirectory()) {
222             // Dir exists, check permissions
223             if (!dir.canRead()) {
224                 throw new InitializationException("Directory '" + dir + "' does not have read permission");
225             }
226         } else if (!dir.exists()) {
227             throw new InitializationException("Directory '" + dir + "' does not exist");
228         } else {
229             throw new InitializationException("Expected directory '" + dir + "' but found a file instead");
230         }
231     }
232
233     /**
234      * @throws InitializationException if non-existent, bad file permissions, or a file instead of a directory
235      */
236     private static void checkExistingWriteableDir(File dir) throws InitializationException {
237         checkExistingReadableDir(dir);
238         if (!dir.canWrite()) {
239             throw new InitializationException("Directory '" + dir + "' does not have write permission");
240         }
241     }
242 }