Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Java Application Deployment: Web Start, Self-Contained Bundles, and JAR Packaging

Notes May 14 1

Deploying Java Web Start Applications

The Deployment Toolkit script provides the createWebStartLaunchButton function for deploying Java Web Start apps. These applications rely on the Java Network Launch Protocol (JNLP). The function generates an HTML anchor tag (<a>) linking to the JNLP file, rendering as a launch button. When clicked, the script verifies the appropriate Java Runtime Environment (JRE) is installed before starting the app.

If the client lacks the minimum required JRE, the script redirects the browser to java.com for downloading the latest version.

Function Signatures:
createWebStartLaunchButton: function(jnlp, minimumVersion)
createWebStartLaunchButton: function(jnlp)

Parameters:

  • jnlp – The absolute URL of the JNLP file containing deployment details.
  • minimumVersion – The lowest JRE version required to execute the application.

Usage with Minimum Version:

<script src="https://www.java.com/js/deployJava.js"></script>
<script>
    var appJnlpPath = "http://example.com/apps/texteditor.jnlp";
    deployJava.createWebStartLaunchButton(appJnlpPath, '1.8.0');
</script>

Usage without Minimum Version:

If no specific JRE version is mandated, use the single-argument signature.

Note: When using these functions, an absolute codebase must be specified in the JNLP file to allow command-line execution via javaws <path/to/local JNLP file>.

Customizing the Launch Button

To replace the default launch button graphic, assign a new image URL to the deployJava.launchButtonPNG variable before invoking the launch button creation.

<script src="https://www.java.com/js/deployJava.js"></script>
<script>
    deployJava.launchButtonPNG = 'https://example.com/img/launch_icon.png';
    var launchTarget = "https://example.com/apps/TextEditor.jnlp";
    deployJava.createWebStartLaunchButton(launchTarget, '1.8.0');
</script>

Deploying Without a Codebase

Starting with Java SE 7, absolute paths for the codebase attribute in JNLP files are optional. If omitted, Java Web Start assumes the codebase is relative to the web page launching the application.

For JNLP files lacking a codebase, use these Deployment Toolkit functions:

  • launchWebStartApplication – Deploys via an HTML link.
  • createWebStartLaunchButtonEx – Generates a launch button.

Running apps deployed this way requires at least Java SE 7. If absent, the user is prompted to install it.

Function Signature: launchWebStartApplication: function(jnlp)

<script src="https://www.java.com/js/deployJava.js"></script>
<a href="javascript:deployJava.launchWebStartApplication('dynamicchart_no_codebase.jnlp');">Open Application</a>

Function Signature: createWebStartLaunchButtonEx: function(jnlp)

<script src="https://www.java.com/js/deployJava.js"></script>
<script>
    var descriptorRef = "dynamicchart_no_codebase.jnlp";
    deployJava.createWebStartLaunchButtonEx(descriptorRef);
</script>

Verifying Client JRE Version

The Deployment Toolkit's versionCheck function determines if a specific JRE version or range is present on the client machine.

Function Signature: versionCheck: function(versionPattern)

Parameter:

  • versionPattern – A string defining the version or range (e.g., "1.8", "1.8.0_*", "1.8.0_101+").
<script src="https://www.java.com/js/deployJava.js"></script>
<script>
    if (deployJava.versionCheck('1.8+')) {
        var appUrl = "https://example.com/apps/ChartApp.jnlp";
        deployJava.createWebStartLaunchButton(appUrl, '1.8.0');
    } else {
        document.location.href = "http://oracle.com";
    }
</script>

Java Network Launch Protocol

JNLP enables applications to launch on a client desktop using resources hosted on a remote web server. Rich Internet Applications (RIAs) launched via JNLP can access JNLP APIs, permitting client desktop access upon user consent. A JNLP file describes the RIA, specifying the main JAR, required JRE version, display information, and system properties.

Structure of a JNLP File

<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="" href="">
    <information>
        <title>Interactive Chart Demo</title>
        <vendor>Chart Dev Team</vendor>
        <icon href="chart-icon.jpg"/>
        <offline-allowed/>
    </information>
    <resources>
        <j2se version="1.8+" href="http://java.sun.com/products/autodl/j2se"/>
        <jar href="ChartDemo.jar" main="true" />
    </resources>
    <application-desc
         name="Interactive Chart Application"
         main-class="com.example.ChartApplication"
         width="800"
         height="600">
    </application-desc>
    <update check="background"/>
