1 package be
.nikiroo
.fanfix
;
4 import java
.io
.IOException
;
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
.TempFiles
;
21 import be
.nikiroo
.utils
.TraceHandler
;
22 import be
.nikiroo
.utils
.resources
.Bundles
;
25 * Global state for the program (services and singletons).
29 public class Instance
{
30 private static ConfigBundle config
;
31 private static UiConfigBundle uiconfig
;
32 private static StringIdBundle trans
;
33 private static DataLoader cache
;
34 private static StringIdGuiBundle transGui
;
35 private static BasicLibrary lib
;
36 private static File coverDir
;
37 private static File readerTmp
;
38 private static File remoteDir
;
39 private static String configDir
;
40 private static TraceHandler tracer
;
41 private static TempFiles tempFiles
;
44 // Before we can configure it:
45 tracer
= new TraceHandler(true, checkEnv("DEBUG"), checkEnv("DEBUG"));
48 configDir
= getConfigDir();
49 if (!new File(configDir
).exists()) {
50 new File(configDir
).mkdirs();
53 // Most of the rest is dependent upon this:
54 createConfigs(configDir
, false);
57 boolean debug
= Instance
.getConfig()
58 .getBoolean(Config
.DEBUG_ERR
, false);
59 boolean trace
= Instance
.getConfig().getBoolean(Config
.DEBUG_TRACE
,
62 if (checkEnv("DEBUG")) {
67 tracer
= new TraceHandler(true, debug
, trace
);
70 remoteDir
= new File(configDir
, "remote");
71 lib
= createDefaultLibrary(remoteDir
);
74 File tmp
= getFile(Config
.CACHE_DIR
);
76 // Could have used: System.getProperty("java.io.tmpdir")
77 tmp
= new File(configDir
, "tmp");
79 String ua
= config
.getString(Config
.USER_AGENT
);
81 int hours
= config
.getInteger(Config
.CACHE_MAX_TIME_CHANGING
, -1);
82 int hoursLarge
= config
83 .getInteger(Config
.CACHE_MAX_TIME_STABLE
, -1);
84 cache
= new DataLoader(tmp
, ua
, hours
, hoursLarge
);
85 } catch (IOException e
) {
86 tracer
.error(new IOException(
87 "Cannot create cache (will continue without cache)", e
));
88 cache
= new DataLoader(ua
);
91 cache
.setTraceHandler(tracer
);
93 // readerTmp / coverDir
94 readerTmp
= getFile(UiConfig
.CACHE_DIR_LOCAL_READER
);
95 if (readerTmp
== null) {
96 readerTmp
= new File(configDir
, "tmp-reader");
99 coverDir
= getFile(Config
.DEFAULT_COVERS_DIR
);
100 if (coverDir
!= null && !coverDir
.exists()) {
101 tracer
.error(new IOException(
102 "The 'default covers' directory does not exists: "
108 tempFiles
= new TempFiles("fanfix");
109 } catch (IOException e
) {
110 tracer
.error(new IOException("Cannot create temporary directory", e
));
115 * The traces handler for this {@link Cache}.
119 * @return the traces handler (never NULL)
121 public static TraceHandler
getTraceHandler() {
126 * The traces handler for this {@link Cache}.
129 * the new traces handler or NULL
131 public static void setTraceHandler(TraceHandler tracer
) {
132 if (tracer
== null) {
133 tracer
= new TraceHandler(false, false, false);
136 Instance
.tracer
= tracer
;
137 cache
.setTraceHandler(tracer
);
141 * Get the (unique) configuration service for the program.
143 * @return the configuration service
145 public static ConfigBundle
getConfig() {
150 * Get the (unique) UI configuration service for the program.
152 * @return the configuration service
154 public static UiConfigBundle
getUiConfig() {
159 * Reset the configuration.
162 * also reset the translation files
164 public static void resetConfig(boolean resetTrans
) {
165 String dir
= Bundles
.getDirectory();
166 Bundles
.setDirectory(null);
169 ConfigBundle config
= new ConfigBundle();
170 config
.updateFile(configDir
);
171 } catch (IOException e
) {
175 UiConfigBundle uiconfig
= new UiConfigBundle();
176 uiconfig
.updateFile(configDir
);
177 } catch (IOException e
) {
183 StringIdBundle trans
= new StringIdBundle(null);
184 trans
.updateFile(configDir
);
185 } catch (IOException e
) {
190 Bundles
.setDirectory(dir
);
195 * Get the (unique) {@link DataLoader} for the program.
197 * @return the {@link DataLoader}
199 public static DataLoader
getCache() {
204 * Get the (unique) {link StringIdBundle} for the program.
206 * This is used for the translations of the core parts of Fanfix.
208 * @return the {link StringIdBundle}
210 public static StringIdBundle
getTrans() {
215 * Get the (unique) {link StringIdGuiBundle} for the program.
217 * This is used for the translations of the GUI parts of Fanfix.
219 * @return the {link StringIdGuiBundle}
221 public static StringIdGuiBundle
getTransGui() {
226 * Get the (unique) {@link LocalLibrary} for the program.
228 * @return the {@link LocalLibrary}
230 public static BasicLibrary
getLibrary() {
232 throw new NullPointerException("We don't have a library to return");
239 * Return the directory where to look for default cover pages.
241 * @return the default covers directory
243 public static File
getCoverDir() {
248 * Return the directory where to store temporary files for the local reader.
250 * @return the directory
252 public static File
getReaderDir() {
257 * Return the directory where to store temporary files for the remote
258 * {@link LocalLibrary}.
261 * the remote for this host
263 * @return the directory
265 public static File
getRemoteDir(String host
) {
266 return getRemoteDir(remoteDir
, host
);
270 * Return the directory where to store temporary files for the remote
271 * {@link LocalLibrary}.
274 * the base remote directory
276 * the remote for this host
278 * @return the directory
280 private static File
getRemoteDir(File remoteDir
, String host
) {
284 return new File(remoteDir
, host
);
291 * Check if we need to check that a new version of Fanfix is available.
293 * @return TRUE if we need to
295 public static boolean isVersionCheckNeeded() {
297 long wait
= config
.getInteger(Config
.UPDATE_INTERVAL
, 1) * 24 * 60
300 String lastUpString
= IOUtils
.readSmallFile(new File(configDir
,
302 long delay
= new Date().getTime()
303 - Long
.parseLong(lastUpString
);
310 } catch (Exception e
) {
311 // No file or bad file:
319 * Notify that we checked for a new version of Fanfix.
321 public static void setVersionChecked() {
323 IOUtils
.writeSmallFile(new File(configDir
), "LAST_UPDATE",
324 Long
.toString(new Date().getTime()));
325 } catch (IOException e
) {
331 * The facility to use temporary files in this program.
333 * <b>MUST</b> be closed at end of program.
335 * @return the facility
337 public static TempFiles
getTempFiles() {
342 * The configuration directory (will check, in order of preference,
343 * {@link Bundles#getDirectory()}, the system properties, the environment
344 * and then defaults to $HOME/.fanfix).
346 * @return the config directory
348 private static String
getConfigDir() {
349 String configDir
= Bundles
.getDirectory();
351 if (configDir
== null) {
352 configDir
= System
.getProperty("CONFIG_DIR");
355 if (configDir
== null) {
356 configDir
= System
.getenv("CONFIG_DIR");
359 if (configDir
== null) {
360 configDir
= new File(getHome(), ".fanfix").getPath();
367 * Create the config variables ({@link Instance#config},
368 * {@link Instance#uiconfig}, {@link Instance#trans} and
369 * {@link Instance#transGui}).
372 * the directory where to find the configuration files
374 * TRUE to reset the configuration files from the default
377 private static void createConfigs(String configDir
, boolean refresh
) {
379 Bundles
.setDirectory(configDir
);
383 config
= new ConfigBundle();
384 config
.updateFile(configDir
);
385 } catch (IOException e
) {
390 uiconfig
= new UiConfigBundle();
391 uiconfig
.updateFile(configDir
);
392 } catch (IOException e
) {
396 // No updateFile for this one! (we do not want the user to have custom
397 // translations that won't accept updates from newer versions)
398 trans
= new StringIdBundle(getLang());
399 transGui
= new StringIdGuiBundle(getLang());
401 // Fix an old bug (we used to store custom translation files by
403 if (trans
.getString(StringId
.INPUT_DESC_CBZ
) == null) {
404 trans
.deleteFile(configDir
);
407 if (checkEnv("NOUTF")) {
408 trans
.setUnicode(false);
409 transGui
.setUnicode(false);
412 Bundles
.setDirectory(configDir
);
416 * Create the default library as specified by the config.
419 * the base remote directory if needed
421 * @return the default {@link BasicLibrary}
423 private static BasicLibrary
createDefaultLibrary(File remoteDir
) {
424 BasicLibrary lib
= null;
426 String remoteLib
= config
.getString(Config
.DEFAULT_LIBRARY
);
427 if (remoteLib
== null || remoteLib
.trim().isEmpty()) {
428 String libDir
= System
.getProperty("fanfix.libdir");
429 if (libDir
== null || libDir
.isEmpty()) {
430 libDir
= config
.getString(Config
.LIBRARY_DIR
);
433 lib
= new LocalLibrary(getFile(libDir
));
434 } catch (Exception e
) {
435 tracer
.error(new IOException(
436 "Cannot create library for directory: "
437 + getFile(libDir
), e
));
440 int pos
= remoteLib
.lastIndexOf(":");
442 String port
= remoteLib
.substring(pos
+ 1).trim();
443 remoteLib
= remoteLib
.substring(0, pos
);
444 pos
= remoteLib
.lastIndexOf(":");
446 String host
= remoteLib
.substring(pos
+ 1).trim();
447 String key
= remoteLib
.substring(0, pos
).trim();
450 tracer
.trace("Selecting remote library " + host
+ ":"
452 lib
= new RemoteLibrary(key
, host
,
453 Integer
.parseInt(port
));
454 lib
= new CacheLibrary(getRemoteDir(remoteDir
, host
),
457 } catch (Exception e
) {
463 tracer
.error(new IOException(
464 "Cannot create remote library for: " + remoteLib
));
472 * Return a path, but support the special $HOME variable.
476 private static File
getFile(Config id
) {
477 return getFile(config
.getString(id
));
481 * Return a path, but support the special $HOME variable.
485 private static File
getFile(UiConfig id
) {
486 return getFile(uiconfig
.getString(id
));
490 * Return a path, but support the special $HOME variable.
494 private static File
getFile(String path
) {
496 if (path
!= null && !path
.isEmpty()) {
497 path
= path
.replace('/', File
.separatorChar
);
498 if (path
.contains("$HOME")) {
499 path
= path
.replace("$HOME", getHome());
502 file
= new File(path
);
509 * Return the home directory from the system properties.
513 private static String
getHome() {
514 String home
= System
.getProperty("fanfix.home");
515 if (home
!= null && new File(home
).isFile()) {
519 if (home
== null || home
.trim().isEmpty()) {
520 home
= System
.getProperty("user.home");
521 if (!new File(home
).isDirectory()) {
526 if (home
== null || home
.trim().isEmpty()) {
527 home
= System
.getProperty("java.io.tmpdir");
528 if (!new File(home
).isDirectory()) {
541 * The language to use for the application (NULL = default system language).
543 * @return the language
545 private static String
getLang() {
546 String lang
= config
.getString(Config
.LANG
);
548 if (lang
== null | lang
.isEmpty()) {
549 if (System
.getenv("LANG") != null
550 && !System
.getenv("LANG").isEmpty()) {
551 lang
= System
.getenv("LANG");
555 if (lang
!= null && lang
.isEmpty()) {
563 * Check that the given environment variable is "enabled".
566 * the variable to check
568 * @return TRUE if it is
570 private static boolean checkEnv(String key
) {
571 String value
= System
.getenv(key
);
573 value
= value
.trim().toLowerCase();
574 if ("yes".equals(value
) || "true".equals(value
)
575 || "on".equals(value
) || "1".equals(value
)
576 || "y".equals(value
)) {