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.
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:
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
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:
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
jar
jar
jar
cf
jar
server.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
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.
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
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.
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.