tracer: fix DEBUG=0
[fanfix.git] / src / be / nikiroo / fanfix / Instance.java
1 package be.nikiroo.fanfix;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.Date;
6
7 import be.nikiroo.fanfix.bundles.Config;
8 import be.nikiroo.fanfix.bundles.ConfigBundle;
9 import be.nikiroo.fanfix.bundles.StringId;
10 import be.nikiroo.fanfix.bundles.StringIdBundle;
11 import be.nikiroo.fanfix.bundles.StringIdGuiBundle;
12 import be.nikiroo.fanfix.bundles.UiConfig;
13 import be.nikiroo.fanfix.bundles.UiConfigBundle;
14 import be.nikiroo.fanfix.library.BasicLibrary;
15 import be.nikiroo.fanfix.library.CacheLibrary;
16 import be.nikiroo.fanfix.library.LocalLibrary;
17 import be.nikiroo.fanfix.library.RemoteLibrary;
18 import be.nikiroo.utils.Cache;
19 import be.nikiroo.utils.IOUtils;
20 import be.nikiroo.utils.Proxy;
21 import be.nikiroo.utils.TempFiles;
22 import be.nikiroo.utils.TraceHandler;
23 import be.nikiroo.utils.resources.Bundles;
24
25 /**
26 * Global state for the program (services and singletons).
27 *
28 * @author niki
29 */
30 public class Instance {
31 private static ConfigBundle config;
32 private static UiConfigBundle uiconfig;
33 private static StringIdBundle trans;
34 private static DataLoader cache;
35 private static StringIdGuiBundle transGui;
36 private static BasicLibrary lib;
37 private static File coverDir;
38 private static File readerTmp;
39 private static File remoteDir;
40 private static String configDir;
41 private static TraceHandler tracer;
42 private static TempFiles tempFiles;
43
44 static {
45 // Before we can configure it:
46 Boolean debug = checkEnv("DEBUG");
47 boolean trace = debug != null && debug;
48 tracer = new TraceHandler(true, trace, trace);
49
50 // config dir:
51 configDir = getConfigDir();
52 if (!new File(configDir).exists()) {
53 new File(configDir).mkdirs();
54 }
55
56 // Most of the rest is dependent upon this:
57 createConfigs(configDir, false);
58
59 // Proxy support
60 Proxy.use(Instance.getConfig().getString(Config.USE_PROXY));
61
62 // update tracer:
63 if (debug == null) {
64 debug = Instance.getConfig().getBoolean(Config.DEBUG_ERR, false);
65 trace = Instance.getConfig().getBoolean(Config.DEBUG_TRACE, false);
66 }
67
68 tracer = new TraceHandler(true, debug, trace);
69
70 // default Library
71 remoteDir = new File(configDir, "remote");
72 lib = createDefaultLibrary(remoteDir);
73
74 // create cache
75 File tmp = getFile(Config.CACHE_DIR);
76 if (tmp == null) {
77 // Could have used: System.getProperty("java.io.tmpdir")
78 tmp = new File(configDir, "tmp");
79 }
80 String ua = config.getString(Config.USER_AGENT);
81 try {
82 int hours = config.getInteger(Config.CACHE_MAX_TIME_CHANGING, -1);
83 int hoursLarge = config
84 .getInteger(Config.CACHE_MAX_TIME_STABLE, -1);
85 cache = new DataLoader(tmp, ua, hours, hoursLarge);
86 } catch (IOException e) {
87 tracer.error(new IOException(
88 "Cannot create cache (will continue without cache)", e));
89 cache = new DataLoader(ua);
90 }
91
92 cache.setTraceHandler(tracer);
93
94 // readerTmp / coverDir
95 readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER);
96 if (readerTmp == null) {
97 readerTmp = new File(configDir, "tmp-reader");
98 }
99
100 coverDir = getFile(Config.DEFAULT_COVERS_DIR);
101 if (coverDir != null && !coverDir.exists()) {
102 tracer.error(new IOException(
103 "The 'default covers' directory does not exists: "
104 + coverDir));
105 coverDir = null;
106 }
107
108 try {
109 tempFiles = new TempFiles("fanfix");
110 } catch (IOException e) {
111 tracer.error(new IOException("Cannot create temporary directory", e));
112 }
113 }
114
115 /**
116 * The traces handler for this {@link Cache}.
117 * <p>
118 * It is never NULL.
119 *
120 * @return the traces handler (never NULL)
121 */
122 public static TraceHandler getTraceHandler() {
123 return tracer;
124 }
125
126 /**
127 * The traces handler for this {@link Cache}.
128 *
129 * @param tracer
130 * the new traces handler or NULL
131 */
132 public static void setTraceHandler(TraceHandler tracer) {
133 if (tracer == null) {
134 tracer = new TraceHandler(false, false, false);
135 }
136
137 Instance.tracer = tracer;
138 cache.setTraceHandler(tracer);
139 }
140
141 /**
142 * Get the (unique) configuration service for the program.
143 *
144 * @return the configuration service
145 */
146 public static ConfigBundle getConfig() {
147 return config;
148 }
149
150 /**
151 * Get the (unique) UI configuration service for the program.
152 *
153 * @return the configuration service
154 */
155 public static UiConfigBundle getUiConfig() {
156 return uiconfig;
157 }
158
159 /**
160 * Reset the configuration.
161 *
162 * @param resetTrans
163 * also reset the translation files
164 */
165 public static void resetConfig(boolean resetTrans) {
166 String dir = Bundles.getDirectory();
167 Bundles.setDirectory(null);
168 try {
169 try {
170 ConfigBundle config = new ConfigBundle();
171 config.updateFile(configDir);
172 } catch (IOException e) {
173 tracer.error(e);
174 }
175 try {
176 UiConfigBundle uiconfig = new UiConfigBundle();
177 uiconfig.updateFile(configDir);
178 } catch (IOException e) {
179 tracer.error(e);
180 }
181
182 if (resetTrans) {
183 try {
184 StringIdBundle trans = new StringIdBundle(null);
185 trans.updateFile(configDir);
186 } catch (IOException e) {
187 tracer.error(e);
188 }
189 }
190 } finally {
191 Bundles.setDirectory(dir);
192 }
193 }
194
195 /**
196 * Get the (unique) {@link DataLoader} for the program.
197 *
198 * @return the {@link DataLoader}
199 */
200 public static DataLoader getCache() {
201 return cache;
202 }
203
204 /**
205 * Get the (unique) {link StringIdBundle} for the program.
206 * <p>
207 * This is used for the translations of the core parts of Fanfix.
208 *
209 * @return the {link StringIdBundle}
210 */
211 public static StringIdBundle getTrans() {
212 return trans;
213 }
214
215 /**
216 * Get the (unique) {link StringIdGuiBundle} for the program.
217 * <p>
218 * This is used for the translations of the GUI parts of Fanfix.
219 *
220 * @return the {link StringIdGuiBundle}
221 */
222 public static StringIdGuiBundle getTransGui() {
223 return transGui;
224 }
225
226 /**
227 * Get the (unique) {@link LocalLibrary} for the program.
228 *
229 * @return the {@link LocalLibrary}
230 */
231 public static BasicLibrary getLibrary() {
232 if (lib == null) {
233 throw new NullPointerException("We don't have a library to return");
234 }
235
236 return lib;
237 }
238
239 /**
240 * Return the directory where to look for default cover pages.
241 *
242 * @return the default covers directory
243 */
244 public static File getCoverDir() {
245 return coverDir;
246 }
247
248 /**
249 * Return the directory where to store temporary files for the local reader.
250 *
251 * @return the directory
252 */
253 public static File getReaderDir() {
254 return readerTmp;
255 }
256
257 /**
258 * Return the directory where to store temporary files for the remote
259 * {@link LocalLibrary}.
260 *
261 * @param host
262 * the remote for this host
263 *
264 * @return the directory
265 */
266 public static File getRemoteDir(String host) {
267 return getRemoteDir(remoteDir, host);
268 }
269
270 /**
271 * Return the directory where to store temporary files for the remote
272 * {@link LocalLibrary}.
273 *
274 * @param remoteDir
275 * the base remote directory
276 * @param host
277 * the remote for this host
278 *
279 * @return the directory
280 */
281 private static File getRemoteDir(File remoteDir, String host) {
282 remoteDir.mkdirs();
283
284 if (host != null) {
285 return new File(remoteDir, host);
286 }
287
288 return remoteDir;
289 }
290
291 /**
292 * Check if we need to check that a new version of Fanfix is available.
293 *
294 * @return TRUE if we need to
295 */
296 public static boolean isVersionCheckNeeded() {
297 try {
298 long wait = config.getInteger(Config.UPDATE_INTERVAL, 1) * 24 * 60
299 * 60 * 1000;
300 if (wait >= 0) {
301 String lastUpString = IOUtils.readSmallFile(new File(configDir,
302 "LAST_UPDATE"));
303 long delay = new Date().getTime()
304 - Long.parseLong(lastUpString);
305 if (delay > wait) {
306 return true;
307 }
308 } else {
309 return false;
310 }
311 } catch (Exception e) {
312 // No file or bad file:
313 return true;
314 }
315
316 return false;
317 }
318
319 /**
320 * Notify that we checked for a new version of Fanfix.
321 */
322 public static void setVersionChecked() {
323 try {
324 IOUtils.writeSmallFile(new File(configDir), "LAST_UPDATE",
325 Long.toString(new Date().getTime()));
326 } catch (IOException e) {
327 tracer.error(e);
328 }
329 }
330
331 /**
332 * The facility to use temporary files in this program.
333 * <p>
334 * <b>MUST</b> be closed at end of program.
335 *
336 * @return the facility
337 */
338 public static TempFiles getTempFiles() {
339 return tempFiles;
340 }
341
342 /**
343 * The configuration directory (will check, in order of preference,
344 * {@link Bundles#getDirectory()}, the system properties, the environment
345 * and then defaults to $HOME/.fanfix).
346 *
347 * @return the config directory
348 */
349 private static String getConfigDir() {
350 String configDir = Bundles.getDirectory();
351
352 if (configDir == null) {
353 configDir = System.getProperty("CONFIG_DIR");
354 }
355
356 if (configDir == null) {
357 configDir = System.getenv("CONFIG_DIR");
358 }
359
360 if (configDir == null) {
361 configDir = new File(getHome(), ".fanfix").getPath();
362 }
363
364 return configDir;
365 }
366
367 /**
368 * Create the config variables ({@link Instance#config},
369 * {@link Instance#uiconfig}, {@link Instance#trans} and
370 * {@link Instance#transGui}).
371 *
372 * @param configDir
373 * the directory where to find the configuration files
374 * @param refresh
375 * TRUE to reset the configuration files from the default
376 * included ones
377 */
378 private static void createConfigs(String configDir, boolean refresh) {
379 if (!refresh) {
380 Bundles.setDirectory(configDir);
381 }
382
383 try {
384 config = new ConfigBundle();
385 config.updateFile(configDir);
386 } catch (IOException e) {
387 tracer.error(e);
388 }
389
390 try {
391 uiconfig = new UiConfigBundle();
392 uiconfig.updateFile(configDir);
393 } catch (IOException e) {
394 tracer.error(e);
395 }
396
397 // No updateFile for this one! (we do not want the user to have custom
398 // translations that won't accept updates from newer versions)
399 trans = new StringIdBundle(getLang());
400 transGui = new StringIdGuiBundle(getLang());
401
402 // Fix an old bug (we used to store custom translation files by
403 // default):
404 if (trans.getString(StringId.INPUT_DESC_CBZ) == null) {
405 trans.deleteFile(configDir);
406 }
407
408 Boolean noutf = checkEnv("NOUTF");
409 if (noutf != null && noutf) {
410 trans.setUnicode(false);
411 transGui.setUnicode(false);
412 }
413
414 Bundles.setDirectory(configDir);
415 }
416
417 /**
418 * Create the default library as specified by the config.
419 *
420 * @param remoteDir
421 * the base remote directory if needed
422 *
423 * @return the default {@link BasicLibrary}
424 */
425 private static BasicLibrary createDefaultLibrary(File remoteDir) {
426 BasicLibrary lib = null;
427
428 String remoteLib = config.getString(Config.DEFAULT_LIBRARY);
429 if (remoteLib == null || remoteLib.trim().isEmpty()) {
430 String libDir = System.getProperty("fanfix.libdir");
431 if (libDir == null || libDir.isEmpty()) {
432 libDir = config.getString(Config.LIBRARY_DIR);
433 }
434 try {
435 lib = new LocalLibrary(getFile(libDir));
436 } catch (Exception e) {
437 tracer.error(new IOException(
438 "Cannot create library for directory: "
439 + getFile(libDir), e));
440 }
441 } else {
442 int pos = remoteLib.lastIndexOf(":");
443 if (pos >= 0) {
444 String port = remoteLib.substring(pos + 1).trim();
445 remoteLib = remoteLib.substring(0, pos);
446 pos = remoteLib.lastIndexOf(":");
447 if (pos >= 0) {
448 String host = remoteLib.substring(pos + 1).trim();
449 String key = remoteLib.substring(0, pos).trim();
450
451 try {
452 tracer.trace("Selecting remote library " + host + ":"
453 + port);
454 lib = new RemoteLibrary(key, host,
455 Integer.parseInt(port));
456 lib = new CacheLibrary(getRemoteDir(remoteDir, host),
457 lib);
458
459 } catch (Exception e) {
460 }
461 }
462 }
463
464 if (lib == null) {
465 tracer.error(new IOException(
466 "Cannot create remote library for: " + remoteLib));
467 }
468 }
469
470 return lib;
471 }
472
473 /**
474 * Return a path, but support the special $HOME variable.
475 *
476 * @return the path
477 */
478 private static File getFile(Config id) {
479 return getFile(config.getString(id));
480 }
481
482 /**
483 * Return a path, but support the special $HOME variable.
484 *
485 * @return the path
486 */
487 private static File getFile(UiConfig id) {
488 return getFile(uiconfig.getString(id));
489 }
490
491 /**
492 * Return a path, but support the special $HOME variable.
493 *
494 * @return the path
495 */
496 private static File getFile(String path) {
497 File file = null;
498 if (path != null && !path.isEmpty()) {
499 path = path.replace('/', File.separatorChar);
500 if (path.contains("$HOME")) {
501 path = path.replace("$HOME", getHome());
502 }
503
504 file = new File(path);
505 }
506
507 return file;
508 }
509
510 /**
511 * Return the home directory from the system properties.
512 *
513 * @return the home
514 */
515 private static String getHome() {
516 String home = System.getProperty("fanfix.home");
517 if (home != null && new File(home).isFile()) {
518 home = null;
519 }
520
521 if (home == null || home.trim().isEmpty()) {
522 home = System.getProperty("user.home");
523 if (!new File(home).isDirectory()) {
524 home = null;
525 }
526 }
527
528 if (home == null || home.trim().isEmpty()) {
529 home = System.getProperty("java.io.tmpdir");
530 if (!new File(home).isDirectory()) {
531 home = null;
532 }
533 }
534
535 if (home == null) {
536 home = "";
537 }
538
539 return home;
540 }
541
542 /**
543 * The language to use for the application (NULL = default system language).
544 *
545 * @return the language
546 */
547 private static String getLang() {
548 String lang = config.getString(Config.LANG);
549
550 if (lang == null | lang.isEmpty()) {
551 if (System.getenv("LANG") != null
552 && !System.getenv("LANG").isEmpty()) {
553 lang = System.getenv("LANG");
554 }
555 }
556
557 if (lang != null && lang.isEmpty()) {
558 lang = null;
559 }
560
561 return lang;
562 }
563
564 /**
565 * Check that the given environment variable is "enabled".
566 *
567 * @param key
568 * the variable to check
569 *
570 * @return TRUE if it is
571 */
572 private static Boolean checkEnv(String key) {
573 String value = System.getenv(key);
574 if (value != null) {
575 value = value.trim().toLowerCase();
576 if ("yes".equals(value) || "true".equals(value)
577 || "on".equals(value) || "1".equals(value)
578 || "y".equals(value)) {
579 return true;
580 }
581
582 return false;
583 }
584
585 return null;
586 }
587 }