NASA World Wind Java Applets

Last modified January 21, 2009

Introduction

This document describes how to assemble and deploy a World Wind Java applet. It includes instructions for using the new and preferred Next Generation Java Plugin (see Release Notes for the Next Generation Java Plug-In Technology) , and the previous method using Sun's JNLPAppletLauncher.

The Next Generation Java Plugin is available with Java 6_10 and later. We strongly suggest that you use the plugin rather than the applet launcher. It resolves many problems people have encountered when using the applet launcher, and it enables much more flexible control of the applet's run-time environment. Unfortunately, as of January 2009 the plugin is not yet supported on Apple OS X.

Requirements

As for the World Wind Java project in general, please check the following points :

JOGL applet setup (without World Wind) can be tested with this sample Gears 3D JOGL animation applet:
https://jogl-demos.dev.java.net/applettest.html. It's a good idea to perform this test prior to deploying the World Wind applet because it will identify any problems the computer has using JOGL alone.

Compiling and running a WWJ applet

To deploy a WWJ applet you need a web page with the proper html declarations, the World Wind Java archive worldwind.jar, and possibly your special implementation of one of the applet templates in its own archive, eg. myapplet.jar. When using the Next Generation Plugin, you also need a .jnlp file.

    myapplet.html          Web page that loads the applet
    myapplet.jnlp          Used with the Next Generation Plugin
    myapplet.jar           Optional applet class in its own archive
    worldwind.jar          World Wind Java SDK, including applet templates

Using either the Next Generation Plugin or the JNLPAppletLauncher all other needed components can be retrieved from external servers: the launcher itself applet-laucher.jar (not needed if you're using the Next Generation Plugin), and the JOGL librairies jogl.jar and gluegen-rt.jar. The appropriate binaries will be downloaded and cached according to the client platform by the launcher.

To compile and deploy a WW applet, follow these steps:

  1. Use one of the World Wind applet templates from the SDK (see code sample below).
  2. Compile and export worldwind.jar and, if needed, a separate jar for the applet.
  3. Sign all jars (see Signing below).
  4. Copy the jar(s) to your deployement folder.
  5. Run with a web page using the Next Generation Plugin (see below) or the JNLPAppletLauncher (see below).

The World Wind Java SDK comes with a build.xml file containing various ant targets to compile, release and zip different parts of the SDK. The applet.release target will do all the work and place all needed files in the applet.release folder along with example html pages.

To use a custom World Wind configuration file in your applet, place within a static block of your applet code to set the Java property that indicates the configuration file's location and name. The code must run before any World Wind method or constructor is invoked. The property is gov.nasa.worldwind.config.file (see code sample below). The path must be relative to the applet's classpath, and the configuration file must be included in the applet's signed jar file. World Wind opens the file via java.lang.Class.getResourceAsStream().

Using the Next Generation Plugin

Launching an applet with the Next Generation Plugin requires a .jnlp file. Here's the HTML to use for the WWJApplet example:

 <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://my.web.server.com/WWJApplet/worldwind.jar">
               http://my.web.server.com/WWJApplet/myapplet.jar">
   <param name="jnlp_href" value="WWJApplet.jnlp"> <!-- Picked up by new plugin -->
   <param name="codebase_lookup" value="false">
   <param name="subapplet.classname" value="gov.nasa.worldwind.examples.applet.WWJApplet">
   <param name="subapplet.displayname" value="World Wind 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>

The corresponding WWJApplet.jnlp file:

    <?xml version="1.0" encoding="UTF-8"?>
    
       <jnlp href="WWJApplet.jnlp">
        <information>
            <title>World Wind Java Applet Demo</title>
            <vendor>NASA</vendor>
            <homepage href="http://worldwind.arc.nasa.gov"/>
            <description>World Wind Java Applet Demo</description>
            <description kind="short">World Wind Java Applet Demo</description>
            <offline-allowed/>
        </information>
        <security>
            <all-permissions/>
        </security>
         <resources os="Windows">
           <property name="sun.java2d.noddraw" value="true"/>
         </resources>
         <resources>
            <j2se href="http://java.sun.com/products/autodl/j2se" version="1.5+" initial-heap-size="512m"
                  max-heap-size="512m"/>
            <property name="sun.java2d.noddraw" value="true"/>
            <jar href="WWJApplet.jar" main="true"/>
            <jar href="worldwind.jar"/>
            <extension name="jogl"
                       href="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp"/>
         </resources>
         <!-- Width and heigth are overwritten by the surrounding web page -->
         <applet-desc
             name="WWJ Applet"
             main-class="gov.nasa.worldwind.examples.applet.WWJApplet"
             width="800" height="600">
            <param name="separate_jvm" value="true" />
         </applet-desc>
       </jnlp>

The Next Generation Plugin allows considerable flexibility in defining the applet context. For instance, a minimal JRE version can be specified along with initial heap memory size (Java 5 and 512M in the above example). A parameter can also direct the plugin to use a different JVM for each applet instance (param separate_jvm< above). World Wind applets should always set this parameter and set its value to true.

As of January 2009 the Next Generation Plugin works with Internet Explorer 6 and 7 on Windows XP or Vista, Firefox 3 on Windows, Solaris and Linux. You can read the new plugin release notes at Release Notes for the Next Generation Java Plug-In Technology.

Current Java Download: Download Java

Using JNLPAppletLauncher

Below is the HTML code necessary to run the sample WWJApplet from the SDK applet package. Note that all achives are referenced with absolute urls to Sun's servers except the worldwind.jar that is located on another server - probably with this web page, but it could be anywhere.

"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://my.web.server.com/WWJApplet/worldwind.jar">
   <param name="codebase_lookup" value="false">
   <param name="subapplet.classname" value="gov.nasa.worldwind.examples.applet.WWJApplet">
   <param name="subapplet.displayname" value="World Wind 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>

If the applet code is in a separate archive, place a reference to that archive in the archive attribute of the applet, and specify the proper path in the subapplet.classname 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://my.web.server.com/WWJApplet/worldwind.jar,
               http://my.web.server.com/WWJApplet/myapplet.jar">
   <param name="codebase_lookup" value="false">
   <param name="subapplet.classname" value="domain.your.path.myApplet">
...
 </applet>

Ref : https://applet-launcher.dev.java.net/

Code samples

WWJ Applet minimal class template

import gov.nasa.worldwind.examples.StatusBar;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.layers.*;
import gov.nasa.worldwind.awt.*;

import javax.swing.*;
import java.awt.*;

public class WWJApplet extends JApplet
{
    private WorldWindowGLCanvas wwd;
    private StatusBar statusBar;

    public WWJApplet()
    {
    }

    public void init()
    {
        try
        {
            // Create World Window GL Canvas
            this.wwd = new WorldWindowGLCanvas();
            this.getContentPane().add(this.wwd, BorderLayout.CENTER);

            // Create the default model as described in the current worldwind properties.
            Model m = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME);
            this.wwd.setModel(m);

            // Add the status bar
            this.statusBar = new StatusBar();
            this.getContentPane().add(statusBar, BorderLayout.PAGE_END);

            // Forward events to the status bar to provide the cursor position info.
            this.statusBar.setEventSource(this.wwd);

        }
        catch (Throwable e)
        {
            e.printStackTrace();
        }
    }

    public void stop()
    {
        // Shutdown World Wind
        WorldWind.shutDown();
    }
}

