@@ -8,21 +8,78 @@ Jaunch is by no means the only solution for the native executable side;
88[ ` jpackage ` ] ( https://docs.oracle.com/en/java/javase/21/docs/specs/man/jpackage.html )
99or [ jDeploy] ( https://www.jdeploy.com/ ) should also work for example.
1010
11- The app-launcher's most major functions are:
12-
13- * Ensure the version of Java being used is appropriate to app's requirements.
14- In case it isn't, offer to upgrade Java by downloading a more appropriate version.
15-
16- * Load classes dynamically, without relying on the system classpath.
17-
18- * Display a splash window while the application is starting up.
11+ ## Major features
12+
13+ ### Java version checking and upgrade
14+
15+ The app-launcher verifies that the running JVM meets the application's minimum
16+ and recommended Java version requirements, as specified by
17+ ` scijava.app.java-version-minimum ` and ` scijava.app.java-version-recommended ` ,
18+ respectively. If the version is too old, the user is offered a choice: download
19+ and install a newer Java automatically, switch to an already-present
20+ good-enough installation, or proceed anyway. The download URL is resolved
21+ per-platform from the file pointed to by ` scijava.app.java-links ` , and the new
22+ installation path is written back into the config file indicated by
23+ ` scijava.app.config-file ` so that the native launcher can pick it up on the
24+ next start.
25+
26+ ### Splash window
27+
28+ While the application initializes, the app-launcher displays a lightweight
29+ splash window with an optional logo image (given by ` scijava.app.splash-image ` )
30+ and a progress bar. The window closes automatically once a window from the main
31+ application appears on screen.
32+
33+ ### Single-instance enforcement
34+
35+ When ` scijava.app.single-instance ` is ` true ` , only one JVM instance of the
36+ application runs at a time. The first instance opens a TCP server socket and
37+ writes the port number and a 128-bit random secret into a private lockfile; any
38+ subsequent launch reads the lockfile, forwards its command-line arguments to
39+ the running instance over the socket, and exits without showing the splash
40+ screen. The running instance receives the arguments and acts on them as
41+ appropriate (e.g. by opening files). The wire protocol is line-oriented plain
42+ text; the client sends the secret as the first line, then one argument per
43+ line, then closes the connection.
44+
45+ ### Module unlocking
46+
47+ When ` scijava.app.unlock-modules ` is ` true ` , the app-launcher calls
48+ ` ReflectionUnlocker.unlockAll() ` before doing anything else. This defeats
49+ Java 9+ JPMS encapsulation by calling ` implAddOpensToAllUnnamed() ` on every
50+ module, allowing deep reflection without needing ` --add-opens ` JVM arguments
51+ except for a single ` --add-opens=java.base/java.lang=ALL-UNNAMED ` argument.
52+
53+ ### Swing Look & Feel configuration
54+
55+ Setting ` scijava.app.look-and-feel ` to a fully-qualified class name causes the
56+ app-launcher to install that ` LookAndFeel ` before creating any UI components.
57+ This keeps the splash and error dialogs visually consistent with the main
58+ application, and enables smarter HiDPI handling via Look & Feels such as
59+ [ FlatLaf] ( https://www.formdev.com/flatlaf/ ) .
60+
61+ ### Class launching
62+
63+ ` ClassLauncher ` is the main entry point. It accepts the target class name and
64+ passes any remaining arguments to that class's ` main ` method. If the target
65+ class fails to load because it was compiled for a newer JVM
66+ (` UnsupportedClassVersionError ` ), the launcher catches the error and offers the
67+ user a Java upgrade before exiting.
1968
2069## Supported configuration
2170
2271The app-launcher uses system properties to configure its behavior:
2372
24- * ` scijava.app.name ` : Name of the application being launched.
25- Used in message dialogs if/when interacting with the user.
73+ * ` scijava.app.name ` : Human-readable name of the application being launched.
74+ Used in splash progress messages and in user-facing dialogs ("Please restart
75+ Fizzbuzz to apply the changes", "Fizzbuzz has been successfully updated to
76+ use the newer Java", etc.).
77+
78+ * ` scijava.app.directory ` : Path to the application's installation directory.
79+ Used to convert Java installation paths to relative form when writing to the
80+ config file, improving portability when the app is moved or accessed from
81+ multiple operating systems. If unset or pointing to a nonexistent path,
82+ absolute paths are used instead.
2683
2784* ` scijava.app.splash-image ` : Resource path to an image for the splash window,
2885 to be loaded using ` ClassLoader#getResource ` . It can be either its own file
@@ -35,7 +92,7 @@ The app-launcher uses system properties to configure its behavior:
3592 behavior on HiDPI displays using smarter Look & Feels such as
3693 [ FlatLaf] ( https://www.formdev.com/flatlaf/ ) .
3794
38- * ` scijava.app.java-root ` : directory containing "bundled " installations of Java.
95+ * ` scijava.app.java-root ` : Directory containing "managed " installations of Java.
3996 The ` Java.root() ` method reports this value if it points to a valid directory.
4097 The ` Java.check() ` method will look here (via ` Java.root() ` ) for which JVMs
4198 are already present locally, and also unpack any newly downloaded JVM into
@@ -56,17 +113,48 @@ The app-launcher uses system properties to configure its behavior:
56113 the ` scijava.app.java-platform ` property must be set and match one of the keys
57114 indicated within the fetched remote resource.
58115
59- * ` scijava.app.java-version-minimum ` : The minimum version of Java required by
60- the application. It can be a standalone number like 11, in which case it is
61- treated as a major version, or a dot-separated sequence of digits, which case
62- version comparisons are done digit by digit (see ` Versions.compare ` ).
63- This value is used by ` Java.check() ` (via ` Java.minimumVersion() ` ) to
64- warn the user accordingly if the running Java version is not good enough.
116+ * ` scijava.app.java-platform ` : Identifies the current platform, e.g.
117+ ` linux-x64 ` , ` macos-arm64 ` , ` windows-x64 ` . Must match one of the keys in the
118+ file pointed to by ` scijava.app.java-links ` for a Java download to succeed.
119+ Typically set by the native launcher. If no matching entry is found, the
120+ detected platform string is included in the error message shown to the user.
121+
122+ * ` scijava.app.java-version-minimum ` : The minimum version of Java required by
123+ the application. It can be a standalone number like ` 11 ` , in which case it is
124+ treated as a major version, or a dot-separated sequence of digits, in which
125+ case version comparisons are done digit by digit (see ` Versions.compare ` ).
126+ This value is used by ` Java.check() ` to warn the user if the running Java
127+ version is not good enough, and to determine whether the warning is framed as
128+ a hard requirement or a strong recommendation.
65129
66130* ` scijava.app.java-version-recommended ` : The minimum version of Java the
67131 application would * prefer* to use. Same syntax as ` java-version-minimum ` .
68- This value is used by ` Java.check() ` (via ` Java.recommendedVersion() ` ) to
69- warn the user accordingly if the running Java version is not ideal.
132+ If the running version is at or above this value no warning is shown, even if
133+ it is below ` java-version-minimum ` — the minimum check only fires when both
134+ properties are set and the version is below both.
135+
136+ * ` scijava.app.config-file ` : Path to a key=value configuration file (typically
137+ the native launcher's config file, e.g. a Jaunch-compatible CFG file) where
138+ the ` jvm-dir ` entry is updated after a Java installation is selected or
139+ downloaded. This is how the app-launcher tells the native launcher which JVM
140+ to use on the next startup.
141+
142+ * ` scijava.app.single-instance ` : Set to ` true ` to enable single-instance mode.
143+ The first launch listens on a dynamically chosen TCP port and writes the port
144+ and a 128-bit random secret into an owner-readable-only lockfile. Subsequent
145+ launches read the lockfile, hand off their arguments to the running instance
146+ over the socket, and exit immediately. The lockfile name is derived from
147+ ` scijava.app.name ` .
148+
149+ * ` scijava.app.unlock-modules ` : Set to ` true ` to call
150+ ` ReflectionUnlocker.unlockAll() ` at startup, opening all Java modules to
151+ unnamed-module reflection. This is equivalent to passing ` --add-opens ` for
152+ every module but requires no knowledge of which modules need to be opened;
153+ only ` --add-opens=java.base/java.lang=ALL-UNNAMED ` need be passed.
154+
155+ * ` scijava.app.debug ` : Set to ` true ` to enable verbose debug logging to
156+ ` stderr ` . Debug mode can also be enabled via ` scijava.log.level=debug ` or by
157+ setting the ` DEBUG_APP_LAUNCHER ` environment variable.
70158
71159## Provenance
72160
0 commit comments