Java Tip 120: Execute self-extracting JARs

Create easy-to-use, cross-platform Java Archives

For many years, Phil Katz’s archive creation, zip, has been one of the most popular file archiving formats. Sun has adopted the zip format as the basis for the Java Archive (JAR). Sun has extended the zip format’s use with various conventions so that you can pack Java classes into an archive file. With the addition of the JAR manifest file, the Java runtime can easily locate and directly execute the main class of the Java application contained in the jar file.

Some zip utility tools can create self-extracting archives for various platforms, such as MS Windows. The utility tool combines a regular zip archive with an extractor program to generate a new executable (exe) file. Receivers of the exe file only need to run it to extract the original zip archive’s contents. The executable runs the extractor program to extract the archived files into a user-specified output directory.

You can convert a base zip or jar file into an executable jar file on any Java platform. Whereas the self-extracting zip can only create platform-specific executables, the self-extracting jar file can be distributed to and run on any platform supporting Java.

Creating the self-extracting jar file is straightforward. You just need a special JAR manifest file, a Java-based extraction program, the zip or jar file containing the base content files, and any Java SDK’s jar utility application.

The manifest file

To make executable JARs, you first need a manifest file called MANIFEST.MF in the META-INF directory. The manifest file may contain a number of possible entries; however, for our purposes here, we just need to specify the name of the Java class that contains the Java-based extractor program’s main() method:

Main-Class: ZipSelfExtractor

We’ve added a manifest file named jarmanifest to this tip’s example code. For more information about the manifest file, see the Jar File Specification.

The extractor

You can make the extractor program using various approaches. The approach we present here is simple and straightforward. First, the extraction program figures out the self-extracting jar file’s name. With that name in hand, the extractor utilizes the standard, built-in Java zip/jar libraries to extract the content files from the archive. You can find the full source code for ZipSelfExtractor in ZipSelfExtractor.java.

Getting the jar filename in the extractor program can be tricky. Although the jar file’s name appears on the command line, that name is not passed to the class’s main() method. Therefore, in the extractor program, we use the following code to extract the information from the URL that points to the extractor:

    private String getJarFileName ()
    {
      myClassName = this.getClass().getName() + ".class";
      URL urlJar =
          this.getClass().getClassLoader().getSystemResource(myClassName);
      String urlStr = urlJar.toString();
      int from = "jar:file:".length();
      int to = urlStr.indexOf("!/");
      return urlStr.substring(from, to);
    }

Notice that in the getSystemResource() method we pass myClassName instead of ZipSelfExtractor.class. That lets us change the extractor program name without changing that part of the code. We set myClassName by looking up the current class’s name.

Next, we extract the jar file’s name. First, we ask for a URL to the class file containing the currently running class (which is the extractor program). Once we have the URL, we can snip out the jar file’s name. By definition, the URL of the JAR extractor program follows the basic format:

  1. jar:, which shows that the executable runs from inside a jar file
  2. The jar file’s URL, such as file:/C:/temp/test.jar, followed by the ! character
  3. The internal path name of the file within the JAR, such as /ZipSelfExtractor.class

In the extractor program’s case, the URL might look like:

jar:file:/home/johnm/test/zipper.jar!/ZipSelfExtractor.class

Now that we have the jar file’s name, we can perform the extraction. The guts of the extraction program rely on the built-in, Java zip/jar file manipulation libraries to uncompress the content files contained in the archive. See Resources for more on the zip/jar file manipulation libraries.

For ease of use, the extractor is a graphical Java application. The application uses the JFileChooser class to let users specify the destination directory to which they want the files extracted. A ProgressMonitor shows the progress of the extraction process. If a file might overwrite an already existing file, the user is asked whether or not to overwrite the existing file. At the conclusion, a standard dialog box presents extraction statistics.

Finally, the extractor program checks that it does not extract the files that make the jar file self-extracting — the manifest file and the extractor’s .class file; the program should just extract the original JAR contents. Those two files are artifacts of the self-extracting jar file and not part of the original, base content files.

Packing the jar file

Now that we have the manifest file and the extractor program, we can build the self-extracting jar file. We can manually use the JDK’s jar utility to make a self-extracting jar file. For example, assuming you have a zip file called myzip.zip, you can perform the following steps to make a self-extracting file from it:

  1. cd to the directory containing myzip.zip
  2. Download zipper.jar
  3. Extract the files into the current directory. We’ve made it a self-extracting JAR:
    java -jar zipper.jar
    
  4. Copy the zipper.class file to ZipSelfExtractor.class
  5. Rename myzip.zip as myzip.jar
  6. Update myzip.jar with the jarmanifest and ZipSelfExtractor.class files:
    jar uvfm myzip.jar jarmanifest ZipSelfExtractor.class
    

Now myzip.jar is self-extracting on all platforms containing Java Runtime Environment (JRE) 1.2 or later. To execute the self-extracting jar file, run:

java -jar myzip.jar

Note that some platforms may have bindings already set up such that you can execute the jar file just by clicking on the myzip.jar file icon, which will run the command line equivalent.

Exercise for the reader

The current ZipSelfExtract does not integrate well if you make a self-extracting JAR out of an existing jar file containing a manifest file. Add intelligence to the self-extractor and the creation instructions so you can deal with existing jar files that contain manifest files.

Free your hand from the JAR

A self-extracting jar file is a good mechanism for cross-platform file distribution. Self-extracting JARs are easy to create, and the minimal user requirement of a JRE 1.2 or later installation is a reasonable tradeoff for gaining cross-platform support.

Instead of manually creating the self-extracting jar file, check out ZipAnywhere. ZipAnywhere is a full-featured zip/jar utility tool written in 100% pure Java. It is a free GUI-based tool a la WinZip and can create self-extracting jar files with the click of a button.

Dr. Zunhe Steve Jin is a
staff software engineer at Rational Software and the author of ZipAnywhere.

John D. Mitchell is the
contributing editor of the JavaWorld Tips ‘N
Tricks column. John is also the founder and chief
architect of Non, Inc., a
Technological Business Risk Management consulting practice.

Source: www.infoworld.com