If the applet uses a custom World Wind configuration file, the following would be added to the WWJApplet class above:

static { System.setProperty("gov.nasa.worldwind.config.file", "config/myWorldWindConfiguration.properties"); }

This property must be set prior to any other World Wind method invocation or object construction. In this example, the properties file would be contained at the above path within the applet's jar file.

Preloading a blue marble base image from the 'images' SDK folder

When a wwj applet is started the first time with an empty cache, the globe will not show until the level zero tiles of blue marble are downloaded. To avoid this delay and an initial display of a blank globe, add in the layer list, before 'blue marble' a full sphere SurfaceImage of a low resolution whole earth blue marble image, which is embedded in the worldwind jar and thus preloaded with the applet.

In the applet init()

            // Add a BMNG base layer to the model layer list, before the Blue Marble
            insertBeforeLayerName(this.wwd, new BMNGOneImage(), "Blue Marble");

Additional methods

    public static void insertBeforeLayerName(WorldWindow wwd, Layer layer, String targetName)
    {
        // Insert the layer into the layer list just before the target layer.
        int targetPosition = 0;
        LayerList layers = wwd.getModel().getLayers();
        for (Layer l : layers)
        {
            if (l.getName().indexOf(targetName) != -1)
            {
                targetPosition = layers.indexOf(l);
                break;
            }
        }
        layers.add(targetPosition, layer);
    }

Applet vs object tag

Note : the applet tag is considered deprecated in favor of the object tag :

DEPRECATED EXAMPLE:
The following sample Java applet:

<APPLET code="AudioItem" width="15" height="15">
   <PARAM name="snd" value="Hello.au|Welcome.au">
   Java applet that plays a welcoming sound.
</APPLET>

may be rewritten as follows with OBJECT:

