1 package cx.fbn.nevernote.config;
4 import java.io.FileFilter;
5 import java.util.regex.Pattern;
8 * Provides access to NeverNote standard runtime directories.
12 public class FileManager {
14 private static final Pattern ALL_PATH_SEPARATORS_REGEX = Pattern.compile("[/\\\\]");
16 private final String homeDirPath;
17 private final File homeDir;
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;
33 * Check or create the db, log and res directories, and purge files from 'res' .
35 * @param homeDirPath the installation dir containing db/log/res directories, must exist
37 public FileManager(String homeDirPath) throws InitializationException {
38 if (homeDirPath == null) {
39 throw new IllegalArgumentException("homeDirPath must not be null");
42 this.homeDir = new File(toPlatformPathSeparator(homeDirPath));
43 checkExistingWriteableDir(homeDir);
44 this.homeDirPath = slashTerminatePath(homeDir.getPath());
47 imagesDir = new File(homeDir, "images");
48 checkExistingReadableDir(imagesDir);
49 imagesDirPath = slashTerminatePath(imagesDir.getPath());
51 qssDir = new File(homeDir, "qss");
52 checkExistingReadableDir(qssDir);
53 qssDirPath = slashTerminatePath(qssDir.getPath());
55 xmlDir = new File(homeDir, "xml");
56 checkExistingReadableDir(xmlDir);
57 xmlDirPath = slashTerminatePath(xmlDir.getPath());
60 dbDir = new File(homeDir, "db");
61 createDirOrCheckWriteable(dbDir);
62 dbDirPath = slashTerminatePath(dbDir.getPath());
64 logsDir = new File(homeDir, "logs");
65 createDirOrCheckWriteable(logsDir);
66 logsDirPath = slashTerminatePath(logsDir.getPath());
68 resDir = new File(homeDir, "res");
69 createDirOrCheckWriteable(resDir);
70 resDirPath = slashTerminatePath(resDir.getPath());
72 deleteTopLevelFiles(resDir);
76 * Get the path to the base installation directory, terminated with {@link File#separator}.
77 * This will contain backslashes on Windows.
79 public String getHomeDirPath() {
84 * Get a file below the 'db' directory.
86 public File getDbDirFile(String relativePath) {
87 return new File(dbDir, toPlatformPathSeparator(relativePath));
91 * Get a file below the base installation directory.
93 public File getHomeDirFile(String relativePath) {
94 return new File(homeDir, toPlatformPathSeparator(relativePath));
98 * Get a path below the base installation directory, using native {@link File#separator}.
99 * This will contain backslashes on Windows.
101 public String getHomeDirPath(String relativePath) {
102 return homeDirPath + toPlatformPathSeparator(relativePath);
106 * Get a path below the 'db' directory, using native {@link File#separator}.
107 * This will contain backslashes on Windows.
109 public String getDbDirPath(String relativePath) {
110 return dbDirPath + toPlatformPathSeparator(relativePath);
114 * Get a file below the 'images' directory.
116 public File getImageDirFile(String relativePath) {
117 return new File(imagesDir, toPlatformPathSeparator(relativePath));
121 * Get a path below the 'images' directory, using native {@link File#separator}.
122 * This will contain backslashes on Windows.
124 public String getImageDirPath(String relativePath) {
125 return imagesDirPath + toPlatformPathSeparator(relativePath);
129 * Get a file below the 'logs' directory.
131 public File getLogsDirFile(String relativePath) {
132 return new File(logsDir, toPlatformPathSeparator(relativePath));
136 * Get a path below the 'qss' directory, using native {@link File#separator}.
137 * This will contain backslashes on Windows.
139 public String getQssDirPath(String relativePath) {
140 return qssDirPath + toPlatformPathSeparator(relativePath);
144 * Get a path to the 'res' directory, terminated with native {@link File#separator}.
145 * This will contain backslashes on Windows.
147 public String getResDirPath() {
152 * Get a path below the 'res' directory, using native {@link File#separator}.
153 * This will contain backslashes on Windows.
155 public String getResDirPath(String relativePath) {
156 return resDirPath + toPlatformPathSeparator(relativePath);
160 * Get a file below the 'xml' directory.
162 public File getXMLDirFile(String relativePath) {
163 return new File(xmlDir, toPlatformPathSeparator(relativePath));
166 private static String toPlatformPathSeparator(String relativePath) {
167 return ALL_PATH_SEPARATORS_REGEX.matcher(relativePath).replaceAll(File.separator);
170 private static String slashTerminatePath(String path) {
171 if (!path.substring(path.length() - 1).equals(File.separator)) {
172 return path + File.separator;
178 * Delete first-level files (but not directories) from the directory.
180 * @throws InitializationException for file deletion failures
182 private static void deleteTopLevelFiles(File dir) throws InitializationException {
183 File[] toDelete = dir.listFiles(new FileFilter() {
185 public boolean accept(File pathname) {
186 return pathname.isFile();
189 for (File f : toDelete) {
191 throw new InitializationException("Failed to delete file: '" + f + "'");
197 * @throws InitializationException for bad file permissions, or a file instead of a directory
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");
205 if (!dir.canWrite()) {
206 throw new InitializationException("Directory '" + dir + "' does not have write permission");
208 } else if (!dir.exists()) {
210 throw new InitializationException("Failed to create directory '" + dir + "'");
213 throw new InitializationException("Expected directory '" + dir + "' but found a file instead");
218 * @throws InitializationException if non-existent, bad file permissions, or a file instead of a directory
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");
226 } else if (!dir.exists()) {
227 throw new InitializationException("Directory '" + dir + "' does not exist");
229 throw new InitializationException("Expected directory '" + dir + "' but found a file instead");
234 * @throws InitializationException if non-existent, bad file permissions, or a file instead of a directory
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");