For about the past 15 years, an organization I work with has used the Java Network Launching Protocol (JNLP) to internally distribute a Java Swing desktop application to its users.
To access the Java Swing application, users had to install a specific version of Java Platform, Standard Edition (Java SE) that contained support for JNLP. When they wanted to use the application, they would click on the link in the organization's intranet, and the Java Web Start (javaws) program would download the XML at the link, interpret it, download the current version of the application if necessary, and run it, all while managing the security sandbox where the application ran. In other words, it was a nice, low-ceremony way to distribute a completely configured application to everyone's desktop.
However, because JNLP is no longer a part of Java SE (from version 11 onward), the organization was faced with a decision: discontinue its use of JNLP as a part of Java SE or eliminate its policy of staying reasonably up to date with Java SE releases. This relatively simple-sounding choice turned out to be somewhat complex for various reasons.
Option 1: Stay with current Java SE and find a substitute for JNLP
IcedTea-Web is an open source project that provides JNLP capabilities. This would imply a two-step pre-configuration process: 1) install Java SE and 2) install IcedTea-Web, which would increase client-side maintenance. Unfortunately, when we were evaluating the options, there was not a working IcedTea-Web facility compatible with Java 11, so this would mean using Java 8. However, Java SE 8 was reaching end-of-life in March 2019, so we would have to create a Java 8 runtime environment from OpenJDK 8 for installation on the client machines and move to a more manual process of tracking OpenJDK 8 updates. Neither of these approaches seemed very appealing.
Option 2: Move away from JNLP
At first, this approach seemed like the worst possible scenario—we would need to modify the application to provide configuration information in some other fashion; all the nice automated-update stuff in JNLP would be discarded; and we would need some kind of per-workstation installation process. Ugh! Or we could rewrite the existing fat client application, liked by its user community, as a web app. Double ugh!!!
All this negativity was surmounted by a few interesting discoveries and a bit of careful thinking:
- The configuration information could be packaged as metadata in a metadata table that could be selected as a "configuration" by the end user.
- The application could fairly easily check its version number against the currently distributed version number and refuse to run, or at least complain to any user running an out-of-date version.
- The application could be packaged along with a customized Java runtime created with the jdeps and jlink commands provided in Open JDK 11, thus ensuring the application always runs with the correct version of Java.
- The whole installation and execution business could be handled on the client side with Windows .cmd files, eliminating the need for an installer (perhaps one day…).
- The application and the customized Java runtime distribution could still be handled as a download from the intranet.
With this detail, the attentive reader may be able to guess…
The chosen solution
In the end, the organization decided to move away from JNLP because the amount of end-user management seemed reasonably straightforward compared to maintaining the existing JNLP environment.
Here is the detailed process for getting to the solution:
- Building the application:
- The app was always developed and maintained using the NetBeans IDE running in a Linux desktop environment; this is still the case, using OpenJDK 11 (from the distro) and NetBeans 10 (downloaded from the new Apache NetBeans site).
- The build process creates an operating system-agnostic dist folder containing the application .jar file and all required libraries
- Customizing the Java 11 runtime:
- Unfortunately, there's no way to customize cross-platform Java runtimes, so we need an intermediate Windows computer—let's call it the IWC. (I'm going to come right out and say this is the major drawback of our approach.)
- OpenJDK 11 prebuilt binaries are installed on the IWC.
- The application dist folder is copied to the IWC.
- Inside the dist folder, the jdeps command from OpenJDK 11 determines which Java runtime components are needed to support the application:
jdeps --print-module-deps TheApplication.jar lib\*
- Using the output of the above command, the jlink command (also from OpenJDK 11) builds the customized runtime:
jlink --no-header-files --no-man-pages --compress=2 \
--strip-debug –add-modules \ java.base,java.desktop,java.sql,java.security.jgss,java.xml \
- At this point, the application can be run (tested) from this folder using the command:
.\customjre\bin\java -jar TheApplication.jar
- The Install.cmd and RunTheApplication.cmd files are copied into the dist folder.
- Bundling the application for distribution:
- The dist folder, containing the application, .cmd files and the custom runtime, is zipped and put on the intranet server; a link pointing to the .zip file allows users to download it.
- Downloading, installing, and running the application:
- The user navigates to the page containing the link pointing to the .zip file.
- Clicking on the link downloads the .zip file.
- The user unzips the .zip file, navigates to the dist folder, and double-clicks Install.cmd.
- When Install.cmd executes, it copies the dist folder into a known place on the user's computer and installs the RunTheApplication.cmd link on the user's desktop.
- The user will need to have certain permissions to install the application.
- The user does not need Java SE installed on the computer.
The application was modified to:
- Read the configuration parameters from a database table (the organization thinks of these as "project parameters," so the user is "selecting a project").
- The VERSION=123 string is extracted from the RELEASE_NOTES.TXT locally and on the server to make sure the versions match (and the end user is harassed if they do not).
That's it. Of course, it's possible to use an installer rather than the .cmd files for a "more professional" installation experience. It's also possible to find other ways to install OpenJDK 11 on the IWC, which could even be a virtual machine (making it the VIWC). It's too bad the jlink command doesn't have a --target-platform option or many other improvements that might be desirable or necessary depending on the nature of the deployment environment.
How well does it work?
Early reports indicate users are happy with the results, and sysadmins are no longer responsible for watching over the Java SE version installed. As for the guy supporting the application, he's more or less OK with the extra build steps—but would rather deal with two machines than run a VIWC on his beautiful System76 laptop.