Section 5.11. Bundling a Java Program: Put it in a JAR


5.11. Bundling a Java Program: Put it in a JAR

Distributing a Java application can be a pain. All but the simplest of applications will have many public classesand since there can only be one public Java class per source file, each Java source file becomes a class file, and the elements of a package name become directory nodes in the path to the class, you end up with a fairly complex collection of directories and files. Wouldn't it be nice to be able to roll the whole mess up into a single binary file for distribution?

Well, you can. The tool to do the job is called jar, which stands for Java ARchive.[26] The files produced by this utility are called JAR files. The JAR format is the common DOS/Windows ZIP file format, with a few special files to support some special features we will explain as they come up.

[26] An abbreviation made up of syllables from words instead of just initials is called a portmanteau. The US Navy is particularly keen on them, using terms like COMSURPAC (Commander, Surface Fleet, Pacific), COMSUBLANT (Commander, Submarine Fleet, Atlantic), and so forth. There. Now you can't claim you didn't learn anything from this book.

Example 5.19. javap output for FetchURL.class
 Compiled from FetchURL.java public class FetchURL extends java.lang.Object {   private java.net.URL requestedURL;   public FetchURL(java.lang.String);   public java.lang.String toString();   public static void main(java.lang.String[]); } Method FetchURL(java.lang.String)    0 aload_0    1 invokespecial #1 <Method java.lang.Object()>    4 aload_0    5 new #2 <Class java.net.URL>    8 dup    9 aload_1   10 invokespecial #3 <Method java.net.URL(java.lang.String)>   13 putfield #4 <Field java.net.URL requestedURL>   16 goto 27   19 astore_2   20 aload_2   21 invokevirtual #6 <Method null>   24 goto 27   27 return Exception table:    from   to target type      4    16   19   <Class java.lang.Exception> Method java.lang.String toString()    0 ldc #7 <String "">    2 astore_1    3 new #8 <Class java.io.BufferedReader>    6 dup    7 new #9 <Class java.io.InputStreamReader>   10 dup   11 aload_0   12 getfield #4 <Field java.net.URL requestedURL>   15 invokevirtual #10 <Method java.net.URLConnection openConnection()>   18 invokevirtual #11 <Method java.io.InputStream getInputStream()>   21 invokespecial #12 <Method java.io.InputStreamReader(java.io.InputStream)>   24 invokespecial #13 <Method java.io.BufferedReader(java.io.Reader)>   27 astore_3   28 goto 55   31 new #14 <Class java.lang.StringBuffer>   34 dup   35 invokespecial #15 <Method java.lang.StringBuffer()>   38 aload_1   39 invokevirtual #16 <Method java.lang.StringBuffer append(java.lang.String)>   42 aload_2   43 invokevirtual #16 <Method java.lang.StringBuffer append(java.lang.String)>   46 ldc #17 <String " ">   48 invokevirtual #16 <Method java.lang.StringBuffer append(java.lang.String)>   51 invokevirtual #18 <Method java.lang.String toString()>   54 astore_1   55 aload_3   56 invokevirtual #19 <Method java.lang.String readLine()>   59 dup   60 astore_2   61 ifnonnull 31   64 goto 79   67 astore 4   69 aload 4   71 invokevirtual #20 <Method null>   74 aconst_null   75 astore_1   76 goto 79   79 aload_1   80 areturn Exception table:    from   to target type      3    64   67   <Class java.lang.Exception> Method void main(java.lang.String[])    0 iconst_0    1 istore_1    2 goto 51    5 getstatic #21 <Field java.io.PrintStream out>    8 new #14 <Class java.lang.StringBuffer>   11 dup   12 invokespecial #15 <Method java.lang.StringBuffer()>   15 aload_0   16 iload_1   17 aaload   18 invokevirtual #16 <Method java.lang.StringBuffer append(java.lang.String)>   21 ldc #22 <String ":">   23 invokevirtual #16 <Method java.lang.StringBuffer append(java.lang.String)>   26 invokevirtual #18 <Method java.lang.String toString()>   29 invokevirtual #23 <Method void println(java.lang.String)>   32 getstatic #21 <Field java.io.PrintStream out>   35 new #24 <Class FetchURL>   38 dup   39 aload_0   40 iload_1   41 aaload   42 invokespecial #25 <Method FetchURL(java.lang.String)>   45 invokevirtual #26 <Method void println(java.lang.Object)>   48 iinc 1 1   51 iload_1   52 aload_0   53 arraylength   54 if_icmplt 5   57 return 

A JAR file packages a subdirectory and its descendants into a single file. A Java CLASSPATH specification may contain a JAR filename everywhere it might contain a directory name. Let's say you use the GPL'ed Java personal finance program called jgnash and you've compiled it from source, so you have a directory off your home directory called jgnash/bin. Suppose you run the program by directly invoking java to run the class jgnashMain and you have $HOME/jgnash/bin on your CLASSPATH. You could clean up the mess on your hard drive by using the jar command to squash all the files in jgnash/bin together into a single JAR file, as shown in Example 5.20.

Example 5.20. Making a JAR file
 $ cd ; mkdir jars $ jar cvf jars/jgnash.jar jgnash/bin 

You could then replace the $HOME/jgnash/bin enTRy in your CLASSPATH with $HOME/jars/jgnash.jar. After that you would still run jgnash with exactly the same java command you always did, but now you got rid of the cluttered pile of files.