</jnlp>

Common elements include <jnlp> (root), spec (minimum JNLP spec version), codebase (base URL for relative paths), href (URL of the JNLP file itself), <information> (title, vendor, icon, offline permissions), <resources> (JRE version, JAR files, system properties), and <application-desc> (main class and arguments).

JNLP files support any character encoding supported by the Java platform. Specify the encoding in the XML prolog, though the prolog itself must be UTF-8 encoded.

Deployment Best Practices

  • Sign the RIA with a certificate from a trusted Certificate Authority.
  • Request the minimum necessary privileges; use the sandbox if unrestricted system access is unneeded.
  • Optimize JAR and resource sizes for faster loading.
  • Enable version download protocols and background update checks.
  • Verify the client possesses the required JRE version using the Deployment Toolkit.
  • Embed the applet's JNLP content within the <applet> tag (Java SE 7+) to avoid extra network requests.
  • Preload Java Web Start applications in enterprise environments: javaws -import -silent <jnlp url>

Reducing Download Time

Download duration depends on JAR file size. Optimization techniques include:

  • Compressing JAR files using the pack200 tool.
  • Removing extraneous whitespace from JNLP and JavaScript files.
  • Optimizing images and animations.

Steps for signed RIAs:

  1. Normalize the JAR: pack200 --repack ChartApp.jar
  2. Sign the normalized JAR: jarsigner -keystore secureKeys ChartApp.jar devAlias
  3. Pack the signed JAR: pack200 ChartApp.jar.pack.gz ChartApp.jar
  4. Enable pack property in the JNLP:
    <resources>
        <property name="jnlp.packEnabled" value="true"/>
    </resources>
    When enabled, the plugin searches for .pack.gz files, falling back to standard JARs if absent.

Avoiding Unnecessary Update Checks

By default, the launch software verifies each JAR file is up-to-date, which adds latency. To mitigate this:

Leveraging Version Download Protocol

Rename JAR files to include version numbers (e.g., ChartApp__V1.0.jar). Specify the version in the JNLP and enable the protocol:

<resources>
    <jar href="ChartApp.jar" main="true" version="1.0"/>
    <property name="jnlp.versionEnabled" value="true"/>
</resources>

Background Update Checks

If running the absolute latest version instantly is not critical, launch the cached version and check for updates in the background. Add the following to the JNLP file:

<update check="background"/>

Ensuring JRE Presence

RIAs often require a minimum JRE version. The Deployment Toolkit offers two strategies:

Immediate Check on Site Entry

<script src="https://www.java.com/js/deployJava.js"></script>
<script>
    if (!deployJava.versionCheck('1.8.0_101+')) {
        var proceed = confirm("A newer Java Runtime is required. Update now?");
        if (proceed) {
            deployJava.returnPage = location.href;
            deployJava.installLatestJRE();
        }
    }
</script>

On-Demand Check

By specifying the minimum version in runApplet or createWebStartLaunchButton, the toolkit ensures the JRE is present before running the RIA.

var appAttributes = { code:'com.example.ChartApplet', width:800, height:600};
var appParams = {jnlp_href: 'chart_applet.jnlp'};
deployJava.runApplet(appAttributes, appParams, '1.8');

Self-Contained Applications

Self-contained applications bundle the application and a dedicated JRE into a single installable package, operating like native software. This bypasses browser security conflicts and allows custom icons, file associations, and multiple entry points.

Prerequisites

Installable bundles must be built on the target platform. Required third-party tools:

  • Windows: Inno Setup 5+ (EXE), WiX Toolset 3.8+ (MSI)
  • Linux: RPMBuild (RPM), Debian packaging tools (DEB)
  • OS X: Native tools (DMG, PKG)

Converting an Existing Application

Organize resources in a project directory. Web Start HTML/JNLP files are unnecessary. Platform-specific icons reside in /src/package/ subdirectories (e.g., /windows, /linux, /macosx).

