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
.Image
;
21 import be
.nikiroo
.utils
.Proxy
;
22 import be
.nikiroo
.utils
.TempFiles
;
23 import be
.nikiroo
.utils
.TraceHandler
;
24 import be
.nikiroo
.utils
.resources
.Bundles
;
27 * Global state for the program (services and singletons).
31 public class Instance
{
32 private static ConfigBundle config
;
33 private static UiConfigBundle uiconfig
;
34 private static StringIdBundle trans
;
35 private static DataLoader cache
;
36 private static StringIdGuiBundle transGui
;
37 private static BasicLibrary lib
;
38 private static File coverDir
;
39 private static File readerTmp
;
40 private static File remoteDir
;
41 private static String configDir
;
42 private static TraceHandler tracer
;
43 private static TempFiles tempFiles
;
45 private static boolean init
;
48 * Initialise the instance -- if already initialised, nothing will happen.
50 * Before calling this method, you may call {@link Bundles#setDirectory()}
53 static public void init() {
60 // Before we can configure it:
61 Boolean debug
= checkEnv("DEBUG");
62 boolean trace
= debug
!= null && debug
;
63 tracer
= new TraceHandler(true, trace
, trace
);
66 configDir
= getConfigDir();
67 if (!new File(configDir
).exists()) {
68 new File(configDir
).mkdirs();
71 // Most of the rest is dependent upon this:
72 createConfigs(configDir
, false);
75 Proxy
.use(Instance
.getConfig().getString(Config
.USE_PROXY
));
79 debug
= Instance
.getConfig().getBoolean(Config
.DEBUG_ERR
, false);
80 trace
= Instance
.getConfig().getBoolean(Config
.DEBUG_TRACE
, false);
83 tracer
= new TraceHandler(true, debug
, trace
);
86 remoteDir
= new File(configDir
, "remote");
87 lib
= createDefaultLibrary(remoteDir
);
89 // create cache and TMP
90 Image
.setTemporaryFilesRoot(new File(configDir
, "tmp.images"));
91 File tmp
= getFile(Config
.CACHE_DIR
);
93 // Could have used: System.getProperty("java.io.tmpdir")
94 tmp
= new File(configDir
, "tmp");
96 String ua
= config
.getString(Config
.USER_AGENT
);
98 int hours
= config
.getInteger(Config
.CACHE_MAX_TIME_CHANGING
, -1);
99 int hoursLarge
= config
100 .getInteger(Config
.CACHE_MAX_TIME_STABLE
, -1);
101 cache
= new DataLoader(tmp
, ua
, hours
, hoursLarge
);
102 } catch (IOException e
) {
103 tracer
.error(new IOException(
104 "Cannot create cache (will continue without cache)", e
));
105 cache
= new DataLoader(ua
);
108 cache
.setTraceHandler(tracer
);
110 // readerTmp / coverDir
111 readerTmp
= getFile(UiConfig
.CACHE_DIR_LOCAL_READER
);
112 if (readerTmp
== null) {
113 readerTmp
= new File(configDir
, "tmp-reader");
116 coverDir
= getFile(Config
.DEFAULT_COVERS_DIR
);
117 if (coverDir
!= null && !coverDir
.exists()) {
118 tracer
.error(new IOException(
119 "The 'default covers' directory does not exists: "
125 tempFiles
= new TempFiles("fanfix");
126 } catch (IOException e
) {
127 tracer
.error(new IOException("Cannot create temporary directory", e
));
132 * The traces handler for this {@link Cache}.
136 * @return the traces handler (never NULL)
138 public static TraceHandler
getTraceHandler() {
143 * The traces handler for this {@link Cache}.
146 * the new traces handler or NULL
148 public static void setTraceHandler(TraceHandler tracer
) {
149 if (tracer
== null) {
150 tracer
= new TraceHandler(false, false, false);
153 Instance
.tracer
= tracer
;
154 cache
.setTraceHandler(tracer
);
158 * Get the (unique) configuration service for the program.
160 * @return the configuration service
162 public static ConfigBundle
getConfig() {
167 * Get the (unique) UI configuration service for the program.
169 * @return the configuration service
171 public static UiConfigBundle
getUiConfig() {
176 * Reset the configuration.
179 * also reset the translation files
181 public static void resetConfig(boolean resetTrans
) {
182 String dir
= Bundles
.getDirectory();
183 Bundles
.setDirectory(null);
186 ConfigBundle config
= new ConfigBundle();
187 config
.updateFile(configDir
);
188 } catch (IOException e
) {
192 UiConfigBundle uiconfig
= new UiConfigBundle();
193 uiconfig
.updateFile(configDir
);
194 } catch (IOException e
) {
200 StringIdBundle trans
= new StringIdBundle(null);
201 trans
.updateFile(configDir
);
202 } catch (IOException e
) {
207 Bundles
.setDirectory(dir
);
212 * Get the (unique) {@link DataLoader} for the program.
214 * @return the {@link DataLoader}
216 public static DataLoader
getCache() {
221 * Get the (unique) {link StringIdBundle} for the program.
223 * This is used for the translations of the core parts of Fanfix.
225 * @return the {link StringIdBundle}
227 public static StringIdBundle
getTrans() {
232 * Get the (unique) {link StringIdGuiBundle} for the program.
234 * This is used for the translations of the GUI parts of Fanfix.
236 * @return the {link StringIdGuiBundle}
238 public static StringIdGuiBundle
getTransGui() {
243 * Get the (unique) {@link LocalLibrary} for the program.
245 * @return the {@link LocalLibrary}
247 public static BasicLibrary
getLibrary() {
249 throw new NullPointerException("We don't have a library to return");
256 * Return the directory where to look for default cover pages.
258 * @return the default covers directory
260 public static File
getCoverDir() {
265 * Return the directory where to store temporary files for the local reader.
267 * @return the directory
269 public static File
getReaderDir() {
274 * Return the directory where to store temporary files for the remote
275 * {@link LocalLibrary}.
278 * the remote for this host
280 * @return the directory
282 public static File
getRemoteDir(String host
) {
283 return getRemoteDir(remoteDir
, host
);
287 * Return the directory where to store temporary files for the remote
288 * {@link LocalLibrary}.
291 * the base remote directory
293 * the remote for this host
295 * @return the directory
297 private static File
getRemoteDir(File remoteDir
, String host
) {
301 return new File(remoteDir
, host
);
308 * Check if we need to check that a new version of Fanfix is available.
310 * @return TRUE if we need to
312 public static boolean isVersionCheckNeeded() {
314 long wait
= config
.getInteger(Config
.UPDATE_INTERVAL
, 1) * 24 * 60
317 String lastUpString
= IOUtils
.readSmallFile(new File(configDir
,
319 long delay
= new Date().getTime()
320 - Long
.parseLong(lastUpString
);
327 } catch (Exception e
) {
328 // No file or bad file:
336 * Notify that we checked for a new version of Fanfix.
338 public static void setVersionChecked() {
340 IOUtils
.writeSmallFile(new File(configDir
), "LAST_UPDATE",
341 Long
.toString(new Date().getTime()));
342 } catch (IOException e
) {
348 * The facility to use temporary files in this program.
350 * <b>MUST</b> be closed at end of program.
352 * @return the facility
354 public static TempFiles
getTempFiles() {
359 * The configuration directory (will check, in order of preference,
360 * {@link Bundles#getDirectory()}, the system properties, the environment
361 * and then defaults to $HOME/.fanfix).
363 * @return the config directory
365 private static String
getConfigDir() {
366 String configDir
= Bundles
.getDirectory();
368 if (configDir
== null) {
369 configDir
= System
.getProperty("CONFIG_DIR");
372 if (configDir
== null) {
373 configDir
= System
.getenv("CONFIG_DIR");
376 if (configDir
== null) {
377 configDir
= new File(getHome(), ".fanfix").getPath();
384 * Create the config variables ({@link Instance#config},
385 * {@link Instance#uiconfig}, {@link Instance#trans} and
386 * {@link Instance#transGui}).
389 * the directory where to find the configuration files
391 * TRUE to reset the configuration files from the default
394 private static void createConfigs(String configDir
, boolean refresh
) {
396 Bundles
.setDirectory(configDir
);
400 config
= new ConfigBundle();
401 config
.updateFile(configDir
);
402 } catch (IOException e
) {
407 uiconfig
= new UiConfigBundle();
408 uiconfig
.updateFile(configDir
);
409 } catch (IOException e
) {
413 // No updateFile for this one! (we do not want the user to have custom
414 // translations that won't accept updates from newer versions)
415 trans
= new StringIdBundle(getLang());
416 transGui
= new StringIdGuiBundle(getLang());
418 // Fix an old bug (we used to store custom translation files by
420 if (trans
.getString(StringId
.INPUT_DESC_CBZ
) == null) {
421 trans
.deleteFile(configDir
);
424 Boolean noutf
= checkEnv("NOUTF");
425 if (noutf
!= null && noutf
) {
426 trans
.setUnicode(false);
427 transGui
.setUnicode(false);
430 Bundles
.setDirectory(configDir
);
434 * Create the default library as specified by the config.
437 * the base remote directory if needed
439 * @return the default {@link BasicLibrary}
441 private static BasicLibrary
createDefaultLibrary(File remoteDir
) {
442 BasicLibrary lib
= null;
444 String remoteLib
= config
.getString(Config
.DEFAULT_LIBRARY
);
445 if (remoteLib
== null || remoteLib
.trim().isEmpty()) {
446 String libDir
= System
.getProperty("fanfix.libdir");
447 if (libDir
== null || libDir
.isEmpty()) {
448 libDir
= config
.getString(Config
.LIBRARY_DIR
);
451 lib
= new LocalLibrary(getFile(libDir
));
452 } catch (Exception e
) {
453 tracer
.error(new IOException(
454 "Cannot create library for directory: "
455 + getFile(libDir
), e
));
459 int pos
= remoteLib
.lastIndexOf(":");
461 String port
= remoteLib
.substring(pos
+ 1).trim();
462 remoteLib
= remoteLib
.substring(0, pos
);
463 pos
= remoteLib
.lastIndexOf(":");
465 String host
= remoteLib
.substring(pos
+ 1).trim();
466 String key
= remoteLib
.substring(0, pos
).trim();
469 tracer
.trace("Selecting remote library " + host
+ ":"
471 lib
= new RemoteLibrary(key
, host
,
472 Integer
.parseInt(port
));
473 lib
= new CacheLibrary(getRemoteDir(remoteDir
, host
),
476 } catch (Exception e
) {
483 tracer
.error(new IOException(
484 "Cannot create remote library for: " + remoteLib
, ex
));
492 * Return a path, but support the special $HOME variable.
496 private static File
getFile(Config id
) {
497 return getFile(config
.getString(id
));
501 * Return a path, but support the special $HOME variable.
505 private static File
getFile(UiConfig id
) {
506 return getFile(uiconfig
.getString(id
));
510 * Return a path, but support the special $HOME variable.
514 private static File
getFile(String path
) {
516 if (path
!= null && !path
.isEmpty()) {
517 path
= path
.replace('/', File
.separatorChar
);
518 if (path
.contains("$HOME")) {
519 path
= path
.replace("$HOME", getHome());
522 file
= new File(path
);
529 * Return the home directory from the system properties.
533 private static String
getHome() {
534 String home
= System
.getProperty("fanfix.home");
535 if (home
!= null && new File(home
).isFile()) {
539 if (home
== null || home
.trim().isEmpty()) {
540 home
= System
.getProperty("user.home");
541 if (!new File(home
).isDirectory()) {
546 if (home
== null || home
.trim().isEmpty()) {
547 home
= System
.getProperty("java.io.tmpdir");
548 if (!new File(home
).isDirectory()) {
561 * The language to use for the application (NULL = default system language).
563 * @return the language
565 private static String
getLang() {
566 String lang
= config
.getString(Config
.LANG
);
568 if (lang
== null || lang
.isEmpty()) {
569 if (System
.getenv("LANG") != null
570 && !System
.getenv("LANG").isEmpty()) {
571 lang
= System
.getenv("LANG");
575 if (lang
!= null && lang
.isEmpty()) {
583 * Check that the given environment variable is "enabled".
586 * the variable to check
588 * @return TRUE if it is
590 private static Boolean
checkEnv(String key
) {
591 String value
= System
.getenv(key
);
593 value
= value
.trim().toLowerCase();
594 if ("yes".equals(value
) || "true".equals(value
)
595 || "on".equals(value
) || "1".equals(value
)
596 || "y".equals(value
)) {