Starting Java Applications
from the Web
Write a Java Web Start app that packages JAR and data files, which download automatically at startup with no impact on performance
by James W. Cooper

Dave Barry once mused about the sugary cereal in the picture on TV being "part of a balanced breakfast." He claimed it really means adjacent to a balanced breakfast—the other tempting foods in the picture—and is about as relevant as a can of shaving cream or a dead bat. That's the way I used to feel about Java Web Start technology. It didn't seem important or relevant—it was just this other weird thing on the table.

Now I see it as a little more important. Java Web Start allows you to post complete Java applications and their data on a Web site and run them seamlessly, either from the Web or in stand-alone fashion. If your client computer is connected to the Web, the Web Start system will check automatically for updates, and, if not, it will run independently.

This sounded a little daft to me at one time, but of course there are lots of cases where a Java application is more useful than embedding something messy in a Web site applet. In fact, running Java applications with automatic updates is really the best of both worlds. I finally came to my senses when I had a fairly complicated application involving data handling, graphics, and a large XML data set that I needed to be able to demonstrate to interested users at various locations not nearby my own office. I didn't want or need to travel somewhere just to run a simple demo, but I wanted to make sure that they had the same visual experience on their computer system that I did. In other words, I wanted to make sure that the code worked there too, as well as it did on my laptop or desktop machine.

Java Web Start allows you to package a system of any number of JAR files and data files and start the system when they are all downloaded. Moreover, if the data you want to include is voluminous, like XML data often is, you can create a compressed JAR file, which will make the download much faster, but hardly affect the performance at all.

Get a Head Start
There are only six major steps to writing and creating a Java Web Start application: 1) set the Web server to recognize the Web Start MIME type; 2) write the application as usual, and put the classes in a JAR file; 3) sign the JAR file; 4) create a package file that lists all the JARs in the application as a JNLP file; 5) put the JNLP file and the JAR files together on the Web site where they can be accessed; and 6) create a Web page to launch the application. We'll go through each of these steps for a simple Web start application.

Each Java Web Start program consists of a set of JAR files and a file with a JNLP extension that contains a description of these files. Your Web server must be able to recognize that a JNLP file has the type:

application/x-java-jnlp-file

In the case of the Apache Web server, you must add this line to the .mime.types configuration file:

application/x-java-jnlp-file 
   JNLP

For other Web servers, you need to find where to add this type. If a Web hosting company hosts your server, it may provide a service to add types graphically or by e-mail request. You can write any sort of application you like, as long as all the resources can be put in JAR files. We'll write a simple program to parse this input XML data file:

<?xml version="1.0" encoding=
   "UTF-8" ?>

<document>

   <person>
      <name>Sam</name>
      <surname>Spade</surname>
   </person>
   <person>
      <name>Sally</name>
      <surname>Frazzle</surname>
   </person>
   <person>
      <name>Andre</name>
      <surname>Norton</surname>
   </person>

</document>

and display these names in a listbox (see Figure 1).

Now the SAX parser for this XML file is easy to write, because we have to look only at the startElement(), endElement(), and characters() methods. We write a small DocParser class that extends the SAX DefaultHandler class and overrides these three methods. The characters() method just accumulates characters from the input line into a buffer, which we reset every time we start a new element. This means we are just saving the characters between tags:

//all characters between tags 
//accumulate here
//may be called any number of 
//times between tags.
public void characters(
   char[] ch, int start, 
   int length) 
      throws SAXException {
      char cbuf[] = 
         new char[length];
      int k = start;
      for(int i=0; i< length; 
         i++) {
         cbuf[i]=ch[k++];
      }
      buffer.append(cbuf);
   }

The startElement() tag resets the string buffer:

//a tag has been started
public void startElement(
   String uri,
   String localName,
   String qName,
   Attributes attrib)
      throws SAXException {
   buffer = new StringBuffer(); 
   //create a new buffer
   }

and the endElement() method stores first and last names:

//a tag has ended
   //a tag has ended
public void endElement(
   String uri, String localName, 
   String qName)
   throws SAXException {

   if (qName.equals("name")) {
      String buf = 
         buffer.toString();
      person = new Person(buf);
      buffer = new StringBuffer();
   }
   if (qName.equals("surname")) {
      title = 
         buffer.toString().trim();
      person.setSurname (title);
      docs.addElement( person);
      buffer = new StringBuffer();
   }
}

and then stores that Person object in a vector until all the names have accumulated.

The real trick to this program is where to find the XML file that it will be reading. Recall that all the resources for a Web Start program must be inside JAR files. We do this in the main program's constructor, creating an input stream by opening that file from the JAR file:

//opens an input stream from a 
//datafile
//enclosed in the JAR file
public InputStream getJarData() 
{
   try {
      ClassLoader cl = 
         this.getClass().
         getClassLoader();
      URL url = cl.getResource(
         fileName);
      InputStream f = 
         url.openStream();
      return f;
   } catch (IOException e) {
      return null;
   }
}

Then we start the SAX parser on this input stream like this:

