Deploying the Calculator

When I first began experimenting with JavaFX and related toolsets, it became apparent that deploying a Java application into a web browser was a cumbersome process.  The default, using Java Archive (JAR) files with the Java Network Launch Protocol (JNLP) was straightforward enough, but places a burden on every potential user of the application.  You must have Java installed on your system, and you must have your system privileges set to run the app.  JNLP will be happy to install Java for you, of course, but not everyone understands the ramifications of doing so.  You must endure somewhat annoying dialogs as you launch the app; to the uninitiated these can be confusing and off-putting.  Curiosity about your app can quickly be dispelled during the download-and-run process. There were (and still are) a host of issues related to running out of a JAR, mostly thanks to exploits, even in the latest versions of the code.  Small wonder that developers have mostly abandoned this technique in favor of building native wrappers for the app, or bypassing Java altogether in favor of languages and tools that directly support web deployment.

When I revisited my early version and upgraded to Java 8, I decided to explore NetBeans “built-in” capability to create a native language version of an application.  The Oracle documentation makes this option somewhat of a no-brainer:

“The easiest way to produce a self-contained application is to modify the deployment task. To request creation of all applicable self-contained application packages simply add nativeBundles="all" to the task…” [Note: this is done in the build.xml file, which is created by NetBeans when you create your project -  see Listing 20].

<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<project name="DateCalculator" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
    <description>Builds, tests, and runs the project DateCalculator.</description>
    <import file="nbproject/build-impl.xml"/>
    <target name="-post-jfx-deploy">
       <fx:deploy width="${javafx.run.width}" height="${javafx.run.height}"
                  nativeBundles="all"
                  outdir="${basedir}/${dist.dir}" outfile="${application.title}">
          <fx:application name="${application.title}"
                          mainClass="${javafx.main.class}"/>
          <fx:resources>
              <fx:fileset dir="${basedir}/${dist.dir}"
                          includes="*.jar"/>
          </fx:resources>
          <fx:info title="${application.title}"
                   vendor="${application.vendor}"/>
        </fx:deploy>         
     </target>
</project>

Listing 20 – modified build.xml file

My initial attempt to generate a native Windows application worked the first time!  The resulting dist folder structure looks like Figure 9:

  Deployment Structure

Figure 9 – Build Deployment Artifacts in my NetBeans Application Folder

The standard deployment build script (without the ‘nativeBundles=all’ directive) generates the DateCalculator.jar file, the .html and .jnlp files, and the web-files directories.  The bundles directory is created when you include the ‘nativeBundles=all’ directive; it contains the native executable file, with supplemental JAR and CFG files (in the app directory), and a “subset” (Oracle’s term) of the Java run-time libraries (in the runtime directory).  I did a cursory examination of the deployment JRE created by NetBeans and the JRE in my filesystem.  The NetBeans JRE is slightly larger (148MB vs 136MB) even though certain installed folders (such as the applet folder) are not included in the bundles package.  I did a cursory examination of the two folder sets; it appears that the main reason that the deployment folder is larger than the filesystem folder is the JavaSE run-time JAR file (rt.jar) is larger by about 9MB.  Futher investigation into the content of the run-time JARS in the two folders shows that the JAR file contents are the same but the deployment class files are always larger, by anywhere from 10% to 30%.  It is possible that the deployment files have added overhead, or a somewhat different compression algorithm; I didn’t do any further research to explore the reason for  the larger deployment size.

So the question is: what do you deploy, and how do you bundle the native application so that it can be run on various Windows versions?   Clearly JNLP is designed to minimize the effort on the part of the developer (me, in this case), and put some of the onus on the curious user who wants to download the app.  Again, if the user has a reasonably recent JRE installed on his or her machine, has the proper security privileges set, and is willing to submit to the JNLP install process, it’s all pretty straightforward.  On the other hand, deploying a native version of the app has some appeal as well: package the necessary components into a zip file (or some equivalent tarball), and post it for download in a web page.  The only down-side, as I see it, is that the download is much larger than it probably needs to be (a more sophisticated approach is to refine the build process to only include class files and support files actually needed by the application, but that strikes me as an onerous and complex task).

To test the bundled application, I copied the dist directory structure to a new laptop (OS: 64-bit Windows 8), which had no installed JRE.  As expected, the bundled version ran just fine, as did the JNLP installer (although I had to tweak some permission settings, and wait a couple of minutes for the download to complete; understandable, given the size of the download).