The JNLPAppletLauncher is a general purpose JNLP-based applet
launcher class for deploying applets that use extension libraries
containing native code. It allows applets to use extensions like
Java 3D, JOGL, and JOAL very easily, with just a few additional
parameters to the <applet>
tag, on Java SE
versions as far back as 1.4.2.
Like Java Web Start, the JNLPAppletLauncher uses an extension's .jnlp file to locate the native resources for a given extension. The applet developer only needs to specify the platform-independent .jar files containing the .class files for the extension. The platform-specific "nativelib" .jar files are downloaded automatically from the same server that hosts the extension's Java Web Start binaries.
Extensions that support JNLPAppletLauncher include Java 3D, JOGL, and JOAL. More can be added without needing to modify the JNLPAppletLauncher. See the section below on modifying extensions to work with the JNLPAppletLauncher.
The applet-launcher.jar
file containing the
JNLPAppletLauncher class must be signed with the same certificate
as the extension's native resources, for example "sun microsystems,
inc.". The user will receive a security dialog and will be prompted
to accept the certificate for the JLNPAppletLauncher. The applet
being deployed may be either signed or unsigned; if it is unsigned,
it runs inside the security sandbox, and if it is signed, the user
receives a security dialog to accept the certificate for the applet
(in addition to the applet-launcher jar, if it is signed by a
different entity).
The steps for deploying such applets are straightforward. First,
the archive
parameter to the applet tag must contain
applet-laucher.jar
, the extension .jar files, and any
jar files associated with your applet. See the section on organizing jar files for more details.
Second, the name of your applet's main class and a textual
description must be specified via the applet tag parameters
subapplet.classname
and
subapplet.displayname
.
Finally, the URLs for the extension .jnlp files being used must be
specified as parameters. The jnlpNumExtensions
parameter indicates the number of JNLP files that are referenced,
and for n
such files, their URLs are passed in as
parameters jnlpExtension1
...
jnlpExtension[n]
.
Traditionally, applets are specified with a codebase and an archive parameter, the latter which is a list of jar files relative to that codebase. The codebase is optional and defaults to the directory on the web server containing the HTML document which contains the applet tag. See the documentation for the applet tag.
It is not well documented, but at least in the Sun JRE at least as far back as Java SE 1.4.2, it is possible to use absolute URLs in the applet tag's archive parameter. This functionality works on all major operating systems: Windows, Mac OS X, Linux, and Solaris. This means that you can pull code resources from multiple web servers, not just one, in similar fashion to Java Web Start and its extension mechanism. (The security implications are that each unsigned piece of code downloaded from a separate server receives sandboxed permissions to connect back to that server; if there are multiple pieces of unsigned code on the stack during execution of the program then the permissions will be the intersection of all of those on the stack, implying that no programmatic network connections back to the web server(s) will be allowed. See the Applet Security FAQ for more details.)
This capability means that your applets can refer directly to extensions like Java 3D and JOGL hosted on Sun's web servers without having to duplicate their jar files on your web server.
To use this capability effectively with the JNLPAppletLauncher, you need to pull in at least three primary pieces of code: the applet launcher itself, your applet's code, and the Java code for the extension, or extensions, your applet depends on. (Remember that the JNLPAppletLauncher's primary function is to automatically download the native code associated with these extensions, and not the Java code for these extensions.)
You might choose to specify the codebase of your applet to point to
your web server's directory containing the jar files of your
applet, and specify absolute URLs to the
applet-launcher.jar
and the extension jar files. Or
you might decide to point the codebase to the server which hosts
the applet launcher and specify all of the other resources,
including your applet, with absolute URLs. Or you might decide to
use all absolute URLs in your archive tag with no codebase. The
techniques are basically equivalent. We recommend either pointing
the codebase to the directory containing your applet's jars, using
relative URLs for your applet, and using absolute URLs for all
other resources; or using all absolute URLs.
Alternatively, you can re-host the jar files and/or JNLP files and nativelib jars for the extensions you use on your own web server. This has the advantage that your applet will connect to fewer web servers upon startup, but has the disadvantages of requiring additional maintenance on your part and not automatically receiving updates to the extensions when they are published.
Note that if you are planning to call into your applet from JavaScript that there are some scripting-related caveats that you need to be aware of.
The jnlpExtension
parameters passed to the
JNLPAppletLauncher must be specified with absolute URLs.
The examples show how to use the JNLPAppletLauncher in a few different scenarios.
This applet parameter was not well documented until recently, but it disables certain legacy behavior of the Java Plug-In. Before the introduction of jar files, applets used to host their class files and resources as flat files on the web server. Once jar files were introduced, it was possible to improve the efficiency of resource loading for applets, but (apparently) not without breaking compatibility. An applet can specify the parameter
<param name="codebase_lookup" value="false">
to improve efficiency of its loading if it does not rely on fetching flat files from the web server off the codebase. We recommend setting this parameter.
Applets using the OpenGL 3D graphics API, for example through JOGL or Java 3D, may encounter robustness issues on the Windows platform because Sun's Java 2D implementation on Windows uses Microsoft's DirectDraw API. DirectDraw and OpenGL are incompatible at the driver level.
As a workaround for this problem, the JNLPAppletLauncher supports disabling the use of DirectDraw. Currently this can only be done on a global basis, for all applets, but doing so is unlikely to slow down other non-3D applets significantly.
Specifying the applet parameter
<param name="noddraw.check" value="true">
will cause the applet launcher, when run on Windows, to check to see whether DirectDraw is enabled and, if so, will prompt the user with a dialog box asking to disable it. A browser restart is required if the setting is changed.
If the dialog box is undesirable in a given situation, you can force the noddraw check to always disable DirectDraw with the two applet parameters:
<param name="noddraw.check" value="true"> <param name="noddraw.check.silent" value="true">
In this case it will not be obvious to the end user that a browser restart might be required for best robustness, but you could potentially document the need to try restarting the browser in case of instability.
The JNLPAppletLauncher supports interaction with the sub-applet via
the getSubApplet()
method. Calling this method from
JavaScript will return the subordinate applet with which you can
then interact via JavaScript.
There are currently some scripting-related caveats associated with pulling jar files from multiple locations for a particular applet. In particular, it appears that the LiveConnect security model on Mac OS X in the Safari browser prohibits JavaScript from one domain from communicating with Java code (such as an applet) downloaded from another domain. This is correct according to older versions of the LiveConnect specification, although some more recent implementations of LiveConnect allow this, restricting the privileges of such calls in other ways.
The workaround for this problem seems to be to host the
applet-launcher.jar
on your web site if you need to
talk to your applet from JavaScript. Your applet's jars will likely
also need to be hosted from the same web server. If you talk to
extension APIs in your archive
tag directly from
JavaScript, you may find it necessary to host those jars on your
web server as well.
From a practical standpoint, most applet developers using
JavaScript with the JNLPAppletLauncher will only need to re-host at
most applet-launcher.jar
on their web site.
An applet using JOGL as an extension. Note that this example does
not specify a codebase, instead specifying all of its archive tag
elements with absolute URLs (split here for readability; in a real
applet tag they must be all on one line). Note also the use of the
noddraw.check
parameter to disable the use of
DirectDraw since using JOGL implies the use of OpenGL.
<applet code="org.jdesktop.applet.util.JNLPAppletLauncher" width=600 height=400 archive="http://download.java.net/media/applet-launcher/applet-launcher.jar, http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar, http://download.java.net/media/gluegen/webstart/gluegen-rt.jar, http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl-demos.jar"> <param name="codebase_lookup" value="false"> <param name="subapplet.classname" value="demos.applets.GearsApplet"> <param name="subapplet.displayname" value="JOGL Gears Applet"> <param name="noddraw.check" value="true"> <param name="progressbar" value="true"> <param name="jnlpNumExtensions" value="1"> <param name="jnlpExtension1" value="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp"> </applet>
An applet using both JOGL and JOAL as extensions. Note again that
all code resources are specified with absolute URLs. In this
example the unsigned applet pulls in code from both
jogl-demos.jar
and joal-demos.jar
. Note
again the use of the noddraw.check
parameter.
<applet code="org.jdesktop.applet.util.JNLPAppletLauncher" width=600 height=400 archive="http://download.java.net/media/applet-launcher/applet-launcher.jar, http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar, http://download.java.net/media/gluegen/webstart/gluegen-rt.jar, http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl-demos.jar, http://download.java.net/media/joal/webstart/joal.jar, http://download.java.net/media/joal/webstart/joal-demos.jar"> <param name="codebase_lookup" value="false"> <param name="subapplet.classname" VALUE="demos.applets.GearsJOALApplet"> <param name="subapplet.displayname" VALUE="JOGL / JOAL Gears Applet"> <param name="noddraw.check" value="true"> <param name="progressbar" value="true"> <param name="jnlpNumExtensions" value="2"> <param name="jnlpExtension1" value="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp"> <param name="jnlpExtension2" value="http://download.java.net/media/joal/webstart/joal.jnlp"> </applet>
An applet using Java 3D as an extension:
<applet code="org.jdesktop.applet.util.JNLPAppletLauncher" width=400 height=300 archive="myapplet.jar, http://download.java.net/media/applet-launcher/applet-launcher.jar, http://download.java.net/media/java3d/webstart/release/j3d/latest/j3dcore.jar, http://download.java.net/media/java3d/webstart/release/j3d/latest/j3dutils.jar, http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar, http://download.java.net/media/gluegen/webstart/gluegen-rt.jar, http://download.java.net/media/java3d/webstart/release/vecmath/latest/vecmath.jar"> <param name="codebase_lookup" value="false"> <param name="subapplet.classname" value="mypkg.MyApplet"> <param name="subapplet.displayname" value="My Java 3D Applet"> <param name="jnlpNumExtensions" value="1"> <param name="jnlpExtension1" value="http://download.java.net/media/java3d/webstart/release/java3d-latest.jnlp"> <param name="progressbar" value="true"> <param name="noddraw.check" value="true"> </applet>
Note that the JOGL jar files are also included in this example. This is necessary in order to run on Mac OS X, for which Java 3D always uses JOGL to render.
This section describes how to set up the archive
and
jnlpExtension
parameters for a few standard
extensions.
The master jar file for the JNLPAppletLauncher is located at the following URL:
http://download.java.net/media/applet-launcher/applet-launcher.jar
This jar needs to be added to your archive parameter.
Java 3D 1.5.1 and later supports the JNLPAppletLauncher. You will need to add the following URLs to your archive parameter:
http://download.java.net/media/java3d/webstart/release/j3d/latest/j3dcore.jar http://download.java.net/media/java3d/webstart/release/j3d/latest/j3dutils.jar http://download.java.net/media/java3d/webstart/release/vecmath/latest/vecmath.jarThen add the following to one of your
jnlpExtension
parameters:
http://download.java.net/media/java3d/webstart/release/java3d-latest.jnlpIf you want to deploy your applet on Mac OS X, you will also need to include JOGL by adding the following URLs to your archive parameter:
http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar http://download.java.net/media/gluegen/webstart/gluegen-rt.jarNote that this will only work if Java 3D is not installed into the JRE as an extension. Since Apple ships their JRE with Java 3D pre-installed, the end-user must uninstall Java 3D in order for Java 3D applets to work on Mac.
Note that the Java 3D .jnlp extension will automatically pull in the native code associated with JOGL and the GlueGen runtime, so you don't have to separately refer to those .jnlp files.
JOGL 1.1.1-rc3 and later support the JNLPAppletLauncher. You will need to add the following URL to your archive parameter:
http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar
Because JOGL depends on the GlueGen runtime, you will also need to add the following URL to your archive parameter:
http://download.java.net/media/gluegen/webstart/gluegen-rt.jar
Finally, add the following to one of your
jnlpExtension
parameters:
http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp
Note that the jogl.jnlp extension will automatically pull in the native code associated with the GlueGen runtime, so you don't have to separately refer to the gluegen-rt.jnlp file.
JOAL 1.1.1 and later support the JNLPAppletLauncher. You will need to add the following URL to your archive parameter:
http://download.java.net/media/joal/webstart/joal.jar
Because JOAL, like JOGL, depends on the GlueGen runtime, you will also need to add the following URL to your archive parameter:
http://download.java.net/media/gluegen/webstart/gluegen-rt.jar
(If you are using both JOGL and JOAL, you only need to refer to gluegen-rt.jar once in your archive parameter.)
Finally, add the following to one of your
jnlpExtension
parameters:
http://download.java.net/media/joal/webstart/joal.jnlp
Note that the joal.jnlp extension will automatically pull in the native code associated with the GlueGen runtime, so you don't have to separately refer to the gluegen-rt.jnlp file.
If you are the author of an extension like JOGL which requires some native code, with only a simple code change you can make your extension work with the JNLPAppletLauncher. Simply add the following method somewhere in your code:
private static void loadLibraryInternal(String libraryName) { String sunAppletLauncher = System.getProperty("sun.jnlp.applet.launcher"); boolean usingJNLPAppletLauncher = Boolean.valueOf(sunAppletLauncher).booleanValue(); boolean loaded = false; if (usingJNLPAppletLauncher) { try { Class jnlpAppletLauncherClass = Class.forName("org.jdesktop.applet.util.JNLPAppletLauncher"); Method jnlpLoadLibraryMethod = jnlpAppletLauncherClass.getDeclaredMethod("loadLibrary", new Class[] { String.class }); jnlpLoadLibraryMethod.invoke(null, new Object[] { libraryName }); loaded = true; } catch (ClassNotFoundException ex) { System.err.println("loadLibrary(" + libName + ")"); System.err.println(ex); System.err.println("Attempting to use System.loadLibrary instead"); } catch (Exception e) { Throwable t = e; if (t instanceof InvocationTargetException) { t = ((InvocationTargetException) t).getTargetException(); } if (t instanceof Error) throw (Error) t; if (t instanceof RuntimeException) { throw (RuntimeException) t; } // Throw UnsatisfiedLinkError for best compatibility with System.loadLibrary() throw (UnsatisfiedLinkError) new UnsatisfiedLinkError().initCause(e); } } if (!loaded) { System.loadLibrary(libraryName); } }
and wherever you would call System.loadLibrary()
(from
within an AccessController.doPrivileged()
block) to
load your extension's native code, call the above
loadLibraryInternal
method instead.
Note again that because the applet-launcher.jar
and
the nativelib jars for all extensions must currently be signed with
the same certificate, this implies that you must resign both the
applet launcher as well as any other extensions your applet relies
on (unless yours is a Sun-standard extension and can be signed with
Sun's code signing certificate).
The JNLPAppletLauncher was developed by Kevin Rushforth, Kenneth Russell, and Chien Yang. It is based on the earlier JOGLAppletLauncher developed by Lilian Chamontin.