public void parseDocuments(
   InputStream stream) {
   docParser = new DocParser();
   try {
      SAXParserFactory sFact = 
         SAXParserFactory.
         newInstance();
      parser = sFact.
         newSAXParser();
      parser.parse(
         stream, docParser);
   } catch (SAXException e) {
      System.out.println(
         "SAX error:" + 
         e.getMessage() + 
         e.getStackTrace());
   } catch (
      ParserConfigurationException 
      e) {
      System.out.println(
         "Config error:" + 
         e.getMessage());
   } catch (IOException e) {
      System.out.println(
         "IO error:" + 
         e.getMessage());
   }

}

Finally, when the data are all parsed, we can fetch the vector of Person objects:

Vector v = docParser.getDocs() ;
Iterator iter = v.iterator() ;
while(iter.hasNext() ) {
   Person doc = (
      Person)iter.next() ;
   jList.add(doc.getNames() );
}

and load them into the listbox (see Figure 1).

Make, Sign the JAR File
Whatever development environment you use, you can make a JAR file that includes this XML file in about three clicks. Just right-click on the project and select Export, JAR file, and then select the elements to export (see Figure 2). One advantage of using data embedded in JAR files here is that you can compress them. Since XML files tend to be huge, this compression can be significant, saving on download time without affecting the program's performance noticeably in loading the data. In the dialog box example, you can see that we have selected the Compress option for this reason (see Figure 2). JAR files, of course, are compressed using much the same algorithm as ZIP files.

If you are distributing this Web Start program "in the wild," you probably need to sign the file using a service provided by a commercial provider. However, you can create a test certificate to make sure everything works using the keytool and jarsigner programs that are provided with Java 1.4.2.

First, create a key in the internal registry maintained by keytool. From the command line type:

keytool -genkey -keystore 
   testkeys -alias mykeys
Enter keystore password:  abcde
Keystore password is too short - 
   must be at least 6 characters
Enter keystore password:  abcdef
What is your first and last 
   name?
   [Unknown]:  James
What is the name of your 
   organizational unit?
   [Unknown]:  Cooper
What is the name of your 
   organization?
   [Unknown]:  JavaPro
What is the name of your City or 
   Locality?
   [Unknown]:  New York
What is the name of your State 
   or Province?
   [Unknown]:  NY
What is the two-letter country 
   code for this unit?
   [Unknown]:  NY
Is CN=James, OU=Cooper, O=
   JavaPro, L=New York, ST=NY, C=
   NY correct?
   [no]:  yes

Enter key password for <mykeys>
   (RETURN if same as keystore 
   password):

Then, to create a self-sign test certificate, type:

C:\>keytool -selfcert -alias 
   mykeys -keystore testkeys
Enter keystore password:  abcdef

Now, finally, to sign the JAR file, go to the folder where the JAR file is located and type:

jarsigner -keystore testkeys 
   wsdemo.jar mykeys

and enter the password you created. Your file is now signed and ready for deployment.

Creating the JNLP Descriptor
Most of the errors in deploying Java Web Start applications can be traced to the syntax of the JNLP file. See Listing 1 for a correct version of this project's JNLP file, which is just an XML file describing the program to be launched. The <jnlp> tag must have a correct path in it, exactly as shown, with the URL path specified in the codebase and the name of the JNLP file itself in the href. The information section is pretty much free form and can contain any descriptions you wish to include. The title and vendor text will appear in the splash screen when you launch the program.

Normally, Web Start applications are run in the sandbox much like that applets use, but you can request unrestricted access using the security tag section exactly as shown.

The resources section needs to include a list of all the JAR files included in the program, and one and only one of them must have main="true", indicating that this is the class that launches the program. As shown in the comments, you can include as many other JAR files as you like. These JAR files can even contain native libraries (such as Windows DLLs) as long as the Java classes load them specifically.

You can specify that additional memory is to be used, but be sure that if you do, you include both the initial and max heap size arguments. You can also leave both out for simple programs.

Finally, the exact class name that contains the main method is specified in the application-desc tag. Be sure that you include the complete package name and not just the class name. For a fuller description of all the possible JNLP tags, visit the Sun site (see Resources).

Launching Web Start
To launch a Java Web Start program, just create a page with a link to the JNLP file, which includes all the JAR files in that same directory. The link from the Web page is simply:

<li>
   <a href="wsdemo.jnlp">
      Click here</a> 
      to see the Java Web start 
      demo.</li>

When you click on the top link on the complete Web page (see Figure 3), you get the splash screen (see Figure 4). Then on the first time only, you will get a security warning (see Figure 5). The program launches to display the listbox (see Figure 1). After you run it twice, you will get a popup asking if you want to add an icon to your desktop. Each time you launch the program it checks for updates, if your computer is connected to the Internet, and downloads them, which makes the system just as flexible as an applet but more powerful because these are true applications.

We've gone through all the steps necessary to get a Web Start application going. Once you get one running the rest is smooth sailing.

Web Start applications can be very useful indeed. Imagine that you are developing an application that someone remote to you will be using. The application gives you a simple way to post updated JAR files each time you make an update and know that the remote version will run correctly the next time that user starts the program. Compared to Froot Loops, this seamless feature is compelling! You can try it on your own computer by installing an Apache server (see Resources, if you want to see it work on the Web).

About the Author
James W. Cooper is a computer science researcher and the author of 15 books, including Java Design Patterns: A Tutorial (Addison-Wesley: 2000), Visual Basic Design Patterns VB 6.0 and VB.NET (Addison-Wesley: 2001), and C# Design Patterns: A Tutorial (Addison-Wesley: 2002). Contact James at .