1
20 package org.crosswire.jsword.book.sword;
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FilenameFilter;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.net.URI;
28 import java.util.ArrayList;
29 import java.util.List;
30
31 import org.crosswire.common.util.CWProject;
32 import org.crosswire.common.util.OSType;
33 import org.crosswire.common.util.PropertyMap;
34 import org.crosswire.common.util.StringUtil;
35 import org.crosswire.jsword.book.BookException;
36 import org.crosswire.jsword.book.Books;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
47 public final class SwordBookPath {
48
51 private SwordBookPath() {
52 }
53
54
61 public static void setAugmentPath(File[] theNewDirs) throws BookException {
62 File[] newDirs = theNewDirs;
63 if (newDirs == null) {
64 return;
65 }
66
67 SwordBookPath.augmentPath = newDirs.clone();
68
69 Books.installed().registerDriver(SwordBookDriver.instance());
71 }
72
73
78 public static File[] getAugmentPath() {
79 return augmentPath.clone();
80 }
81
82
89 public static File[] getSwordPath() {
90 ArrayList<File> swordPath = new ArrayList<File>();
91
92 swordPath.add(getSwordDownloadDir());
94
95 if (augmentPath != null) {
97 for (int i = 0; i < augmentPath.length; i++) {
98 File path = augmentPath[i];
99 if (!swordPath.contains(path)) {
100 swordPath.add(path);
101 }
102 }
103 }
104
105 File[] defaultPath = getDefaultPaths();
106 if (defaultPath != null) {
108 for (int i = 0; i < defaultPath.length; i++) {
109 File path = defaultPath[i];
110 if (!swordPath.contains(path)) {
111 swordPath.add(path);
112 }
113 }
114 }
115
116 return swordPath.toArray(new File[swordPath.size()]);
117 }
118
119
126 public static String[] getBookList(File bookDir) {
127 return bookDir.list(new CustomFilenameFilter());
128 }
129
130
134 private static File[] getDefaultPaths() {
135 migrateBookDir();
137
138 List<File> bookDirs = new ArrayList<File>();
139
140 String home = System.getProperty(PROPERTY_USER_HOME);
141
142 readSwordConf(bookDirs, ".");
144
145 testDefaultPath(bookDirs, ".");
147
148 testDefaultPath(bookDirs, ".." + File.separator + DIR_SWORD_LIBRARY);
150
151 String swordhome = System.getProperty(PROPERTY_SWORD_HOME);
155 if (swordhome != null) {
156 testDefaultPath(bookDirs, swordhome);
157
158 testDefaultPath(bookDirs, swordhome + File.separator + ".." + File.separator + DIR_SWORD_LIBRARY);
160 }
161
162 if (System.getProperty("os.name").startsWith("Windows")) {
163 testDefaultPath(bookDirs, DIR_WINDOWS_DEFAULT);
164 testDefaultPath(bookDirs, DIR_WINDOWS_DEFAULT + File.separator + ".." + File.separator + DIR_SWORD_LIBRARY);
166 }
167
168 readSwordConf(bookDirs, home + File.separator + DIR_SWORD_CONF);
170
171 String[] sysconfigPaths = StringUtil.split(DIR_SWORD_GLOBAL_CONF, ':');
173 for (int i = 0; i < sysconfigPaths.length; i++) {
174 readSwordConf(bookDirs, sysconfigPaths[i]);
175 }
176
177 URI userDataArea = OSType.getOSType().getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
178
179 testDefaultPath(bookDirs, new File(userDataArea.getPath()));
181
182 testDefaultPath(bookDirs, new File(CWProject.instance().getWritableProjectDir().getPath()));
187
188 return bookDirs.toArray(new File[bookDirs.size()]);
189 }
190
191 private static void readSwordConf(List<File> bookDirs, File swordConfDir) {
192 File sysconfig = new File(swordConfDir, SWORD_GLOBAL_CONF);
193 if (sysconfig.canRead()) {
194 InputStream is = null;
195 try {
196 PropertyMap prop = new PropertyMap();
197 is = new FileInputStream(sysconfig);
198 prop.load(is);
199 String datapath = prop.get(DATA_PATH);
200 testDefaultPath(bookDirs, datapath);
201 datapath = prop.get(AUGMENT_PATH);
202 testDefaultPath(bookDirs, datapath);
203 } catch (IOException ex) {
204 log.warn("Failed to read system config file", ex);
205 } finally {
206 if (is != null) {
207 try {
208 is.close();
209 } catch (IOException e) {
210 log.warn("Failed to close system config file", e);
211 }
212 }
213 }
214 }
215 }
216
217 private static void readSwordConf(List<File> bookDirs, String swordConfDir) {
218 readSwordConf(bookDirs, new File(swordConfDir));
219 }
220
221
230 private static void testDefaultPath(List<File> bookDirs, File path) {
231 if (path == null) {
232 return;
233 }
234
235 File mods = new File(path, SwordConstants.DIR_CONF);
236 if (mods.isDirectory() && mods.canRead()) {
237 bookDirs.add(path);
238 }
239 }
240
241
250 private static void testDefaultPath(List<File> bookDirs, String path) {
251 if (path == null) {
252 return;
253 }
254
255 testDefaultPath(bookDirs, new File(path));
256 }
257
258 private static File getDefaultDownloadPath() {
259 File path = null;
260 File[] possiblePaths = getDefaultPaths();
261
262 if (possiblePaths != null) {
263 for (int i = 0; i < possiblePaths.length; i++) {
264 File mods = new File(possiblePaths[i], SwordConstants.DIR_CONF);
265 if (mods.canWrite()) {
266 path = possiblePaths[i];
267 break;
268 }
269 }
270 }
271
272 if (path == null) {
275 URI userDataArea = OSType.getOSType().getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
276 path = new File(userDataArea.getPath());
277 }
278
279 return path;
280 }
281
282 private static void migrateBookDir() {
283 URI userDataArea = OSType.getOSType().getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
285
286 File swordBookPath = new File(userDataArea.getPath());
287
288 File oldPath = new File(CWProject.instance().getDeprecatedWritableProjectDir().getPath());
291
292 if (oldPath.isDirectory()) {
293 migrateBookDir(oldPath, swordBookPath);
294 return;
295 }
296
297 oldPath = new File(CWProject.instance().getWritableProjectDir().getPath());
299
300 if (oldPath.isDirectory()) {
301 migrateBookDir(oldPath, swordBookPath);
302 return;
303 }
304
305 oldPath = new File(OSType.DEFAULT.getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT).getPath());
307 if (oldPath.isDirectory()) {
308 migrateBookDir(oldPath, swordBookPath);
309 }
310 }
311
312 private static void migrateBookDir(File oldPath, File newPath) {
313 File oldDataDir = new File(oldPath, SwordConstants.DIR_DATA);
315 File newDataDir = new File(newPath, SwordConstants.DIR_DATA);
316 File oldConfDir = new File(oldPath, SwordConstants.DIR_CONF);
317 File newConfDir = new File(newPath, SwordConstants.DIR_CONF);
318
319 if (!migrate(oldDataDir, newDataDir)) {
321 return;
322 }
323
324 if (!migrate(oldConfDir, newConfDir)) {
326 migrate(newDataDir, oldDataDir);
328 }
329 }
330
331 private static boolean migrate(File oldPath, File newPath) {
332 if (oldPath.equals(newPath) || !oldPath.exists()) {
333 return true;
334 }
335
336 File parent = newPath.getParentFile();
338 if (!parent.exists() && !parent.mkdirs()) {
339 return false;
340 }
341
342 return oldPath.renameTo(newPath);
343 }
344
345
351 public static File getSwordDownloadDir() {
352 if (overrideDownloadDir != null) {
353 return overrideDownloadDir;
354 }
355 return defaultDownloadDir;
356 }
357
358
361 public static File getDownloadDir() {
362 return overrideDownloadDir;
363 }
364
365
369 public static void setDownloadDir(File dlDir) {
370 if (!"".equals(dlDir.getPath())) {
371 overrideDownloadDir = dlDir;
372 log.debug("Setting sword download directory to: {}", dlDir);
373 }
374 }
375
376
380 static class CustomFilenameFilter implements FilenameFilter {
381
386 public boolean accept(File parent, String name) {
387 return !name.startsWith(PREFIX_GLOBALS) && name.endsWith(SwordConstants.EXTENSION_CONF);
388 }
389 }
390
391
394 private static final String DIR_WINDOWS_DEFAULT = "C:\\Program Files\\CrossWire\\The SWORD Project";
395
396
399 private static final String DIR_SWORD_LIBRARY = "library";
400
401
404 private static final String DIR_SWORD_CONF = ".sword";
405
406
409 private static final String DIR_SWORD_CONF_ALT = "Sword";
410
411
414 private static final String SWORD_GLOBAL_CONF = "sword.conf";
415
416
419 private static final String DIR_SWORD_GLOBAL_CONF = "/etc:/usr/local/etc";
420
421
424 private static final String DATA_PATH = "DataPath";
425
426
429 private static final String AUGMENT_PATH = "AugmentPath";
430
431
434 private static final String PROPERTY_SWORD_HOME = "sword.home";
435
436
439 private static final String PROPERTY_USER_HOME = "user.home";
440
441
444 private static final String PREFIX_GLOBALS = "globals.";
445
446
449 private static File[] augmentPath = new File[0];
450
451
454 private static File defaultDownloadDir = getDefaultDownloadPath();
455
456
459 private static File overrideDownloadDir;
460
461
464 private static final Logger log = LoggerFactory.getLogger(SwordBookPath.class);
465
466 }
467