How to launch recent versions of ROES from Linux

After using the ROES printing client (which I use with BayPhoto and WHCC) for a really long time, I discovered earlier this year that recent versions use JavaFX, and I could no longer launch it with just javaws roes_client.jlnp. The following isn’t a completely finished solution, but it got me to the point of sending out a new print order, so I figured that’s good enough to write it up.

The approach that no longer works for me

If I just run javaws roes_client.jlnp, I click through the normal dialogs before getting an error like the following:

netx: Launch Error: Could not launch JNLP file. ( (javafx/application/Platform (javafx.application.Platform)))
net.sourceforge.jnlp.LaunchException: Fatal: Launch Error: Could not launch JNLP file. The application has not been initialized, for more information execute javaws/browser from the command line and send a bug report.
	at java.desktop/net.sourceforge.jnlp.Launcher.launchApplication(
	at java.desktop/net.sourceforge.jnlp.Launcher$
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(
	at java.base/java.lang.reflect.Method.invoke(
	at java.desktop/net.sourceforge.jnlp.Launcher.launchApplication(
	... 1 more
Caused by: java.lang.NoClassDefFoundError: javafx/application/Platform
	at<init>(Unknown Source)
	at Source)
	... 6 more
Caused by: java.lang.ClassNotFoundException: javafx.application.Platform
	at java.desktop/net.sourceforge.jnlp.runtime.JNLPClassLoader.loadClass(
	... 8 more

The error all the way at the bottom is the root cause:
java.lang.ClassNotFoundException: javafx.application.Platform
So the JVM wasn’t able to find and load the core JavaFX libraries, which are required by the ROES client.

Packages to install

I’m on Debian, so the packages I list are as named/packaged in Debian. YMMV. That said, these are the important ones:

  • icedtea-netx provides the “Java Web Start” implementation that can interpret and run .jnlp files, which is how ROES is executed.
  • openjfx provides the JavaFX implementation that will be used by the ROES client.
  • openjdk-11-jre the base Java runtime environment that will be used by the ROES client. I haven’t tried this with more recent versions — I picked 11 because it matches the openjfx version, so I figured it had the highest chance of success.

Building a command line

javaws is actually just a shell script that runs java, so we can use bash with command echoing to see what the base java command is:

$bash -x $(which javaws) launch.jnlp 
+ exec -a javaws /usr/lib/jvm/default-java/bin/java -splash:/usr/share/icedtea-web/javaws_splash.png -Xbootclasspath/a:/usr/share/icedtea-web/javaws.jar:/usr/share/java/js.jar:/usr/share/java/tagsoup.jar:/usr/lib/jvm/default-java/lib/ext/nashorn.jar -Xms8m --patch-module java.desktop=/usr/share/icedtea-web/javaws.jar: @/usr/share/icedtea-web/bin/itw-modularjdk.args -classpath /usr/lib/jvm/default-java/lib/rt.jar:/usr/lib/jvm/default-java/lib/ext/jfxrt.jar -Dicedtea-web.bin.location=/usr/share/icedtea-web/bin/ net.sourceforge.jnlp.runtime.Boot launch.jnlp

And we know that the JVM will look for classes to load on the classpath. Two important javaws arguments are the following:

$javaws --help
    -nosecurity          - Disables the secure runtime environment. You need also to workaround corrupted signatures(No argument expected)
    -Xnofork             - Do not create another JVM.(No argument expected)

On Debian, the openjfx JARs are installed at /usr/share/openjfx/lib/*.jar. Because I don’t know a simple way to join the OpenJFX JAR filenames with a colon character in bash, I just did it in ruby, using
ruby -e 'puts ARGV.join(":")' /usr/share/openjfx/lib/*.jar

And because I’m going to modify the classpath by hand, I need to make sure that the jnlp loader doesn’t start a new sub-JVM (which may not use the same classpath), so I use -Xnofork as the first option after the main class, net.sourceforge.jnlp.runtime.Boot.

Lastly, I would need to create a new security manager config that provides permissions to OpenJFX (since it’s not part of the JDK/JRE), but I just disabled the security manager instead, by removing from the command line, and adding -nosecurity after -Xnofork.

The command line that worked for me

All that said, here’s the command line that finally worked. Instead if figuring out how to get javaws to do what I needed, I just ran the java command by hand, based on what it had originally run. Note that I’m using the outer set of parens to create a sub-shell, so that the exec command doesn’t terminate my terminal shell — I don’t know how important it is for the java process to be called javaws, but I figured it’s easy enough to keep that working, so I did it.

$ (exec -a javaws /usr/lib/jvm/default-java/bin/java -splash:/usr/share/icedtea-web/javaws_splash.png -Xbootclasspath/a:/usr/share/icedtea-web/javaws.jar:/usr/share/java/js.jar:/usr/share/java/tagsoup.jar:/usr/lib/jvm/default-java/lib/ext/nashorn.jar -Xms8m --patch-module java.desktop=/usr/share/icedtea-web/javaws.jar: @/usr/share/icedtea-web/bin/itw-modularjdk.args -classpath /usr/lib/jvm/default-java/lib/rt.jar:/usr/lib/jvm/default-java/lib/ext/jfxrt.jar:$(ruby -e 'puts ARGV.join(":")' /usr/share/openjfx/lib/*.jar) -Dicedtea-web.bin.location=/usr/share/icedtea-web/bin/ net.sourceforge.jnlp.runtime.Boot -Xnofork -nosecurity launch.jnlp)
1 Like

WHCC really needs to update that thing, but food job getting it going.

Yeah, I was about to write that ROES doesn’t have any competitors, so I wasn’t sure who would make something better, but it looks like the company that makes ROES also has a web-app version, so I have no idea why all the labs stick with the Java one: