1. Application Packaging
We now leave the world of applets and turn to the packaging of Java applications. When you ship an application, you don't want to deploy a mess of class files. Just as with applets, you should package the class files and other resources required by your program in a JAR file. Once the program is packaged, it can be loaded with a simple command or, if the operating system is configured appropriately, by double-clicking on the JAR file.

The Manifest
You can package application programs, program components (sometimes called "beans"—see Chapter 8 of Volume 2), and code libraries into JAR files. For example, the runtime library of the JDK is contained in a very large file rt.jar.

A JAR file is simply a ZIP file that contains classes, other files that a program may need (such as icon images), and a manifest file that describes special features of the archive.

The manifest file is called MANIFEST.MF and is located in a special META-INF subdirectory of the JAR file. The minimum legal manifest is quite boring: just

Manifest-Version: 1.0 

Complex manifests can have many more entries. The manifest entries are grouped into sections. The first section in the manifest is called the main section. It applies to the whole JAR file. Subsequent entries can specify properties of named entities such as individual files, packages, or URLs. Those entries must begin with a Name entry. Sections are separated by blank lines. For example,

Manifest-Version: 1.0
lines describing this archive


Name: Woozle.class
lines describing this file

Name: com/mycompany/mypkg/
lines describing this package


To edit the manifest, place the lines that you want to add to the manifest into a text file. Then run
jar cfm JARFileName ManifestFileName . . .