<OBJECT codetype="application/java"
        classid="AudioItem"
        width="15" height="15">
   <PARAM name="snd" value="Hello.au|Welcome.au">
   Java applet that plays a welcoming sound.
</OBJECT>

Ref: HTML 4.01 Specifications, December 1999 : Applet
http://www.w3.org/TR/1999/REC-html401-19991224/struct/objects.html#h-13.4

Communication between the web page and the applet

Passing parameters to the applet

Initial values can be passed to the applet using the param tag of the applet or oject tags:

  <param name="paramName" value="some value">

From the applet class a parameter value can be retreived with the getParameter() method:

  String paramValue = getParameter("paramName");

Javascript to the applet

To allow javascript to 'talk' to the applet, first add an id attribute to the applet tag :

    <applet
         id="wwjApplet"
         code="org.jdesktop.applet.util.JNLPAppletLauncher"
         width=600
         height=400
    ... >

To call an applet java method from javascript :

  // Call someAppletMethod() via the launcher getSubApplet() method

  document.getElementById('wwjApplet').getSubApplet().someAppletMethod();

Note the use of the launcher getSubApplet() method to get at the applet itself. Javascript is really calling the launcher.

Important note for Mac : for javascript to be able to 'talk' to the applet, the applet-launcher.jar must be hosted on the same server as the applet. This means that if you need to have javascript/applet interaction across plateforms, you need to host a copy of applet-launcher.jar and keep it up to date.

When using the Next Generation Plugin, javascript will be able to access the applet directly without going through the applet launcher. For backward compatibility it is recommended to use the below code when accessing the applet:

    var theApplet = null;

    function getWWJApplet()
    {
       if (theApplet == null) {
          theApplet = document.getElementById('wwjApplet');
       }
       // See if we're using the old Java Plug-In and the JNLPAppletLauncher
       try {
          theApplet = theApplet.getSubApplet();
       } catch (e) {
          // Using new-style applet -- ignore
       }
    return theApplet;
    }

    // Call someAppletMethod() via the getWWJApplet() method

    getWWJApplet().someAppletMethod();

Ref: Java Plugin Guide : JavaScript to Java Communication (Scripting)
http://java.sun.com/j2se/1.5.0/docs/guide/plugin/developer_guide/js_java.html

Applet to javascript and the document object

To allow the applet to access javascript or the document object, add the mayscript attribute to the applet tag :

    <applet
         mayscript
         code="org.jdesktop.applet.util.JNLPAppletLauncher"
         width=600
         height=400
    ... >

To perform a call to javascript from the applet class use JSObject.getWindow():

  import netscape.javascript.*;
  ...

  JSObject win = JSObject.getWindow(this);
  win.call("functionName", null);  // calls javascript functionName()

  or

  win.eval("alert('An alert message')"); // evaluates and executes some javascript code as a string

Ref: Java Plugin Guide : Java-to-Javascript Communication
http://java.sun.com/j2se/1.5.0/docs/guide/plugin/developer_guide/java_js.html

Signing archive files

To sign your archive files, you need to use keytool and jarsigner from your JDK bin folder.

Assuming the path to keytool and jarsigner is in the PATH environment variable.

Create a certificate (once):

.../WWJ Applet>keytool -genkey -keyalg rsa -alias yourname

Enter pw : ******

.../WWJ Applet>keytool -export -alias yourname -file yourname.crt

Signing a jar :

.../WWJ Applet>jarsigner worldwind.jar yourname

Enter pw : ******

Note : this example creates the certificate in the same folder as the applet. This is not necessary.

Ref: How to Sign Applets Using RSA-Signed Certificates
http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/rsa_signing.html

Security Policy

This code bit may be usefull in some situations.

        Policy.setPolicy(new Policy() {
            public void refresh() {
            }

            public PermissionCollection getPermissions(CodeSource arg0) {
                Permissions perms = new Permissions();
                perms.add(new AllPermission());
                return (perms);
            }
        });

Known issues

We've received reports of the following issues occuring occassionaly

First use :

After navigating to other pages and coming back

Note: Memory leaks have been reported when launching several applets in different tabs or when reloading the same applet page. Most of these issues have been solved with the Next Generation Pugin available since Java 6_10.

WWJ Applet examples

IGE, France
http://www.ige.fr/3d/WW/WWJ.php

Pred, France
http://atpred.free.fr/applet.html

GIS Solution, Italy
http://www.gis-solution.com/WWApplet/WWApplet.htm

Document history

July 2007 - Patrick Murris
First version

January 2009 - Patrick Murris
Updated for Next Generation Plugin