This is only the most basic purpose of jar, however. Its uses extend well beyond merely concatenating and compressing collections of .class files.

5.11.1. Deploying Applications

One of the best uses of jar is to package applications for distribution. You can put a large Java application into a single file with jar, and by using a manifest (which we are about to discuss) you can nominate the main class to run in that JAR file. You can then provide a shell script (and a batch file, if you are also deploying to Microsoft Windows) that will set the CLASSPATH to point to the JAR file and run java against it. With this simple setup, users need not even know they are using a Java applicationit runs like any other application.

5.11.1.1 The Manifest File

The only way in which jar really differs from any other ZIP archive utility is in the automatic creation and use of a manifest file, by default named META-INF/MANIFEST in the archive. Even if you do not specify a manifest file of your own, the jar utility creates one for you. Let's take a moment to look at what goes into the manifest.

A manifest is basically a list of key/value pairs. The key comes at the start of a line and the value comes at the end of the line with a colon separating the two. Example 5.21 shows a sample manifest.

Example 5.21. Manifest from the Payback sample application
 Manifest-Version: 1.0 Ant-Version: Apache Ant 1.5.3 Created-By: 1.4.1_02-b06 (Sun Microsystems Inc.) Version: 1.0 Main-Class: net.multitool.Payback.Payback 

All of these entries were produced automatically by ant or the jar utility itself, except for Main-Class, which we specified (albeit with ant, as you will see in Chapter 9). The manifest has certain values that are always filled in by jar, but two that you might commonly specify are

  • Main-Class, which allows users to run a Java application by merely typing java someJarFile.jar, without having to know the fully package qualified name of the class that contains the application's main().

  • Class-Path, which allows you to specify what the classpath should be when the application is run.

There are keys specific to applets, to signed applications, to beans, and so forth. We will address these as it becomes necessary. Full details can, of course, be found in the Sun's documentation for jar.[27]

[27] http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/jar.html

5.11.1.2 Putting a Compiled Application in a JAR File

Let's assume we are going to manually put a Java application in a JAR file. We will want to specify the name of the class that contains the main() method of the application. First off, you want the JAR's directory hierarchy to begin at the folder that contains the first node of each package's name. Our sample application here is in the package net.multitool.Payback, so we want our present working directory to be the one which contains the net subdirectory. Here's a dump of the directory tree from that point after compilation of our sample application:

 $ find . -print . ./net ./net/multitool ./net/multitool/Payback ./net/multitool/Payback/Account.class ./net/multitool/Payback/Purchase.class ./net/multitool/Payback/Cost.class ./net/multitool/Payback/DebtAccount.class ./net/multitool/Payback/Payback.class ./net/multitool/Payback/SavingsAccount.class ./net/multitool/util ./net/multitool/util/SAMoney.class ./net/multitool/util/SAMoneyTest$1.class ./net/multitool/util/SAMoneyTest$2.class ./net/multitool/util/SAMoneyTest.class $ 

We now want to specify which class contains the application's main() method. It happens to be the Payback class, so we create a file called manifest[28] with the following contents:

[28] It can have any name. The key/value pairs from the file will be placed by the jar utility into the standard manifest called META-INF/MANIFEST.MF no matter what name you give to this file.

 $ cat manifest Main-Class: net.multitool.Payback.Payback 

Next, we use the jar utility to create the JAR file:

 $ jar cmf manifest payback.jar net $ ls -la total 20 drwxrwxr-x    3 mschwarz mschwarz    4096 Aug  4 18:19 . drwxrwxr-x    7 mschwarz mschwarz    4096 Aug  4 17:57 .. -rw-rw-r--    1 mschwarz mschwarz      43 Aug  4 18:17 manifest drwxrwxr-x    3 mschwarz mschwarz    4096 Jul 28 16:16 net -rw-rw-r--    1 mschwarz mschwarz    7506 Aug  4 18:21 payback.jar 

The options to jar tell it what to do. In our case, -c instructs to create a JAR file, -m adds the contents of the file named in the next parameter to the META-INF/MANIFEST file, -f and the next parameter is the filename of the JAR file being created. If we had not specified -f, the JAR file would have been written to standard out and an I/O redirect would be needed, but the result would have been the same:

 $ jar cvm manifest net > payback.jar $ ls -la total 24 drwxrwxr-x    3 mschwarz mschwarz    4096 Aug  4 18:24 . drwxrwxr-x    7 mschwarz mschwarz    4096 Aug  4 17:57 .. -rw-rw-r--    1 mschwarz mschwarz      43 Aug  4 18:17 manifest drwxrwxr-x    3 mschwarz mschwarz    4096 Jul 28 16:16 net -rw-rw-r--    1 mschwarz mschwarz    7506 Aug  4 18:27 payback.jar 

Everything that follows parameters required by option letters is considered to be a file or directory that is to be added to the JAR file. The option syntax for jar is similar to that for pkzip in the DOS/Windows world and the tar utility in the UNIX world.

As elsewhere in this chapter, we are just getting you started. See Sun's documentation for details.

5.11.2. Basic jar Operation

We have already covered the most common case, using jar to create a "rolled-up" Java application. jar has many command options besides -c and we'll document a few of them.

-c

Create a JAR file.

-u

Update a JAR filereplace updated files, add missing files.

-x

Extract files from a JAR file.

-t

List files in a JAR.

-f

Specify the JAR filename.

-v

Be verbosedisplay descriptions of what the jar utility is doing as it does it.

-m

Add the contents of the named file to the manifest.



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net