For example, to make a new JAR file with a manifest, run:
jar cfm MyArchive.jar manifest.mf com/mycompany/mypkg/*.class

To add items to the manifest of an existing JAR file, place the additions into a text file and use a command such as
jar ufm MyArchive.jar manifest-additions.mf

See http://java.sun.com/j2se/5.0/docs/guide/jar/jar.html for more information on the JAR and manifest file formats.

Self-Running JAR Files
To package an application, place all files that your application needs into a JAR file and then add a manifest entry that specifies the main class of your program—the class that you would normally specify when invoking the java program launcher.

Make a file, say, mainclass.mf, containing a line such as
Main-Class: com/mycompany/mypkg/MainAppClass

CAUTION
The last line in the manifest must end with a newline character. Otherwise, the manifest will not be read correctly. It is a common error to produce a text file containing just the Main-Class line without a line terminator.

Do not add a .class extension to the main class name. Then run the jar command:
jar cvfm MyProgram.jar mainclass.mf files to add

Users can now simply start the program as
java -jar MyProgram.jar

Depending on the operating system configuration, you may be able to launch the application by double-clicking on the JAR file icon.

On Windows, the Java runtime installer creates a file association for the ".jar" extension that launches the file with the javaw -jar command. (Unlike the java command, the javaw command doesn't open a shell window.)
On Solaris, the operating system recognizes the "magic number" of a JAR file and starts it with the java -jar command.
On Mac OS X, the operating system recognizes the ".jar" file extension and executes the Java program when you double-click on a JAR file. Furthermore, the application package utility MRJAppBuilder lets you turn a JAR file into a first-class, double-clickable Mac application with custom class paths, icons, and so on. For more information, see http://developer.apple.com/qa/java/java29.html.

Resources
Classes that are used in both applets and applications often use associated data files, such as
Image and sound files;

Text files with message strings and button labels;
Files with binary data, for example, to describe the layout of a map.
In Java, such an associated file is called a resource.
NOTE
In Windows, the term "resource" has a more specialized meaning. Windows resources also consist of images, button labels, and so on, but they are attached to the executable file and accessed by a standard programming interface. In contrast, Java resources are stored as separate files, not as part of class files. And it is up to each class to access and interpret the resource data.
For example, consider a class, AboutPanel, that displays a message such as the one in Figure 10-11.
Figure 10-11. Displaying a resource from a JAR file

Of course, the book title and copyright year in the panel will change for the next edition of the book. To make it easy to track this change, we want to put the text inside a file and not hardcode it as a string.

But where should you put a file such as about.txt? Of course, it would be convenient if you simply placed it with the rest of the program files, for example, in a JAR file.

The class loader knows how to search for class files until it has located them somewhere on the class path, or in an archive, or on a web server. The resource mechanism gives you the same convenience for files that aren't class files. Here are the necessary steps:

1.Get the Class object of the class that has a resource, for example, AboutPanel.class.
2.Call getresource(filename) to get the resource location as a URL.
3.If the resource is an image or audio file, read it directly with the getImage or getAudioClip method.
4.Otherwise, use the openStream method on the URL to read in the data in the file. (See Chapter 12 for more on streams.)

The point is that the class loader remembers how to locate the class and it can then search for the associated resource in the same location.
For example, to make an icon with the image file about.gif, do the following:
URL url = AboutPanel.class.getResource("about.gif");  ImageIcon icon = new ImageIcon(url);

That means "locate the about.gif file at the same place where you find AboutPanel.class."
To read in the file about.txt, you can use similar commands:
URL url = AboutPanel.class.getResource("about.txt");  InputStream stream = url.openStream();

Because this combination is so common, there is a convenient shortcut method: geTResourceAsStream returns an InputStream, not a URL.
InputStream stream = AboutPanel.class.getResourceAsStream("about.txt");

To read from this stream, you need to know how to process input (see Chapter 12 for details). In the sample program, we read the stream a line at a time with the following instructions:

InputStream stream = AboutPanel.class.getResourceAsStream("about.txt");  Scanner in = Scanner.create(stream);  while (in.hasNext())     textArea.append(in.nextLine() + "\n"); 

The Core Java example files include a JAR file named ResourceTest.jar that contains all the class files for this example and the resource files about.gif and about.txt. This demonstrates that the program locates the resource file in the same location as the class file, namely, inside the JAR file. Example 10-12 shows the source code.

TIP
As you saw earlier in this chapter, applets can locate image and audio files with the getImage and getAudioClip methods—these methods automatically search JAR files. But to load other files from a JAR file, applets still need the geTResourceAsStream method.
Instead of placing a resource file inside the same directory as the class file, you can place it in a subdirectory. You can use a hierarchical resource name such as
data/text/about.txt

This is a relative resource name, and it is interpreted relative to the package of the class that is loading the resource. Note that you must always use the / separator, regardless of the directory separator on the system that actually stores the resource files. For example, on the Windows file system, the resource loader automatically translates / to \ separators.

A resource name starting with a / is called an absolute resource name. It is located in the same way that a class inside a package would be located. For example, a resource

/corejava/title.txt 

is located in the corejava directory (which may be a subdirectory of the class path, inside a JAR file, or, for applets, on a web server).

Automating the loading of files is all that the resource loading feature does. There are no standard methods for interpreting the contents of a resource file. Each program must have its own way of interpreting the contents of its resource files.

Another common application of resources is the internationalization of programs. Language-dependent strings, such as messages and user interface labels, are stored in resource files, with one file for each language. The internationalization API, which is discussed in Chapter 10 of Volume 2, supports a standard method for organizing and accessing these localization files.

Example 10-12. ResourceTest.java


 1. import java.awt.*;  
 2. import java.awt.event.*;  
 3. import java.io.*;  
 4. import java.net.*;  
 5. import java.util.*;  
 6. import javax.swing.*;  
 7.  
 8. public class ResourceTest  
 9. { 
 10.    public static void main(String[] args) 
 11.    { 
 12.       ResourceTestFrame frame = new ResourceTestFrame(); 
 13.       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
 14.       frame.setVisible(true); 
 15.    } 
 16. } 
 17. 
 18. /** 
 19.    A frame with a panel that has components demonstrating 
 20.    resource access from a JAR file. 
 21. */ 
 22. class ResourceTestFrame extends JFrame 
 23. { 
 24.    public ResourceTestFrame() 
 25.    { 
 26.       setTitle("ResourceTest"); 
 27.       setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 
 28.       add(new AboutPanel()); 
 29.    } 
 30. 
 31.    public static final int DEFAULT_WIDTH = 300; 
 32.    public static final int DEFAULT_HEIGHT = 300; 
 33. } 
 34. 
 35. /** 
 36.    A panel with a text area and an "About" button. Pressing 
 37.    the button fills the text area with text from a resource. 
 38. */ 
 39. class AboutPanel extends JPanel 
 40. { 
 41.    public AboutPanel() 
 42.    { 
 43.       setLayout(new BorderLayout()); 
 44. 
 45.       // add text area 
 46.       textArea = new JTextArea(); 
 47.       add(new JScrollPane(textArea), BorderLayout.CENTER); 
 48. 
 49.       // add About button 
 50.       URL aboutURL = AboutPanel.class.getResource("about.gif"); 
 51.       JButton aboutButton = new JButton("About", new ImageIcon(aboutURL)); 
 52.       aboutButton.addActionListener(new AboutAction()); 
 53.       add(aboutButton, BorderLayout.SOUTH); 
 54.    } 
 55. 
 56.    private JTextArea textArea; 
 57. 
 58.    private class AboutAction implements ActionListener 
 59.    { 
 60.       public void actionPerformed(ActionEvent event) 
 61.       { 
 62.          InputStream stream = AboutPanel.class.getResourceAsStream("about.txt"); 
 63.          Scanner in = new Scanner(stream); 
 64.          while (in.hasNext()) 
 65.             textArea.append(in.nextLine() + "\n"); 
 66.       } 
 67.    } 
 68. } 

java.lang.Class 1.0
URL getResource(String name) 1.1
InputStream getResourceAsStream(String name) 1.1

find the resource in the same place as the class and then return a URL or input stream you can use for loading the resource. Return null if the resource isn't found, and so do not throw an exception for an I/O error.
Parameters:
name
    The resource name

