Skip to content

Commit 4efd476

Browse files
ctruedenclaude
andcommitted
Update README with current feature set
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ce89f97 commit 4efd476

1 file changed

Lines changed: 107 additions & 19 deletions

File tree

README.md

Lines changed: 107 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
99
or [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

2271
The 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

Comments
 (0)