Java ScreenShot
     

Screenshot Core Java 2: Volume I - Fundamentals

Table of Contents
 10.  Deploying Applets and apps


Packaging apps

We now leave the world of applets and turn to the packaging of Java apps. When you ship an app, 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 app programs, program components (sometimes called "Java beans"—see of Volume 2), and code libraries into JAR files. For example, the runtime library of the SDK 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: foo/bar/
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


For more information on the JAR and manifest file formats, see http://java.oracle.com/j2se/1.3/docs/guide/jar/jar.html.

Self-Running JAR files

To package an app, place all files that your app 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 interpreter. Make a file, say, mainclass.mf, containing a line such as

Main-Class: com/mypackage/MainAppClass


Java graphics caution_icon.gif

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 app 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, there is an app package utility MRJAppBuilder that you can use to turn a JAR file into a first-class double-clickable Mac app with custom class paths, icons, and so on. See http://developer.apple.com/qa/java/java29.html for more information.

Resources

Classes that are used in both applets and apps 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.

Java graphics notes_icon.gif

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 coding 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 Screenshot-11.
Screenshot-11. Displaying a resource from a JAR file

Java graphics 10fig11.gif


Of course, the tutorial title and copyright year in the panel will change for the next version of the tutorial. 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 for more on streams.)

The point is that the class loader remembers how to locate the class, and then it can 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 in = url.openStream();


Because this combination is so common, there is a convenient shortcut method: getResourceAsStream returns an InputStream, not a URL.

InputStream in
 = AboutPanel.class.getResourceAsStream("about.txt");


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

InputStream in = AboutPanel.class.
 getResourceAsStream("about.txt");
BufferedReader reader = new BufferedReader(new
 InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null)
 textArea.append(line + "\n");


The Core Java example files that you downloaded from www.phptr.com/corejava include a JAR file named ResourceTest.jar that contains all of 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.

Java graphics exclamatory_icon.gif

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 app 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 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 javax.swing.*;
 6.
 7. public class ResourceTest
 8. {
 9. public static void main(String[] args)
10. {
11. ResourceTestFrame frame = new ResourceTestFrame();
12. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
13. frame.show();
14. }
15. }
16.
17. /**
18. A frame with a panel that has components demonstrating
19. resource access from a JAR file.
20. */
21. class ResourceTestFrame extends JFrame
22. {
23. public ResourceTestFrame()
24. {
25. setTitle("ResourceTest");
26. setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
27. setContentPane(new AboutPanel());
28. }
29.
30. public static final int DEFAULT_WIDTH = 300;
31. public static final int DEFAULT_HEIGHT = 300;
32. }
33.
34. /**
35. A panel with a text area and an "About" button. Pressing
36. the button fills the text area with text from a resource.
37. */
38. class AboutPanel extends JPanel
39. {
40. public AboutPanel()
41. {
42. setLayout(new BorderLayout());
43.
44. // add text area
45. textArea = new JTextArea();
46. add(new JScrollPane(textArea), BorderLayout.CENTER);
47.
48. // add About button
49. URL aboutURL = AboutPanel.class.getResource("about.gif");
50. JButton aboutButton = new JButton("About",
51. 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. try
63. {
64. // read text from resource into text area
65. InputStream in = AboutPanel.class.
66. getResourceAsStream("about.txt");
67. BufferedReader reader = new BufferedReader(new
68. InputStreamReader(in));
69. String line;
70. while ((line = reader.readLine()) != null)
71. textArea.append(line + "\n");
72. }
73. catch(IOException exception)
74. {
75. exception.printStackTrace();
76. }
77. }
78. }
79. }


java.lang.Class 1.0

Java graphics api_icon.gif
  • 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. The methods 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

Optional Packages

JAR files can be used to package code libraries. You can add any set of classes into a JAR file and make the classes available by adding the JAR file to the class path. For commonly used code libraries, you can bypass that step by turning a JAR file into an optional package.

Java graphics notes_icon.gif

In prior versions of the Java SDK, optional packages were called extensions. The "package" term is a bit misleading—an optional package can contain classes from multiple Java coding language packages.

The main section of the manifest of an optional package describes the contents. Here is an example.
Extension-Name: com.mycompany.myextension Specification-Vendor: My Company, Inc Specification-Version: 1.0
Implementation-Vendor-Id: com.mycompany Implementation-Vendor: My Company, Inc Implementation-Version: 1.0.3


The extension name can be completely arbitrary. Just like with Java language packages, you can ensure uniqueness by using reversed domain names. A program that requires extensions specifies them in the main section of its manifest:

Extension-List: myext otherext myext-Extension-Name: com.mycompany.myextension myext-Specification-Version: 1.0
myext-Implementation-Version: 1.0.1
myext-Implementation-Vendor-Id: com.mycompany otherext-Extension-Name: com.hal.util otherext-Specification-Version: 2.0


This particular app needs two optional packages, with aliases myext and anotherext. The alias-Extension-Name line yields the actual extension name. The app states that it requires a myext package that conforms to specification 1.0 or higher and implementation 1.0.1 or higher, and it insists that the package be implemented by a specific vendor. For the other extension, the program only requires that it conforms to specification 2.0 or higher. Any implementation and vendor are acceptable. When the program starts, it needs to locate the optional packages. An optional package JAR can simply be dropped into the jre/lib/ext directory. Alternatively, the program can specify a URL where the optional package can be downloaded, such as

alias-Implementation-URL: http://www.mycompany.com/packages/myextension.jar


For more information on optional packages, see http://java.oracle.com/j2se/1.4/docs/guide/extensions.

Sealing

We mentioned in that you can seal a Java language package to ensure that no further classes can add themselves to it. Sealing protects the features with package visibility. 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, like this:

Name: com/mycompany/mypackage/
Sealed: true Name: com/hal/util/
Sealed: false


To seal a package, make a text file with the manifest instructions. Then run the jar command:

jar cvfm MyPackage.jar sealed.mf files to add


Screenshot

Java ScreenShot
     
Top
 

Comments