Sealing
We mentioned in Chapter 4 that you can seal a Java language package to ensure that no further classes can add themselves to it. You would want to seal a package if you use package-visible classes, methods, and fields in your code. Without sealing, other classes can place themselves into the same package and thereby gain access to its package-visible features.

For example, if you seal the package com.mycompany.util, then no class outside the sealed archive can be defined with the statement
package com.mycompany.util;

To achieve this, you put all classes of the package into a JAR file. By default, packages in a JAR file are not sealed. You can change that global default by placing the line

Sealed: true 

into the main section of the manifest. For each individual package, you can specify whether you want the package sealed or not, by adding another section to the JAR file manifest, like this:

Name: com/mycompany/util/ 
Sealed: true   

Name: com/mycompany/misc/ 
Sealed: false 

To seal a package, make a text file with the manifest instructions. Then run the jar command in the usual way:
jar cvfm MyArchive.jar manifest.mf files to add

2. Java Web Start
Java Web Start is a newer technology that aims to improve on the user experience of Java programs that are delivered over the Internet. Here are the principal differences between Java Web Start applications and applets.

Java Web Start delivers regular Java applications that are started by a call to the main method of a class. There is no need to inherit from Applet.

A Java Web Start application does not live inside a browser. It is displayed outside the browser.

A Java Web Start application can be launched through the browser, but the underlying mechanism is quite different from the launch of an applet. Browsers are tightly integrated with a Java runtime environment that executes applets. The Java Web Start integration is much looser. The browser simply launches an external application whenever it loads a Java Web Start application descriptor. That is the same mechanism that is used to launch other helper applications such as Adobe Acrobat or RealAudio. Even hostile browser vendors won't be able to interfere with this mechanism.

Once a Java Web Start application has been downloaded, it can be started outside the browser.

Java Web Start has a slightly relaxed "sandbox" that allows unsigned applications some access to local resources.

To prepare an application for delivery by Java Web Start, you package it in one or more JAR files. Then you prepare a descriptor file in Java Network Launch Protocol (JNLP) format. Place these files on a web server. Next, make sure that your web server reports a MIME type of application/x-java-jnlp-file for files with extension .jnlp. (Browsers use the MIME type to determine which helper application to launch.) Consult your web server documentation for details.

TIP
To experiment with Java Web Start, install Tomcat from jakarta.apache.org/tomcat. Tomcat is a container for servlets and JSP pages, but it also serves web pages. The current version is preconfigured to handle JNLP files.

Let's try out Java Web Start to deliver the calculator application from Chapter 9. Follow these steps.
1.Compile Calculator.java.
2.Prepare a manifest file Calculator.mf with the line
Main-Class: Calculator
3.Produce a JAR file with the command
jar cvfm Calculator.jar Calculator.mf *.class
4.Prepare the launch file Calculator.jnlp with the following contents:
Prepare the launch file Calculator.jnlp with the following contents:


<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+"codebase="http://localhost:8080/calculator/" href="Calculator.jnlp">
  <information>
    <title>Calculator Demo Application</title>
    <vendor>Cay S. Horstmann</vendor>
    <description>A Calculator</description>
    <offline-allowed/>
  </information>
  <resources>
    <j2se version="5.0+"/>
    <jar href="Calculator.jar"/>
  </resources>
  <application-desc/>
</jnlp>


 The launch file format is fairly self-explanatory. For a full specification, seehttp://java.sun.com/products/javawebstart/docs/developersguide.htm.5.If you use Tomcat, make a directory tomcat/webapps/calculator, where tomcat is the base directory of your Tomcat installation.
Make a subdirectory tomcat/webapps/calculator/WEB-INF, and place the following minimal web.xml file inside the WEB-INF subdirectory:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
</web-app>

6.Place the JAR file and the launch file on your web server so that the URL matches the codebase enTRy in the JNLP file. If you use Tomcat, put them into the tomcat/webapps/calculator directory.
7.Make sure that your browser has been configured for Java Web Start, by checking that the application/x-java-jnlp-file MIME type is associated with the javaws application. If you installed the JDK, the configuration should be automatic.
8.Start Tomcat.
9.Point your browser to the JNLP file. For example, if you use Tomcat, go tohttp://localhost:8080/calculator/Calculator.jnlp.
10.You should see the launch window for Java Web Start (see Figure 10-12). Soon afterward, the calculator should come up, with a border marking it as a Java Web Start application (see Figure 10-13).
Figure 10-12. Launching Java Web Start

Figure 10-13. The calculator delivered by Java Web Start

11.When you access the JNLP file again, the application is retrieved from the cache. You can review the cache content by using the Java Plug-in control panel (see Figure 10-14). As of JDK 5.0, that control panel is used both for applets and Java Web Start applications. In Windows, look for the Java Plug-in control panel inside the Windows control panel. Under Linux, run jdk/jre/bin/ControlPanel.
Figure 10-14. The application cache