Java Application Deployment: Web Start, Self-Contained Bundles, and JAR Packaging
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
pack200tool. - Removing extraneous whitespace from JNLP and JavaScript files.
- Optimizing images and animations.
Steps for signed RIAs:
- Normalize the JAR:
pack200 --repack ChartApp.jar - Sign the normalized JAR:
jarsigner -keystore secureKeys ChartApp.jar devAlias - Pack the signed JAR:
pack200 ChartApp.jar.pack.gz ChartApp.jar - Enable pack property in the JNLP:
When enabled, the plugin searches for<resources> <property name="jnlp.packEnabled" value="true"/> </resources>.pack.gzfiles, 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(requiresMain-Classmanifest 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.MyAppAlternatively, 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