Lesson 7: Packages and Java Archive File Format

Until now, you have used classes from the Java API library by importing the package containing the class or classes you need. A package is a convenient way to organize groups of related classes, and in development, you should organize your application files into packages too. Packages make it easier to locate and use the class files and help you control access to class data at run time.

When your application is fully tested, debugged, and ready for deployment, use the Java Archive file format to deploy the application. JAR file format is a compression and file packaging format and tool for bundling executable files with any other related application files so they can be deployed as one unit.

This lesson shows you how to organize the program files from Part 2, Lesson 6: Internationalization into packages and deploy the executable and other related files to production using JAR file format. Normally, you would use packages from the beginning of development.

Setting up Class Packages

It is easy to organize class files into packages. All you do is put related class files in the same directory, give the directory a name that relates to the purpose of the classes, and add a line to the top of each class file that declares the package name, which is the same as the directory name where they reside.

For example, the class and other related files for the program files from Part 2, Lesson 6: Internationalization can be divided into three groups of files: fruit order client, view order client, and server files. Although these three sets of classes are related to each other, they have different functions and are to be deployed separately.

Create the Directories

To organize the internationalization program into three packages, you could create the following three directories and move the listed source files into them:

  • client1
    • RMIEnglishApp.java
    • RMIFrenchApp.java
    • RMIGermanApp.java
    • MessagesBundle_de_DE.properties
    • MessagesBundle_en_US.properties
    • MessagesBundle_fr_FR.properties
    • index.html
    • rmiFapp.html
    • rmiGapp.html
    • rmiEapp.html
    • java.policy
  • client2
    • RMIClient2.java
    • MessagesBundle_de_DE.properties
    • MessagesBundle_en_US.properties
    • MessagesBundle_fr_FR.properties
    • java.policy
  • server
    • DataOrder.java
    • RemoteServer.java
    • Send.java
    • java.policy

Declare the Packages

