diff options
author | Kenneth Russel <[email protected]> | 2007-07-04 20:17:41 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2007-07-04 20:17:41 +0000 |
commit | 0efbb04ee61d88c717c6aef85d07a289b0a3b22f (patch) | |
tree | e850d834d583864e0cf15122071b2b746a1ec5d9 | |
parent | dbaf3a158787fb183c669a68921b2bf7e336e107 (diff) |
Wrote documentation for applet launcher and copied to front page.
Includes discussion about support for absolute URLs in archive tag
(important to increase code sharing) and provides Java 3D, JOGL and
JOAL-based examples. Added noddraw.check and noddraw.check.silent
support.
-rw-r--r-- | README-build.html | 6 | ||||
-rw-r--r-- | src/org/jdesktop/applet/util/JNLPAppletLauncher.java | 579 | ||||
-rw-r--r-- | www/index.html | 408 |
3 files changed, 952 insertions, 41 deletions
diff --git a/README-build.html b/README-build.html index 9919a4f..27a6741 100644 --- a/README-build.html +++ b/README-build.html @@ -41,8 +41,8 @@ * intended for use in the design, construction, operation or * maintenance of any nuclear facility. * -* $Revision: 1.1 $ -* $Date: 2007/06/19 20:00:29 $ +* $Revision: 1.2 $ +* $Date: 2007/07/04 20:17:41 $ * $State: Exp $ */ --> @@ -83,7 +83,7 @@ as follows:</p> <ul> - <li>JDK 5 or later</li> + <li>JDK 1.4.2 or later</li> <li>Apache Ant 1.6.5 or later</li> diff --git a/src/org/jdesktop/applet/util/JNLPAppletLauncher.java b/src/org/jdesktop/applet/util/JNLPAppletLauncher.java index f6d31d0..4032724 100644 --- a/src/org/jdesktop/applet/util/JNLPAppletLauncher.java +++ b/src/org/jdesktop/applet/util/JNLPAppletLauncher.java @@ -37,8 +37,8 @@ * intended for use in the design, construction, operation or * maintenance of any nuclear facility. * - * $Revision: 1.6 $ - * $Date: 2007/06/28 22:08:03 $ + * $Revision: 1.7 $ + * $Date: 2007/07/04 20:17:42 $ * $State: Exp $ */ @@ -53,6 +53,7 @@ import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; @@ -76,12 +77,14 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Properties; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Logger; import javax.swing.ImageIcon; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; @@ -93,48 +96,199 @@ import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** - * General purpose JNLP-based AppletLauncher class for deploying applets that use - * extension libraries containing native code. It is based on JOGLAppletLauncher, - * but uses an extension's .jnlp file to locate the native resources, so that - * for a given extension, the application developer only needs to host the - * platform-independent .jar files containing the .class files. The - * platform-specific native .jar files are downloaded automatically from the same - * server that hosts the extension web start binaries. + * 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 <code><applet></code> tag, on Java SE + * versions as far back as 1.4.2. * * <p> - * Extensions that currently plan to support JNLPAppletLauncher include: - * Java 3D, JOAL, and JOGL. More could be added later without needing to modify - * JNLPAppletLauncher. * + * 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. + * + * <p> + * + * 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 <a + * href="#MODIFYING">modifying extensions to work with the + * JNLPAppletLauncher</a>. + * + * <h2> How to Deploy Applets Using the JNLPAppletLauncher </h2> * <p> - * The applet-launcher jar file containing the JNLPAppletLauncher class must be - * signed with the same certificate as the extension's native resources, typically - * "sun microsystems, inc.". The user will receive a ssecurity 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 <code>applet-launcher.jar</code> 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). * * <p> + * * 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 (in this case, "your_applet.jar"). + * the <code>archive</code> parameter to the applet tag must contain + * <code>applet-laucher.jar</code>, the extension .jar files, and any + * jar files associated with your applet. See the section on <a + * href="#ORGANIZING">organizing jar files</a> for more details. + * + * <p> + * + * Second, the name of your applet's main class and a textual + * description must be specified via the applet tag parameters + * <code>subapplet.classname</code> and + * <code>subapplet.displayname</code>. + * + * <p> + * + * Finally, the URLs for the extension .jnlp files being used must be + * specified as parameters. The <code>jnlpNumExtensions</code> + * parameter indicates the number of JNLP files that are referenced, + * and for <code>n</code> such files, their URLs are passed in as + * parameters <code>jnlpExtension1</code> ... + * <code>jnlpExtension[n]</code>. + * + * <h2><a name="ORGANIZING">Organizing Jar Files</a></h2> * * <p> - * Second, the codebase directory on the server, which contains the - * applet's jar files, must also contain applet-laucher.jar and all of - * the extension .jar files - * files from the standard extension's runtime distributions - * (TBD). + * + * 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 <a + * href="http://java.sun.com/j2se/1.4.2/docs/guide/misc/applet.html">applet + * tag</a>. * * <p> - * TODO: List the Java 3D, JOGL, and JOAL jar files here. + * + * 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 <a + * href="http://java.sun.com/sfaq/">Applet Security FAQ</a> for more + * details.) * * <p> - * Sample applet code: + * + * 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. + * + * <p> + * + * 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.) + * + * <p> + * + * 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 + * <code>applet-launcher.jar</code> 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. + * + * <p> + * + * 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. + * + * <p> + * + * The <code>jnlpExtension</code> parameters passed to the + * JNLPAppletLauncher must be specified with absolute URLs. + * + * <p> + * + * The <a href="#EXAMPLES">examples</a> show how to use the + * JNLPAppletLauncher in a few different scenarios. + * + * <h2>Applets using the OpenGL(r) 3D API</h2> + * + * 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. + * + * <p> + * + * 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. + * + * <p> + * + * Specifying the applet parameter + * + * <pre> + * <param name="noddraw.check" value="true"> + * </pre> + * + * 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. + * + * <p> + * + * 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: + * + * <pre> + * <param name="noddraw.check" value="true"> + * <param name="noddraw.check.silent" value="true"> + * </pre> + * + * 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. + * + * <h2><a name="EXAMPLES">Examples</a></h2> + * + * <p> + * + * An applet using Java 3D as an extension: + * * <pre> * <applet code="org.jdesktop.applet.util.JNLPAppletLauncher" * width=640 @@ -149,12 +303,224 @@ import org.xml.sax.helpers.DefaultHandler; * <param name="progressbar" value="true"> * </applet> * </pre> + * + * <p> + * + * 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. Note also the use of the + * <code>noddraw.check</code> parameter to disable the use of + * DirectDraw since using JOGL implies the use of OpenGL. + * + * <pre> + * <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="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> + * </pre> + * + * <p> + * + * 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 + * <code>jogl-demos.jar</code> and <code>joal-demos.jar</code>. Note + * again the use of the <code>noddraw.check</code> parameter. + * + * <pre> + * <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="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> + * </pre> + * + * <h2> Locations of Standard Extensions </h2> * - * TODO: Finish this, borrowing from JOGLAppletLauncher where needed. + * <p> + * + * This section describes how to set up the <code>archive</code> and + * <code>jnlpExtension</code> parameters for a few standard + * extensions. + * + * <h3>JNLPAppletLauncher</h3> + * + * The master jar file for the JNLPAppletLauncher is located at the following URL: + * <pre> + * http://download.java.net/media/applet-launcher/applet-launcher.jar + * </pre> + * + * This jar needs to be added to your archive parameter. + * + * <h3>Java 3D</h3> + * + * The early access release of Java 3D 1.5.1 and later support the + * JNLPAppletLauncher. You will need to add the following URLs to your + * archive parameter: + * + * <pre> + * http://download.java.net/media/java3d/webstart/early-access/j3d/1.5.1/j3dcore.jar + * http://download.java.net/media/java3d/webstart/early-access/j3d/1.5.1/j3dutils.jar + * http://download.java.net/media/java3d/webstart/early-access/vecmath/1.5.1/vecmath.jar + * </pre> + * + * and refer to the following in one of your <code>jnlpExtension</code> parameters: + * + * <pre> + * http://download.java.net/media/java3d/webstart/early-access/java3d-1.5.1-exp.jnlp + * </pre> + * + * <h3>JOGL</h3> + * + * JOGL 1.1.1-rc3 and later support the JNLPAppletLauncher. You will + * need to add the following URL to your archive parameter: + * + * <pre> + * http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar + * </pre> + * + * Because JOGL depends on the GlueGen runtime, you will also need to + * add the following URL to your archive parameter: + * + * <pre> + * http://download.java.net/media/gluegen/webstart/gluegen-rt.jar + * </pre> + * + * Finally, add the following to one of your + * <code>jnlpExtension</code> parameters: + * + * <pre> + * http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp + * </pre> + * + * 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. + * + * <h3>JOAL</h3> + * + * JOAL 1.1.1 and later support the JNLPAppletLauncher. You will need + * to add the following URL to your archive parameter: + * + * <pre> + * http://download.java.net/media/joal/webstart/joal.jar + * </pre> + * + * Because JOAL, like JOGL, depends on the GlueGen runtime, you will + * also need to add the following URL to your archive parameter: + * + * <pre> + * http://download.java.net/media/gluegen/webstart/gluegen-rt.jar + * </pre> + * + * (If you are using both JOGL and JOAL, you only need to refer to + * gluegen-rt.jar once in your archive parameter.) + * + * <p> + * + * Finally, add the following to one of your + * <code>jnlpExtension</code> parameters: + * + * <pre> + * http://download.java.net/media/joal/webstart/joal.jnlp + * </pre> + * + * 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. + * + * <h2><a name="MODIFYING">Modifying Your Extension To Work With The JNLPAppletLauncher</a></h2> + * + * <p> + * + * 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: + * + * <pre> + * private static void loadLibraryInternal(String libraryName) { + * String sunAppletLauncher = System.getProperty("sun.jnlp.applet.launcher"); + * boolean usingJNLPAppletLauncher = + * Boolean.valueOf(sunAppletLauncher).booleanValue(); + * 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 }); + * } catch (Exception e) { + * throw new RuntimeException(e); + * } + * } else { + * System.loadLibrary(libraryName); + * } + * } + * </pre> + * + * and wherever you would call <code>System.loadLibrary()</code> (from + * within an <code>AccessController.doPrivileged()</code> block) to + * load your extension's native code, call the above + * <code>loadLibraryInternal</code> method instead. + * + * <p> + * + * Note again that because the <code>applet-launcher.jar</code> 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). + * + * <h2>Acknowledgments</h2> + * + * The JNLPAppletLauncher was developed by Kevin Rushforth, Kenneth + * Russell, and Chien Yang. It is based on the former + * JOGLAppletLauncher developed by Lilian Chamontin. */ public class JNLPAppletLauncher extends Applet { + private static void loadLibraryInternal(String libraryName) { + String sunAppletLauncher = System.getProperty("sun.jnlp.applet.launcher"); + boolean usingJNLPAppletLauncher = + Boolean.valueOf(sunAppletLauncher).booleanValue(); + + 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 }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + System.loadLibrary(libraryName); + } + } + private static final boolean VERBOSE = false; private static final boolean DEBUG = true; @@ -182,6 +548,11 @@ public class JNLPAppletLauncher extends Applet { // Panel that will hold the splash-screen image and progress bar while loading private JPanel loaderPanel; + // Helpers for updating deployment.properties with -Dsun.java2d.noddraw=true + private static final String JRE_PREFIX = "deployment.javapi.jre."; + private static final String NODDRAW_PROP = "-Dsun.java2d.noddraw=true"; + private static final String DONT_ASK = ".dont_ask"; + // Optional progress bar private JProgressBar progressBar; @@ -404,7 +775,7 @@ public class JNLPAppletLauncher extends Applet { startupThread.setPriority(Thread.NORM_PRIORITY - 1); startupThread.start(); } else if (appletStarted) { - // TODO: checkNoDDrawAndUpdateDeploymentProperties(); + checkNoDDrawAndUpdateDeploymentProperties(); // We have to start again the applet (start can be called multiple times, // e.g once per tabbed browsing @@ -1370,7 +1741,7 @@ public class JNLPAppletLauncher extends Applet { subApplet.init(); remove(loaderPanel); validate(); - // TODO: checkNoDDrawAndUpdateDeploymentProperties(); + checkNoDDrawAndUpdateDeploymentProperties(); subApplet.start(); appletStarted = true; } catch (Exception ex) { @@ -1848,4 +2219,144 @@ public class JNLPAppletLauncher extends Applet { } } + //---------------------------------------------------------------------- + // Helper routines for adding + + // Get a "boolean" parameter + private boolean getBooleanParameter(String parameterName) { + return Boolean.valueOf(getParameter(parameterName)).booleanValue(); + } + + private void checkNoDDrawAndUpdateDeploymentProperties() { + if (!getBooleanParameter("noddraw.check")) + return; + if (System.getProperty("os.name").toLowerCase().startsWith("windows") && + !"true".equalsIgnoreCase(System.getProperty("sun.java2d.noddraw"))) { + if (!SwingUtilities.isEventDispatchThread()) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + updateDeploymentPropertiesImpl(); + } + }); + } catch (Exception e) { + } + } else { + updateDeploymentPropertiesImpl(); + } + } + } + + private void updateDeploymentPropertiesImpl() { + String userHome = System.getProperty("user.home"); + File dontAskFile = new File(userHome + File.separator + ".jnlp-applet" + + File.separator + DONT_ASK); + if (dontAskFile.exists()) + return; // User asked us not to prompt again + + int option = 0; + + if (!getBooleanParameter("noddraw.check.silent")) { + option = JOptionPane.showOptionDialog(null, + "For best robustness of OpenGL applets on Windows,\n" + + "we recommend disabling Java2D's use of DirectDraw.\n" + + "This setting will affect all applets, but is unlikely\n" + + "to slow other applets down significantly. May we update\n" + + "your deployment.properties to turn off DirectDraw for\n" + + "applets? You can change this back later if necessary\n" + + "using the Java Control Panel, Java tab, under Java\n" + + "Applet Runtime Settings.", + "Update deployment.properties?", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + new Object[] { + "Yes", + "No", + "No, Don't Ask Again" + }, + "Yes"); + } + + if (option < 0 || + option == 1) + return; // No + + if (option == 2) { + try { + dontAskFile.createNewFile(); + } catch (IOException e) { + } + return; // No, Don't Ask Again + } + + try { + // Must update deployment.properties + File propsDir = new File(System.getProperty("user.home") + File.separator + + "Application Data/Sun/Java/Deployment"); + if (!propsDir.exists()) + // Don't know what's going on or how to set this permanently + return; + + File propsFile = new File(propsDir, "deployment.properties"); + if (!propsFile.exists()) + // Don't know what's going on or how to set this permanently + return; + + Properties props = new Properties(); + InputStream input = new BufferedInputStream(new FileInputStream(propsFile)); + props.load(input); + input.close(); + // Search through the keys looking for JRE versions + Set/*<String>*/ jreVersions = new HashSet/*<String>*/(); + for (Iterator/*<String>*/ iter = props.keySet().iterator(); iter.hasNext(); ) { + String key = (String) iter.next(); + if (key.startsWith(JRE_PREFIX)) { + int idx = key.lastIndexOf("."); + if (idx >= 0 && idx > JRE_PREFIX.length()) { + String jreVersion = key.substring(JRE_PREFIX.length(), idx); + jreVersions.add(jreVersion); + } + } + } + + // Make sure the currently-running JRE shows up in this set to + // avoid repeated displays of the dialog. It might not in some + // upgrade scenarios where there was a pre-existing + // deployment.properties and the new Java Control Panel hasn't + // been run yet. + jreVersions.add(System.getProperty("java.version")); + + // OK, now that we know all JRE versions covered by the + // deployment.properties, check out the args for each and update + // them + for (Iterator/*<String>*/ iter = jreVersions.iterator(); iter.hasNext(); ) { + String version = (String) iter.next(); + String argKey = JRE_PREFIX + version + ".args"; + String argVal = props.getProperty(argKey); + if (argVal == null) { + argVal = NODDRAW_PROP; + } else if (argVal.indexOf(NODDRAW_PROP) < 0) { + argVal = argVal + " " + NODDRAW_PROP; + } + props.setProperty(argKey, argVal); + } + + OutputStream output = new BufferedOutputStream(new FileOutputStream(propsFile)); + props.store(output, null); + output.close(); + + if (!getBooleanParameter("noddraw.check.silent")) { + // Tell user we're done + JOptionPane.showMessageDialog(null, + "For best robustness, we recommend you now exit and\n" + + "restart your web browser. (Note: clicking \"OK\" will\n" + + "not exit your browser.)", + "Browser Restart Recommended", + JOptionPane.INFORMATION_MESSAGE); + } + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/www/index.html b/www/index.html index 67ed10f..35e9726 100644 --- a/www/index.html +++ b/www/index.html @@ -11,12 +11,412 @@ <body style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);"> -<p>Welcome to the home page for the applet-launcher project. This -project contains the JNLPAppletLauncher utility, which...</p> +<h2>Overview</h2> -<h3>Downloads</h3> +<!-- NOTE: to regenerate the text for this web page, copy the class + javadoc for the JNLPAppletLauncher and run an emacs macro over it + to remove the leading " *"s. --> -<p>Coming soon...</p> + 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 <code><applet></code> tag, on Java SE + versions as far back as 1.4.2. + + <p> + + 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. + + <p> + + 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 <a + href="#MODIFYING">modifying extensions to work with the + JNLPAppletLauncher</a>. + + <h2> How to Deploy Applets Using the JNLPAppletLauncher </h2> + <p> + + The <code>applet-launcher.jar</code> 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). + + <p> + + The steps for deploying such applets are straightforward. First, + the <code>archive</code> parameter to the applet tag must contain + <code>applet-laucher.jar</code>, the extension .jar files, and any + jar files associated with your applet. See the section on <a + href="#ORGANIZING">organizing jar files</a> for more details. + + <p> + + Second, the name of your applet's main class and a textual + description must be specified via the applet tag parameters + <code>subapplet.classname</code> and + <code>subapplet.displayname</code>. + + <p> + + Finally, the URLs for the extension .jnlp files being used must be + specified as parameters. The <code>jnlpNumExtensions</code> + parameter indicates the number of JNLP files that are referenced, + and for <code>n</code> such files, their URLs are passed in as + parameters <code>jnlpExtension1</code> ... + <code>jnlpExtension[n]</code>. + + <h2><a name="ORGANIZING">Organizing Jar Files</a></h2> + + <p> + + 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 <a + href="http://java.sun.com/j2se/1.4.2/docs/guide/misc/applet.html">applet + tag</a>. + + <p> + + 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 <a + href="http://java.sun.com/sfaq/">Applet Security FAQ</a> for more + details.) + + <p> + + 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. + + <p> + + 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.) + + <p> + + 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 + <code>applet-launcher.jar</code> 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. + + <p> + + 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. + + <p> + + The <code>jnlpExtension</code> parameters passed to the + JNLPAppletLauncher must be specified with absolute URLs. + + <p> + + The <a href="#EXAMPLES">examples</a> show how to use the + JNLPAppletLauncher in a few different scenarios. + + <h2>Applets using the OpenGL(r) 3D API</h2> + + 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. + + <p> + + 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. + + <p> + + Specifying the applet parameter + + <pre> + <param name="noddraw.check" value="true"> + </pre> + + 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. + + <p> + + 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: + + <pre> + <param name="noddraw.check" value="true"> + <param name="noddraw.check.silent" value="true"> + </pre> + + 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. + + <h2><a name="EXAMPLES">Examples</a></h2> + + <p> + + An applet using Java 3D as an extension: + + <pre> + <applet code="org.jdesktop.applet.util.JNLPAppletLauncher" + width=640 + height=480 + codebase="http://download.java.net/media/java3d/applets/applet-test/" + archive="applet-launcher.jar,j3d-examples.jar,j3dcore.jar,j3dutils.jar,vecmath.jar"> + <param name="subapplet.classname" value="org.jdesktop.j3d.examples.four_by_four.FourByFour"> + <param name="subapplet.displayname" value="Java 3D Four by Four Applet"> + <param name="jnlpNumExtensions" value="1"> + <param name="jnlpExtension1" + value="http://download.java.net/media/java3d/webstart/early-access/java3d-1.5.1-exp.jnlp"> + <param name="progressbar" value="true"> + </applet> + </pre> + + <p> + + 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. Note also the use of the + <code>noddraw.check</code> parameter to disable the use of + DirectDraw since using JOGL implies the use of OpenGL. + + <pre> + <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="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> + </pre> + + <p> + + 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 + <code>jogl-demos.jar</code> and <code>joal-demos.jar</code>. Note + again the use of the <code>noddraw.check</code> parameter. + + <pre> + <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="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> + </pre> + + <h2> Locations of Standard Extensions </h2> + + <p> + + This section describes how to set up the <code>archive</code> and + <code>jnlpExtension</code> parameters for a few standard + extensions. + + <h3>JNLPAppletLauncher</h3> + + The master jar file for the JNLPAppletLauncher is located at the following URL: + <pre> + http://download.java.net/media/applet-launcher/applet-launcher.jar + </pre> + + This jar needs to be added to your archive parameter. + + <h3>Java 3D</h3> + + The early access release of Java 3D 1.5.1 and later support the + JNLPAppletLauncher. You will need to add the following URLs to your + archive parameter: + + <pre> + http://download.java.net/media/java3d/webstart/early-access/j3d/1.5.1/j3dcore.jar + http://download.java.net/media/java3d/webstart/early-access/j3d/1.5.1/j3dutils.jar + http://download.java.net/media/java3d/webstart/early-access/vecmath/1.5.1/vecmath.jar + </pre> + + and refer to the following in one of your <code>jnlpExtension</code> parameters: + + <pre> + http://download.java.net/media/java3d/webstart/early-access/java3d-1.5.1-exp.jnlp + </pre> + + <h3>JOGL</h3> + + JOGL 1.1.1-rc3 and later support the JNLPAppletLauncher. You will + need to add the following URL to your archive parameter: + + <pre> + http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar + </pre> + + Because JOGL depends on the GlueGen runtime, you will also need to + add the following URL to your archive parameter: + + <pre> + http://download.java.net/media/gluegen/webstart/gluegen-rt.jar + </pre> + + Finally, add the following to one of your + <code>jnlpExtension</code> parameters: + + <pre> + http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp + </pre> + + 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. + + <h3>JOAL</h3> + + JOAL 1.1.1 and later support the JNLPAppletLauncher. You will need + to add the following URL to your archive parameter: + + <pre> + http://download.java.net/media/joal/webstart/joal.jar + </pre> + + Because JOAL, like JOGL, depends on the GlueGen runtime, you will + also need to add the following URL to your archive parameter: + + <pre> + http://download.java.net/media/gluegen/webstart/gluegen-rt.jar + </pre> + + (If you are using both JOGL and JOAL, you only need to refer to + gluegen-rt.jar once in your archive parameter.) + + <p> + + Finally, add the following to one of your + <code>jnlpExtension</code> parameters: + + <pre> + http://download.java.net/media/joal/webstart/joal.jnlp + </pre> + + 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. + + <h2><a name="MODIFYING">Modifying Your Extension To Work With The JNLPAppletLauncher</a></h2> + + <p> + + 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: + + <pre> + private static void loadLibraryInternal(String libraryName) { + String sunAppletLauncher = System.getProperty("sun.jnlp.applet.launcher"); + boolean usingJNLPAppletLauncher = + Boolean.valueOf(sunAppletLauncher).booleanValue(); + 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 }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + System.loadLibrary(libraryName); + } + } + </pre> + + and wherever you would call <code>System.loadLibrary()</code> (from + within an <code>AccessController.doPrivileged()</code> block) to + load your extension's native code, call the above + <code>loadLibraryInternal</code> method instead. + + <p> + + Note again that because the <code>applet-launcher.jar</code> 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). + + <h2>Acknowledgments</h2> + + The JNLPAppletLauncher was developed by Kevin Rushforth, Kenneth + Russell, and Chien Yang. It is based on the former + JOGLAppletLauncher developed by Lilian Chamontin. </body> </html> |