Ant tasks (fx:deploy) handle packaging. The nativeBundles attribute dictates the output format (e.g., all, installer, image, or specific formats like msi).

<project name="ChartPackaging" default="default" basedir="." >
    <target name="package" depends="jar">
        <taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
                 uri="javafx:com.sun.javafx.tools.ant"
                 classpath="${java.home}/../lib/ant-javafx.jar;src"/>
        <fx:deploy outdir="${basedir}/build/packager"
                   outfile="ChartDemo"
                   nativeBundles="all">
            <fx:application name="Chart Demo"
                        mainClass="com.example.ChartApplication" version="1.0"/>
            <fx:resources>
                <fx:fileset dir="dist" includes="ChartDemo.jar"/>
            </fx:resources>
            <fx:info title="Chart Demo" vendor="Example Corp"/>
            <fx:bundleArgument arg="win.menuGroup" value="Demos"/>
        </fx:deploy>
    </target>
</project>

Run ant package to generate binaries in build/packager/bundles.

Configuring File Associations

Self-contained applications can be linked to specific file extensions or MIME types using the <fx:association> element. Best practice dictates specifying both extension and MIME type for cross-platform compatibility.

<fx:info title="Code Runner">
    <fx:association extension="py" mimetype="text/x-python" description="Python Script"/>
    <fx:association extension="rb" mimetype="text/x-ruby" description="Ruby Script"/>
</fx:info>

On Windows and Linux, opening an associated file passes the file path as an argument to the main class. On macOS, a single instance runs, and an OpenFilesEvent is dispatched to a registered FileOpenHandler. Admin privileges may be required for system-wide associations (e.g., setting win.exe.systemWide to true).

Adding External Libraries

External dependencies can be downloaded during the build process and included in the /dist directory alongside the application JAR.

<copy toFile="lib/script-engine.jar">
    <resources>
      <url url="http://repo.example.com/script-engine.jar"/>
    </resources>
</copy>

Providing Default Arguments

Default command-line arguments can be passed using the <fx:argument> element inside <fx:application>.

<fx:application id="coderunner" name="Code Runner" mainClass="${main.class}">
    <fx:argument>default_script.py</fx:argument>
</fx:application>

Cross-Platform Build Configuration

A single Ant build file can support all platforms. Use conditions to determine the main class (e.g., macOS requires a specific handler class) and exclude platform-specific files.

<condition property="main.class" 
           value="com.example.RunnerApp" 
           else="com.example.RunnerAppMac">
    <not><os family="mac"/></not>
</condition>

Multiple Entry Points

To bundle multiple applications, define the primary entry point in <fx:application mainClass="..."> and secondary launchers using <fx:secondaryLauncher>.

<fx:secondaryLauncher name="Data Viewer"
    mainClass="com.example.DataViewer"
    title="Data Viewer"
    vendor="Example Corp">
</fx:secondaryLauncher>

Packaging Programs in JAR Files

The Java Archive (JAR) format aggregates multiple files into a single archive, typically containing class files and auxiliary resources. Benefits include security (digital signatures), reduced download time (single HTTP transaction), compression, package sealing, and versioning.

Basic JAR Operations

  • Creating: jar cf archive.jar input-files
  • Viewing: jar tf archive.jar
  • Extracting: jar xf archive.jar
  • Updating: jar uf archive.jar new-files
  • Running: java -jar app.jar (requires Main-Class manifest header)

Useful options include v (verbose), 0 (no compression), M (no manifest), and -C (change directory during execution). Metadata inside JAR files must use UTF-8 encoding.

Working with Manifest Files

The manifest file (META-INF/MANIFEST.MF) contains metadata about the JAR's contents. The default manifest specifies the version and creator tool.

Modifying the Manifest

Use the m option to merge custom headers from a text file into the manifest: jar cfm archive.jar manifest.txt input-files

Setting the Application Entry Point

Define the main class using the Main-Class header.

Main-Class: com.example.MyApp

Alternatively, use the e flag during creation: jar cfe app.jar com.example.MyApp com/example/MyApp.class

Adding Classes to the Class Path

Specify dependent JARs in the Class-Path header to avoid long command-line classpath configurations.

Class-Path: lib/utils.jar lib/logger.jar

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.