Each *.java file needs a package delcaration at the top that reflects the name of the directory. Also, the fruit order ( client1 and view order ( client2) client class files need an import statement for the server package because they have to access the remote server object at runtime.

As an example, the package declaration and import statements for the RMIClient2.java class file look like this:


//package declaration
package client2;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;

import java.io.*;
import java.net.*;

import java.rmi.*;
import java.rmi.server.*;

import java.util.*;
import java.text.*;

//Import server package
import server.*;

Make Classes and Fields Accessible

With class files organized into packages, you have to declare the server classes in the server directory public so they can be instantiated by client programs, which are created from classes in the client1 and client2 directories. If you do not specify public, a class can only be instantiated by an object created from a class in the same package.

So client programs can access the fruit order data, the fields of the DataOrder class have to be public too. The RemoteServer class and Send interface need to be public classes, but their fields do not need to be public because the do not have public data.

Fields and methods without an access specifier such as public can only be accessed by objects created from classes in the same package.

Here is the new DataOrder class.


package server;

import java.io.*;

//Make class public
public class DataOrder implements Serializable{

//Make fields public
  public String apples, peaches, pears, cardnum, custID;
  public double icost;
  public int itotal;
}

Change Client Code to Find the Properties Files

In the example, the properties files ( Messages_*) are stored in the directories with the client source files. This makes it easier to package and deploy the files later. So the programs can field the properties files, you have to make one small change to the client source code.

The code that creates the messages variable needs to include the directory (package name) as follows:


  messages = ResourceBundle.getBundle(
        "client2" + 
        File.separatorChar + 
        "MessagesBundle", currentLocale);

Compile and Run the Example

Compiling and running the example organized into packages is a little different from compiling and running the example in previous lessons. First, you have to execute the compiler and interpreter commands from one directory above the package directories, and second, you have to specify the package directories to the compiler and interpreter commands.

Compile

These instructions assume development occurs in the zelda home directory.


                    Unix:
cd /home/zelda/classes

javac server/Send.java
javac server/RemoteServer.java
javac client2/RMIClient2.java
javac client1/RMIFrenchApp.java
javac client1/RMIGermanApp.java
javac client1/RMIEnglishApp.java
rmic -d . server.RemoteServer
cp server/RemoteServer*.class 
        /home/zelda/public_html/classes
cp server/Send.class 
        /home/zelda/public_html/classes
cp server/DataOrder.class
        /home/zelda/public_html/classes


                    Win32:
cd \home\zelda\classes

javac server\Send.java
javac server\RemoteServer.java
javac client2\RMIClient2.java
javac client1\RMIFrenchApp.java
javac client1\RMIGermanApp.java
javac client1\RMIEnglishApp.java
rmic -d . server.RemoteServer
copy server\RemoteServer*.class
        \home\zelda\public_html\classes
copy server\Send.class 
        \home\zelda\public_html\classes
copy server\DataOrder.class
        \home\zelda\public_html\classes
                

Note: The rmic -d . server.RemoteServer line uses server.RemoteServer instead of server/RemoteServer so the _stub and _skel classes are generated properly with the package.

Start rmi Registry:


                    
Unix:
cd /home/zelda/public_html/classes
unsetenv CLASSPATH
rmiregistry &


Win32:
cd \home\zelda\public_html\classes
set CLASSPATH=
start rmiregistry 
                

Start the Server


  
Unix:
  cd /home/zelda/public_html/classes

  java -Djava.rmi.server.codebase=
        http://kq6py/~zelda/classes
  -Djava.rmi.server.hostname=kq6py.eng.sun.com
  -Djava.security.policy=
        server/java.policy server/RemoteServer


Win32:
  cd \home\zelda\public_html\classes

  java -Djava.rmi.server.codebase=
        file:c:\home\zelda\public_html\classes
  -Djava.rmi.server.hostname=kq6py.eng.sun.com
  -Djava.security.policy=
        server\java.policy server\RemoteServer
                

Start RMIGermanApp Here is the HTML code to load the German applet, Note the directory/package name prefixed to the applet class name ( client1/RMIGermanApp.class).


 <HTML>
 <BODY>
 <APPLET CODE=client1/RMIGermanApp.class WIDTH=300 HEIGHT=300>
 </APPLET>
 </BODY>
 </HTML>

client1


  cd /home/zelda/classes

  appletviewer rmiGapp.html

Start RMIClient2 in French


                   Unix:
  cd /home/zelda/classes

  java -Djava.rmi.server.codebase=
        http://kq6py/~zelda/classes
  -Djava.rmi.server.hostname=kq6py.eng.sun.com
  -Djava.security.policy=client2/java.policy
        client2/RMIClient2 kq6py.eng.sun.com fr FR


                    Win32:
  cd \home\zelda\classes

  java -Djava.rmi.server.codebase=
        file:c:\home\zelda\public_html\classes
  -Djava.rmi.server.hostname=kq6py.eng.sun.com
  -Djava.security.policy=client2\java.policy
        client2\RMIClient2 kq6py.eng.sun.com fr FR
                

Using JAR Files to Deploy

After testing and debugging, the best way to deploy the two client and server files is to bundle the executables and other related application files into three separate JAR files, one JAR file for each client program, and one JAR file for the server program.

JAR files use the ZIP file format to compress and pack files into, and decompress and unpack files from, the JAR file. JAR files make it easy to deploy programs that consist of many files. Browsers can easily download applets bundled into JAR files, and the download goes much more quickly than if the applet and its related files were not bundled into a JAR file.

Server Set of Files

Here are the server files:

  • RemoteServer.class
  • RemoteServer_skel.class
  • RemoteServer_stub.class
  • Send.class
  • DataOrder.class
  • java.policy

Compress and Pack Server Files

To compress and pack the server files into one JAR file, type the following command on one line. This command is executed in the same directory with the files. If you execute the command from a directory other than where the files are, you have to specify the full pathname.


  jar cf server.jar 
        RemoteServer.class 
        RemoteServer_skel.class
        RemoteServer_stub.class
        Send.class
        DataOrder.class
        java.policy

jarjarjarcfjarserver.jar


kq6py% jar
Usage: jar {ctxu}[vfm0M] [jar-file] [manifest-file] 
  [-C dir] files ...
Options:
  -c  create new archive
  -t  list table of contents for archive
  -x  extract named (or all) files from archive
  -u  update existing archive
  -v  generate verbose output on standard output
  -f  specify archive file name
  -m  include manifest information from specified 
        manifest file
  -0  store only; use no ZIP compression
  -M  Do not create a manifest file for the entries
  -C  change to the specified directory and 
        include the following file
If any file is a directory then it is processed 
  recursively.
The manifest file name and the archive file name 
  needs to be specified in the same order the 
  'm' and 'f' flags are specified.

Example 1: to archive two class files into an 
  archive called classes.jar: 
     jar cvf classes.jar Foo.class Bar.class 
Example 2: use an existing manifest file 'mymanifest' 
  and archive all the files in the foo/ directory 
  into 'classes.jar': 
     jar cvfm classes.jar mymanifest -C foo/ .

server.jar

Decompress and Unpack Server Files

After moving the JAR file to its final location, the compressed and packed files need to be decompressed and unpacked so you can start the server. The following command means extract ( x) all files from the server.jar file ( f).

jar xf server.jar

Fruit Order Set of Files

The fruit order set of files (below) consists of applet classes, web pages, translation files, and the policy file. Because they live on the web, they need to be in a directory accessible by the web server. The easiest way to deploy these files is to bundle them all into a JAR file and copy them to their location.

  • RMIEnglishApp.class
  • RMIFrenchApp.class
  • RMIGermanApp.class
  • index.html (top-level web page where user chooses language)
  • rmiEapp.html (second-level web page for English)
  • rmiFapp.html (second-level web page for French)
  • rmiGapp.html (second-level web page for German)
  • MessagesBundle_de_DE.properties
  • MessagesBundle_en_US.properties
  • MessagesBundle_fr_FR.properties
  • java.policy

Compress and Pack Files


  jar cf applet.jar 
        RMIEnglishApp.class
        RMIFrenchApp.class
        RMIGermanApp.class
        index.html
        rmiEapp.html
        rmiFapp.html
        rmiGapp.html
        MessagesBundle_de_DE.properties
        MessagesBundle_en_US.properties
        MessagesBundle_fr_FR.properties
        java.policy

applet.jar

Decompress and Unpack Files

An applet in a JAR file can be invoked from an HTML file without being unpacked. All you do is specify the ARCHIVE option to the APPLET tag in your web page, which tells appletviewer the name of the JAR file containing the class file. Be sure to include the package directory when you specify the applet class to the CODE option.

You can leave the translation files and policy file in the JAR file. When using appletviewer, the applet invoked from the JAR file will find them in the JAR file.


<HTML>
<BODY>
<APPLET CODE=client1/RMIFrenchApp.class
  ARCHIVE="applet.jar"
  WIDTH=300
  HEIGHT=300>
</APPLET>
</BODY>
</HTML>

However, you do need to unpack the web pages so you can move them to their final location. The following command does this. Everything goes on one line.


  jar xv applet.jar index.html  
        rmiEapp.html 
        rmiFapp.html 
        rmiGapp.html

Note: To run the HTML files from a browser, you need to unpack the JAR file, copy the java.policy file to your home directory and make sure it has the right name ( .java.policy for Unix and java.policy for Windows), and install Java Plug-In.

View Order Set of Files

The view order set of files (below) consists of the application class file and the policy file.

  • RMIClient2.class
  • java.policy

Compress and Pack Files

jar cf vieworder.jar RMIClient2.class java.policy

vieworder.jar

Decompress and Unpack Files

jar xf vieworder.jar

More Information

You can find more information on packages in the Creating and Using Packages lesson in The Java Tutorial.

You can find more information on these and other JAR file format topics in the JAR File Format trail in The Java Tutorial.