1 package be
.nikiroo
.fanfix
;
4 import java
.io
.IOException
;
5 import java
.net
.MalformedURLException
;
7 import java
.util
.ArrayList
;
10 import javax
.net
.ssl
.SSLException
;
12 import be
.nikiroo
.fanfix
.bundles
.Config
;
13 import be
.nikiroo
.fanfix
.bundles
.StringId
;
14 import be
.nikiroo
.fanfix
.data
.Chapter
;
15 import be
.nikiroo
.fanfix
.data
.MetaData
;
16 import be
.nikiroo
.fanfix
.data
.Story
;
17 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
18 import be
.nikiroo
.fanfix
.library
.CacheLibrary
;
19 import be
.nikiroo
.fanfix
.library
.LocalLibrary
;
20 import be
.nikiroo
.fanfix
.library
.RemoteLibrary
;
21 import be
.nikiroo
.fanfix
.library
.RemoteLibraryServer
;
22 import be
.nikiroo
.fanfix
.library
.WebLibrary
;
23 import be
.nikiroo
.fanfix
.library
.WebLibraryServer
;
24 import be
.nikiroo
.fanfix
.output
.BasicOutput
;
25 import be
.nikiroo
.fanfix
.output
.BasicOutput
.OutputType
;
26 import be
.nikiroo
.fanfix
.reader
.BasicReader
;
27 import be
.nikiroo
.fanfix
.reader
.CliReader
;
28 import be
.nikiroo
.fanfix
.searchable
.BasicSearchable
;
29 import be
.nikiroo
.fanfix
.supported
.BasicSupport
;
30 import be
.nikiroo
.fanfix
.supported
.SupportType
;
31 import be
.nikiroo
.utils
.Progress
;
32 import be
.nikiroo
.utils
.Version
;
33 import be
.nikiroo
.utils
.VersionCheck
;
36 * Main program entry point.
41 private enum MainAction
{
42 IMPORT
, EXPORT
, CONVERT
, READ
, READ_URL
, LIST
, HELP
, START
, VERSION
, SERVER
, STOP_SERVER
, REMOTE
, SET_SOURCE
, SET_TITLE
, SET_AUTHOR
, SEARCH
, SEARCH_TAG
46 * Main program entry point.
48 * Known environment variables:
50 * <li>NOUTF: if set to 1 or 'true', the program will prefer non-unicode
51 * {@link String}s when possible</li>
52 * <li>CONFIG_DIR: a path where to look for the <tt>.properties</tt> files
53 * before taking the usual ones; they will also be saved/updated into this
54 * path when the program starts</li>
55 * <li>DEBUG: if set to 1 or 'true', the program will override the DEBUG_ERR
56 * configuration value with 'true'</li>
60 * <li>--import [URL]: import into library</li>
61 * <li>--export [id] [output_type] [target]: export story to target</li>
62 * <li>--convert [URL] [output_type] [target] (+info): convert URL into
64 * <li>--read [id] ([chapter number]): read the given story from the library
66 * <li>--read-url [URL] ([chapter number]): convert on the fly and read the
67 * story, without saving it</li>
68 * <li>--search: list the supported websites (where)</li>
69 * <li>--search [where] [keywords] (page [page]) (item [item]): search on
70 * the supported website and display the given results page of stories it
71 * found, or the story details if asked</li>
72 * <li>--search-tag [where]: list all the tags supported by this website</li>
73 * <li>--search-tag [index 1]... (page [page]) (item [item]): search for the
74 * given stories or subtags, tag by tag, and display information about a
75 * specific page of results or about a specific item if requested</li>
76 * <li>--list ([type]): list the stories present in the library</li>
77 * <li>--set-source [id] [new source]: change the source of the given story</li>
78 * <li>--set-title [id] [new title]: change the title of the given story</li>
79 * <li>--set-author [id] [new author]: change the author of the given story</li>
80 * <li>--version: get the version of the program</li>
81 * <li>--server: start the server mode (see config file for parameters)</li>
82 * <li>--stop-server: stop the running server on this port if any</li>
83 * <li>--remote [key] [host] [port]: use the given remote library</li>
87 * see method description
89 public static void main(String
[] args
) {
90 new Main().start(args
);
94 * Start the default handling for the application.
96 * If specific actions were asked (with correct parameters), they will be
97 * forwarded to the different protected methods that you can override.
99 * At the end of the method, {@link Main#exit(int)} will be called; by
100 * default, it calls {@link System#exit(int)} if the status is not 0.
103 * the arguments received from the system
105 public void start(String
[] args
) {
106 // Only one line, but very important:
109 String urlString
= null;
111 String sourceString
= null;
112 String titleString
= null;
113 String authorString
= null;
114 String chapString
= null;
115 String target
= null;
117 MainAction action
= MainAction
.START
;
118 Boolean plusInfo
= null;
121 SupportType searchOn
= null;
122 String search
= null;
123 List
<Integer
> tags
= new ArrayList
<Integer
>();
127 boolean noMoreActions
= false;
130 for (int i
= 0; exitCode
== 0 && i
< args
.length
; i
++) {
134 // Action (--) handling:
135 if (!noMoreActions
&& args
[i
].startsWith("--")) {
136 if (args
[i
].equals("--")) {
137 noMoreActions
= true;
140 action
= MainAction
.valueOf(args
[i
].substring(2)
141 .toUpperCase().replace("-", "_"));
142 } catch (Exception e
) {
143 Instance
.getInstance().getTraceHandler()
144 .error(new IllegalArgumentException("Unknown action: " + args
[i
], e
));
154 if (urlString
== null) {
163 } else if (sourceString
== null) {
164 sourceString
= args
[i
];
165 } else if (target
== null) {
172 if (urlString
== null) {
174 } else if (sourceString
== null) {
175 sourceString
= args
[i
];
176 } else if (target
== null) {
178 } else if (plusInfo
== null) {
179 if ("+info".equals(args
[i
])) {
189 if (sourceString
== null) {
190 sourceString
= args
[i
];
198 } else if (sourceString
== null) {
199 sourceString
= args
[i
];
207 } else if (sourceString
== null) {
208 titleString
= args
[i
];
216 } else if (sourceString
== null) {
217 authorString
= args
[i
];
225 } else if (chapString
== null) {
226 chapString
= args
[i
];
232 if (urlString
== null) {
234 } else if (chapString
== null) {
235 chapString
= args
[i
];
241 if (searchOn
== null) {
242 searchOn
= SupportType
.valueOfAllOkUC(args
[i
]);
244 if (searchOn
== null) {
245 Instance
.getInstance().getTraceHandler().error("Website not known: <" + args
[i
] + ">");
250 if (BasicSearchable
.getSearchable(searchOn
) == null) {
251 Instance
.getInstance().getTraceHandler().error("Website not supported: " + searchOn
);
255 } else if (search
== null) {
257 } else if (page
!= null && page
== -1) {
259 page
= Integer
.parseInt(args
[i
]);
260 } catch (Exception e
) {
263 } else if (item
!= null && item
== -1) {
265 item
= Integer
.parseInt(args
[i
]);
266 } catch (Exception e
) {
269 } else if (page
== null || item
== null) {
270 if (page
== null && "page".equals(args
[i
])) {
272 } else if (item
== null && "item".equals(args
[i
])) {
282 if (searchOn
== null) {
283 searchOn
= SupportType
.valueOfAllOkUC(args
[i
]);
285 if (searchOn
== null) {
286 Instance
.getInstance().getTraceHandler().error("Website not known: <" + args
[i
] + ">");
290 if (BasicSearchable
.getSearchable(searchOn
) == null) {
291 Instance
.getInstance().getTraceHandler().error("Website not supported: " + searchOn
);
294 } else if (page
== null && item
== null) {
295 if ("page".equals(args
[i
])) {
297 } else if ("item".equals(args
[i
])) {
301 int index
= Integer
.parseInt(args
[i
]);
303 } catch (NumberFormatException e
) {
304 Instance
.getInstance().getTraceHandler().error("Invalid tag index: " + args
[i
]);
308 } else if (page
!= null && page
== -1) {
310 page
= Integer
.parseInt(args
[i
]);
311 } catch (Exception e
) {
314 } else if (item
!= null && item
== -1) {
316 item
= Integer
.parseInt(args
[i
]);
317 } catch (Exception e
) {
320 } else if (page
== null || item
== null) {
321 if (page
== null && "page".equals(args
[i
])) {
323 } else if (item
== null && "item".equals(args
[i
])) {
336 exitCode
= 255; // not supposed to be selected by user
339 exitCode
= 255; // no arguments for this option
342 exitCode
= 255; // no arguments for this option
345 exitCode
= 255; // no arguments for this option
350 } else if (host
== null) {
352 } else if (port
== null) {
353 port
= Integer
.parseInt(args
[i
]);
356 if (host
.startsWith("http://")
357 || host
.startsWith("https://")) {
358 lib
= new WebLibrary(key
, host
, port
);
360 lib
= new RemoteLibrary(key
, host
, port
);
363 lib
= new CacheLibrary(
364 Instance
.getInstance().getRemoteDir(host
), lib
,
365 Instance
.getInstance().getUiConfig());
367 Instance
.getInstance().setLibrary(lib
);
369 action
= MainAction
.START
;
377 final Progress mainProgress
= new Progress(0, 80);
378 mainProgress
.addProgressListener(new Progress
.ProgressListener() {
379 private int current
= mainProgress
.getMin();
382 public void progress(Progress progress
, String name
) {
383 int diff
= progress
.getProgress() - current
;
389 StringBuilder builder
= new StringBuilder();
390 for (int i
= 0; i
< diff
; i
++) {
394 System
.err
.print(builder
.toString());
396 if (progress
.isDone()) {
397 System
.err
.println("");
401 Progress pg
= new Progress();
402 mainProgress
.addProgress(pg
, mainProgress
.getMax());
404 VersionCheck updates
= checkUpdates();
409 if (updates
!= null) {
410 // we consider it read
411 Instance
.getInstance().setVersionChecked();
415 exitCode
= imprt(BasicReader
.getUrl(urlString
), pg
);
416 } catch (MalformedURLException e
) {
417 Instance
.getInstance().getTraceHandler().error(e
);
423 if (updates
!= null) {
424 // we consider it read
425 Instance
.getInstance().setVersionChecked();
428 OutputType exportType
= OutputType
.valueOfNullOkUC(sourceString
, null);
429 if (exportType
== null) {
430 Instance
.getInstance().getTraceHandler().error(new Exception(trans(StringId
.OUTPUT_DESC
, sourceString
)));
435 exitCode
= export(luid
, exportType
, target
, pg
);
439 if (updates
!= null) {
440 // we consider it read
441 Instance
.getInstance().setVersionChecked();
444 OutputType convertType
= OutputType
.valueOfAllOkUC(sourceString
, null);
445 if (convertType
== null) {
446 Instance
.getInstance().getTraceHandler()
447 .error(new IOException(trans(StringId
.ERR_BAD_OUTPUT_TYPE
, sourceString
)));
453 exitCode
= convert(urlString
, convertType
, target
,
454 plusInfo
== null ?
false : plusInfo
, pg
);
458 exitCode
= list(sourceString
);
462 Instance
.getInstance().getLibrary().changeSource(luid
, sourceString
, pg
);
463 } catch (IOException e1
) {
464 Instance
.getInstance().getTraceHandler().error(e1
);
470 Instance
.getInstance().getLibrary().changeTitle(luid
, titleString
, pg
);
471 } catch (IOException e1
) {
472 Instance
.getInstance().getTraceHandler().error(e1
);
478 Instance
.getInstance().getLibrary().changeAuthor(luid
, authorString
, pg
);
479 } catch (IOException e1
) {
480 Instance
.getInstance().getTraceHandler().error(e1
);
485 if (luid
== null || luid
.isEmpty()) {
493 if (chapString
!= null) {
495 chap
= Integer
.parseInt(chapString
);
496 } catch (NumberFormatException e
) {
497 Instance
.getInstance().getTraceHandler().error(new IOException(
498 "Chapter number cannot be parsed: " + chapString
, e
));
504 BasicLibrary lib
= Instance
.getInstance().getLibrary();
505 exitCode
= read(lib
.getStory(luid
, null), chap
);
506 } catch (IOException e
) {
507 Instance
.getInstance().getTraceHandler()
508 .error(new IOException("Failed to read book", e
));
514 if (urlString
== null || urlString
.isEmpty()) {
522 if (chapString
!= null) {
524 chap
= Integer
.parseInt(chapString
);
525 } catch (NumberFormatException e
) {
526 Instance
.getInstance().getTraceHandler().error(new IOException(
527 "Chapter number cannot be parsed: " + chapString
, e
));
533 BasicSupport support
= BasicSupport
534 .getSupport(BasicReader
.getUrl(urlString
));
535 if (support
== null) {
536 Instance
.getInstance().getTraceHandler()
537 .error("URL not supported: " + urlString
);
542 exitCode
= read(support
.process(null), chap
);
543 } catch (IOException e
) {
544 Instance
.getInstance().getTraceHandler()
545 .error(new IOException("Failed to read book", e
));
551 page
= page
== null ?
1 : page
;
553 Instance
.getInstance().getTraceHandler().error("Incorrect page number");
558 item
= item
== null ?
0 : item
;
560 Instance
.getInstance().getTraceHandler().error("Incorrect item number");
565 if (searchOn
== null) {
568 } catch (IOException e
) {
569 Instance
.getInstance().getTraceHandler().error(e
);
572 } else if (search
!= null) {
574 searchKeywords(searchOn
, search
, page
, item
);
575 } catch (IOException e
) {
576 Instance
.getInstance().getTraceHandler().error(e
);
585 if (searchOn
== null) {
590 page
= page
== null ?
1 : page
;
592 Instance
.getInstance().getTraceHandler().error("Incorrect page number");
597 item
= item
== null ?
0 : item
;
599 Instance
.getInstance().getTraceHandler().error("Incorrect item number");
605 searchTags(searchOn
, page
, item
,
606 tags
.toArray(new Integer
[] {}));
607 } catch (IOException e
) {
608 Instance
.getInstance().getTraceHandler().error(e
);
617 if (updates
!= null) {
618 // we consider it read
619 Instance
.getInstance().setVersionChecked();
623 .println(String
.format("Fanfix version %s"
624 + "%nhttps://github.com/nikiroo/fanfix/"
625 + "%n\tWritten by Nikiroo",
626 Version
.getCurrentVersion()));
631 } catch (IOException e
) {
632 Instance
.getInstance().getTraceHandler().error(e
);
639 } catch (IOException e
) {
640 Instance
.getInstance().getTraceHandler().error(e
);
645 // Can be given via "--remote XX XX XX"
647 key
= Instance
.getInstance().getConfig()
648 .getString(Config
.SERVER_KEY
);
650 // If a subkey in RW mode exists, use it
651 for (String subkey
: Instance
.getInstance().getConfig()
652 .getList(Config
.SERVER_ALLOWED_SUBKEYS
,
653 new ArrayList
<String
>())) {
654 if ((subkey
+ "|").contains("|rw|")) {
655 key
= key
+ "|" + subkey
;
662 port
= Instance
.getInstance().getConfig().getInteger(Config
.SERVER_PORT
);
666 String mode
= Instance
.getInstance().getConfig()
667 .getString(Config
.SERVER_MODE
, "fanfix");
668 if ("http".equals(mode
)) {
669 host
= "http://localhost";
670 } else if ("https".equals(mode
)) {
671 host
= "https://localhost";
672 } else if ("fanfix".equals(mode
)) {
673 host
= "fanfix://localhost";
678 System
.err
.println("No port given nor configured in the config file");
683 stopServer(key
, host
, port
);
684 } catch (SSLException e
) {
685 Instance
.getInstance().getTraceHandler().error(
686 "Bad access key for remote library");
688 } catch (IOException e
) {
689 Instance
.getInstance().getTraceHandler().error(e
);
695 exitCode
= 255; // should not be reachable (REMOTE -> START)
701 Instance
.getInstance().getTempFiles().close();
702 } catch (IOException e
) {
703 Instance
.getInstance().getTraceHandler().error(new IOException(
704 "Cannot dispose of the temporary files", e
));
707 if (exitCode
== 255) {
715 * A normal invocation of the program (without parameters or at least
716 * without "action" parameters).
718 * You will probably want to override that one if you offer a user
721 * @throws IOException
722 * in case of I/O error
724 protected void start() throws IOException
{
725 new CliReader().listBooks(null);
729 * Will check if updates are available, synchronously.
731 * For this, it will simply forward the call to
732 * {@link Main#checkUpdates(String)} with a value of "nikiroo/fanfix".
734 * You may want to override it so you call the forward method with the right
735 * parameters (or also if you want it to be asynchronous).
737 * @return the newer version information or NULL if nothing new
739 protected VersionCheck
checkUpdates() {
740 return checkUpdates("nikiroo/fanfix");
744 * Will check if updates are available on a specific GitHub project.
746 * Will be called by {@link Main#checkUpdates()}, but if you override that
747 * one you mall call it with another project.
749 * @param githubProject
750 * the GitHub project, for instance "nikiroo/fanfix"
752 * @return the newer version information or NULL if nothing new
754 protected VersionCheck
checkUpdates(String githubProject
) {
756 VersionCheck updates
= VersionCheck
.check(githubProject
,
757 Instance
.getInstance().getTrans().getLocale());
758 if (updates
.isNewVersionAvailable()) {
759 notifyUpdates(updates
);
762 } catch (IOException e
) {
763 // Maybe no internet. Do not report any update.
770 * Notify the user about available updates.
772 * Will only be called when a version is available.
774 * Note that you can call {@link Instance#setVersionChecked()} on it if the
775 * user has read the information (by default, it is marked read only on
776 * certain other actions).
779 * the new version information
781 protected void notifyUpdates(VersionCheck updates
) {
782 // Sent to syserr so not to cause problem if one tries to capture a
783 // story content in text mode
785 "A new version of the program is available at https://github.com/nikiroo/fanfix/releases");
786 System
.err
.println("");
787 for (Version v
: updates
.getNewer()) {
788 System
.err
.println("\tVersion " + v
);
789 System
.err
.println("\t-------------");
790 System
.err
.println("");
791 for (String it
: updates
.getChanges().get(v
)) {
792 System
.err
.println("\t- " + it
);
794 System
.err
.println("");
799 * Import the given resource into the {@link LocalLibrary}.
802 * the resource to import
804 * the optional progress reporter
806 * @return the exit return code (0 = success)
808 protected static int imprt(URL url
, Progress pg
) {
810 MetaData meta
= Instance
.getInstance().getLibrary().imprt(url
, pg
);
811 System
.out
.println(meta
.getLuid() + ": \"" + meta
.getTitle() + "\" imported.");
812 } catch (IOException e
) {
813 Instance
.getInstance().getTraceHandler().error(e
);
821 * Export the {@link Story} from the {@link LocalLibrary} to the given
827 * the {@link OutputType} to use
831 * the optional progress reporter
833 * @return the exit return code (0 = success)
835 protected static int export(String luid
, OutputType type
, String target
,
838 Instance
.getInstance().getLibrary().export(luid
, type
, target
, pg
);
839 } catch (IOException e
) {
840 Instance
.getInstance().getTraceHandler().error(e
);
848 * List the stories of the given source from the {@link LocalLibrary}
849 * (unless NULL is passed, in which case all stories will be listed).
852 * the source to list the known stories of, or NULL to list all
855 * @return the exit return code (0 = success)
857 protected int list(String source
) {
859 new CliReader().listBooks(source
);
860 } catch (IOException e
) {
861 Instance
.getInstance().getTraceHandler().error(e
);
869 * Start the current reader for this {@link Story}.
874 * which {@link Chapter} to read (starting at 1), or NULL to get
875 * the {@link Story} description
877 * @return the exit return code (0 = success)
879 protected int read(Story story
, Integer chap
) {
883 new CliReader().listChapters(story
);
885 new CliReader().printChapter(story
, chap
);
887 } catch (IOException e
) {
888 Instance
.getInstance().getTraceHandler()
889 .error(new IOException("Failed to read book", e
));
893 Instance
.getInstance().getTraceHandler()
894 .error("Cannot find book: " + story
);
902 * Convert the {@link Story} into another format.
905 * the source {@link Story} to convert
907 * the {@link OutputType} to convert to
911 * TRUE to also export the cover and info file, even if the given
912 * {@link OutputType} does not usually save them
914 * the optional progress reporter
916 * @return the exit return code (0 = success)
918 protected int convert(String urlString
, OutputType type
,
919 String target
, boolean infoCover
, Progress pg
) {
922 Instance
.getInstance().getTraceHandler().trace("Convert: " + urlString
);
923 String sourceName
= urlString
;
925 URL source
= BasicReader
.getUrl(urlString
);
926 sourceName
= source
.toString();
927 if (sourceName
.startsWith("file://")) {
928 sourceName
= sourceName
.substring("file://".length());
932 BasicSupport support
= BasicSupport
.getSupport(source
);
934 if (support
!= null) {
935 Instance
.getInstance().getTraceHandler()
936 .trace("Support found: " + support
.getClass());
937 Progress pgIn
= new Progress();
938 Progress pgOut
= new Progress();
941 pg
.addProgress(pgIn
, 1);
942 pg
.addProgress(pgOut
, 1);
945 Story story
= support
.process(pgIn
);
947 target
= new File(target
).getAbsolutePath();
948 BasicOutput
.getOutput(type
, infoCover
, infoCover
)
949 .process(story
, target
, pgOut
);
950 } catch (IOException e
) {
951 Instance
.getInstance().getTraceHandler()
952 .error(new IOException(
953 trans(StringId
.ERR_SAVING
, target
), e
));
957 Instance
.getInstance().getTraceHandler()
958 .error(new IOException(
959 trans(StringId
.ERR_NOT_SUPPORTED
, source
)));
963 } catch (IOException e
) {
964 Instance
.getInstance().getTraceHandler().error(new IOException(
965 trans(StringId
.ERR_LOADING
, sourceName
), e
));
968 } catch (MalformedURLException e
) {
969 Instance
.getInstance().getTraceHandler().error(new IOException(trans(StringId
.ERR_BAD_URL
, sourceName
), e
));
977 * Display the correct syntax of the program to the user to stdout, or an
978 * error message if the syntax used was wrong on stderr.
981 * TRUE to show the syntax help, FALSE to show "syntax error"
983 protected void syntax(boolean showHelp
) {
985 StringBuilder builder
= new StringBuilder();
986 for (SupportType type
: SupportType
.values()) {
987 builder
.append(trans(StringId
.ERR_SYNTAX_TYPE
, type
.toString(),
989 builder
.append('\n');
992 String typesIn
= builder
.toString();
993 builder
.setLength(0);
995 for (OutputType type
: OutputType
.values()) {
996 builder
.append(trans(StringId
.ERR_SYNTAX_TYPE
, type
.toString(),
997 type
.getDesc(true)));
998 builder
.append('\n');
1001 String typesOut
= builder
.toString();
1003 System
.out
.println(trans(StringId
.HELP_SYNTAX
, typesIn
, typesOut
));
1005 System
.err
.println(trans(StringId
.ERR_SYNTAX
));
1010 * Starts a search operation (i.e., list the available web sites we can
1013 * @throws IOException
1014 * in case of I/O errors
1016 protected void search() throws IOException
{
1017 new CliReader().listSearchables();
1021 * Search for books by keywords on the given supported web site.
1024 * the web site to search on
1026 * the keyword to look for
1028 * the page of results to get, or 0 to inquire about the number
1031 * the index of the book we are interested by, or 0 to query
1032 * about how many books are in that page of results
1034 * @throws IOException
1035 * in case of I/O error
1037 protected void searchKeywords(SupportType searchOn
, String search
,
1038 int page
, Integer item
) throws IOException
{
1039 new CliReader().searchBooksByKeyword(searchOn
, search
, page
, item
);
1043 * Search for books by tags on the given supported web site.
1046 * the web site to search on
1048 * the page of results to get, or 0 to inquire about the number
1051 * the index of the book we are interested by, or 0 to query
1052 * about how many books are in that page of results
1054 * the tags to look for
1056 * @throws IOException
1057 * in case of I/O error
1059 protected void searchTags(SupportType searchOn
, Integer page
, Integer item
,
1060 Integer
[] tags
) throws IOException
{
1061 new CliReader().searchBooksByTag(searchOn
, page
, item
, tags
);
1065 * Start a Fanfix server.
1067 * @throws IOException
1068 * in case of I/O errors
1069 * @throws SSLException
1070 * when the key was not accepted
1072 private void startServer() throws IOException
{
1073 String mode
= Instance
.getInstance().getConfig()
1074 .getString(Config
.SERVER_MODE
, "fanfix");
1075 if (mode
.equals("fanfix")) {
1076 RemoteLibraryServer server
= new RemoteLibraryServer();
1077 server
.setTraceHandler(Instance
.getInstance().getTraceHandler());
1079 } else if (mode
.equals("http")) {
1080 WebLibraryServer server
= new WebLibraryServer(false);
1081 server
.setTraceHandler(Instance
.getInstance().getTraceHandler());
1083 } else if (mode
.equals("https")) {
1084 WebLibraryServer server
= new WebLibraryServer(true);
1085 server
.setTraceHandler(Instance
.getInstance().getTraceHandler());
1088 throw new IOException("Unknown server mode: " + mode
);
1093 * Stop a running Fanfix server.
1096 * the key to contact the Fanfix server
1098 * the host on which it runs
1100 * the port on which it runs
1102 * @throws IOException
1103 * in case of I/O errors
1104 * @throws SSLException
1105 * when the key was not accepted
1107 private void stopServer(String key
, String host
, int port
)
1108 throws IOException
, SSLException
{
1109 if (host
.startsWith("http://") || host
.startsWith("https://")) {
1110 new WebLibrary(key
, host
, port
).stop();
1112 new RemoteLibrary(key
, host
, port
).stop();
1117 * We are done and ready to exit.
1119 * By default, it will call {@link System#exit(int)} if the status is not 0.
1124 protected void exit(int status
) {
1126 System
.exit(status
);
1131 * Simple shortcut method to call {link Instance#getTrans()#getString()}.
1134 * the ID to translate
1136 * @return the translated result
1138 static private String
trans(StringId id
, Object
... params
) {
1139 return Instance
.getInstance().getTrans().getString(id
, params
);