Download Extensions


Download Extensions

Download extensions are sets of classes (and related resources) in JAR files. A JAR file’s manifest can contain headers that refer to one or more download extensions. The extensions can be referenced in one of two ways:

  • by a Class-Path header

  • by an Extension-List header
Note that at most one of each is allowed in a manifest. Download extensions indicated by a Class-Path header are downloaded only for the lifetime of the application that downloads them, such as a web browser. Their advantage is that nothing is installed on the client; their disadvantage is that they are downloaded each time they are needed. Download extensions that are downloaded by an Extension-List header are installed into the /lib/ext directory of the JRE that downloads them. Their advantage is that they are downloaded the first time they’re needed; subsequently they can be used without downloading. But as shown later in this tutorial, they are more complex to deploy.

Since download extensions that use the Class-Path headers are simpler, lets consider them first. Assume for example that a.jar and b.jar are two JAR files in the same directory, and that the manifest of a.jar contains this header:


Class-Path: b.jar
Then the classes in b.jar serve as extension classes for purposes of the classes in a.jar. The classes in a.jar can invoke classes in b.jar without b.jar‘s classes having to be named on the class path. a.jar may or may not itself be an extension. If b.jar weren’t in the same directory as a.jar, then the value of the Class-Path header should be set to the relative pathname of b.jar.

There’s nothing special about the classes that are playing the role of a download extension. They are treated as extensions solely because they’re referenced by the manifest of some other JAR file.


To get a better understanding of how download extensions work, let’s create one and put it to use.


An Example


Suppose you want to create an applet that makes use of the RectangleArea class of the previous section:
public final class RectangleArea {
public static int area(java.awt.Rectangle r) {
return r.width * r.height;
}
}
In the previous section, you made the RectangleArea class into an installed extension by placing the JAR file containing it into the lib/ext directory of the JRE. By making it an installed extension, you enabled any application to use the RectangleArea class as if it were part of the Java platform.

If you want to be able to use the RectangleArea class from an applet, the situation is a little different. Suppose, for example, that you have an applet, AreaApplet, that makes use of class RectangleArea:


import java.applet.Applet;
import java.awt.*;

public class AreaApplet extends Applet {
Rectangle r;

public void init() {
int width = 10;
int height = 5;

r = new Rectangle(width, height);
}

public void paint(Graphics g) {
g.drawString(“The rectangle’s area is ”
+ RectangleArea.area(r), 10, 10);
}
}

This applet instantiates a 10 x 5 rectangle and then displays the rectangle’s area by using the RectangleArea.area method.

However, you can’t assume that everyone who downloads and uses your applet is going to have the RectangleArea class available on their system, as an installed extension or otherwise. One way around that problem is to make the RectangleArea class available from the server side, and you can do that by using it as a download extension.


To see how that’s done, let’s assume that you’ve bundled AreaApplet in a JAR file called AreaApplet.jar and that the class RectangleArea is bundled in RectangleArea.jar. In order for RectangleArea.jar to be treated as a download extension, RectangleArea.jar must be listed in the Class-Path header in AreaApplet.jar‘s manifest. AreaApplet.jar‘s manifest might look like this, for example:


Manifest-Version: 1.0
Class-Path: RectangleArea.jar
The value of the Class-Path header in this manifest is RectangleArea.jar with no path specified, indicating that RectangleArea.jar is located in the same directory as the applet’s JAR file.

More about the Class-Path Header


If an applet or application uses more than one extension, you can list multiple URLs in a manifest. For example, the following is a valid header:
Class-Path: area.jar servlet.jar images/
In the Class-Path header any URLs listed that don’t end with ‘/‘ are assumed to be JAR files. URLs ending in ‘/‘ indicate directories. In the preceding example, images/ might be a directory containing resources needed by the applet or the application.

Note that only one Class-Path header is allowed in a manifest file, and that each line in a manifest must be no more than 72 characters long. If you need to specify more class path entries than will fit on one line, you can extend them onto subsequent continuation lines. Begin each continuation line with two spaces. For example:


Class-Path: area.jar servlet.jar monitor.jar datasource.jar
provider.jar gui.jar
A future release may remove the limitation of having only one instance of each header, and of limiting lines to only 72 characters.

Download extensions can be “daisy chained”, meaning that the manifest of one download extension can have a Class-Path header that refers to a second extension, which can refer to a third extension, and so on.


Installing Download Extensions


In the above example, the extension downloaded by the applet is available only while the browser which loaded the applet is still running. However, applets can trigger installation of extensions, if additional information is included in the manifests of both the applet and the extension.

Since this mechanism extends the platform’s core API, its use should be judiciously applied. It is rarely appropriate for interfaces used by a single, or small set of applications. All visible symbols should follow reverse domain name and class hierarchy conventions.


The basic requirements are that both the applet and the extensions it uses provide version information in their manifests, and that they be signed. The version information allows Java Plug-in to ensure that the extension code has the version expected by the applet. For example, the AreaApplet could specify an areatest extension in its manifest:


Manifest-Version: 1.0
Extension-List: areatest
areatest-Extension-Name: area
areatest-Specification-Version: 1.1
areatest-Implementation-Version: 1.1.2
areatest-Implementation-Vendor-Id: com.sun
areatest-Implementation-URL: http://www.sun.com/test/area.jar
(Please note that there is no area.jar file at the above URL; this is just an example!) The manifest in area.jar would provide corresponding information:
Manifest-Version: 1.0
Extension-Name: area
Specification-Vendor: Sun Microsystems, Inc
Specification-Version: 1.1
Implementation-Vendor-Id: com.sun
Implementation-Vendor: Sun Microsystems, Inc
Implementation-Version: 1.1.2
Both the applet and the extension must be signed, by the same signer. Signing the jar files will modify them in-place, providing more information in their manifest files. Signing helps ensure that only trusted code gets installed. A simple way to sign jar files is to first create a keystore, and then use that to hold certificates for the applet and extension. For example:
keytool -genkey -dname “cn=Fred” -alias test -keypass mykeypass -storepass mystorepass -validity 180
Then the jar files can be signed:
jarsigner -storepass mystorepass -keypass mykeypass AreaApplet.jar test
jarsigner -storepass mystorepass -keypass mykeypass area.jar test
More information on keytool, jarsigner, and other security tools is at the Summary of Tools for the Java 2 Platform Security.

Here is AreaDemo.html, which loads the applet and causes the extension code to be downloaded and installed:


<html>
<body>
<applet code=”AreaApplet.class” archive=”AreaApplet.jar”/>
</body>
</html>
When the page is loaded for the first time, the user is told that the applet requires installation of the extension. A subsequent dialog informs the user about the signed applet. Accepting both installs the extension in the lib/ext folder of the JRE and runs the applet.

After restarting the web browser and load the same web page, only the dialog about the applet’s signer is presented, because area.jar is already installed. This is also true if AreaDemo.html is opened in a different web browser (assuming both browsers use the same JRE).

Installed Extensions

Installed Extensions

Installed extensions are JAR files in the lib/ext directory of the Java Runtime Environment (JRETM) software. As its name implies, the JRE is the runtime portion of the Java Development Kit containing the platform’s core API but without development tools such as compilers and debuggers. The JRE is available either by itself or as part of the Java Development Kit.

As of the Java 1.2 platform, the JRE is a strict subset of the JDKTM software. A subset of the JDK software directory tree looks like this:





The JRE consists of those directories within the highlighted box in the diagram. Whether your JRE is stand-alone or part of the JDK software, any JAR file in the lib/ext of the JRE directory is automatically treated by the runtime environment as an extension.


Since installed extensions extend the platform’s core API, use them judiciously. They are rarely appropriate for interfaces used by a single, or small set of applications.


Furthermore, since the symbols defined by installed extensions will be visible in all Java processes, care should be taken to ensure that all visible symbols follow the appropriate “reverse domain name” and “class hierarchy” conventions. For example, com.mycompany.MyClass.


As of Java 6, extension JAR files may also be placed in a location that is independent of any particular JRE, so that extensions can be shared by all JREs that are installed on a system. Prior to Java 6, the value of java.ext.dirs referred to a single directory, but as of Java 6 it is a list of directories (like CLASSPATH) that specifies the locations in which extensions are searched for. The first element of the path is always the lib/ext directory of the JRE. The second element is a directory outside of the JRE. This other location allows extension JAR files to be installed once and used by several JREs installed on that system. The location varies depending on the operating system:



  • SolarisTM Operating System: /usr/jdk/packages/lib/ext

  • Linux: /usr/java/packages/lib/ext

  • Microsoft Windows: %SystemRoot%\Sun\Java\lib\ext

Note that an installed extension placed in one of the above directories extends the platform of each of the JREs (Java 6 or later) on that system.



A Simple Example


Let’s create a simple installed extension. Our extension consists of one class, RectangleArea, that computes the areas of rectangles:
public final class RectangleArea {
public static int area(java.awt.Rectangle r) {
return r.width * r.height;
}
}
This class has a single method, area, that takes an instance of java.awt.Rectangle and returns the rectangle’s area.

Suppose that you want to test RectangleArea with an application called AreaApp:


import java.awt.*;

public class AreaApp {
public static void main(String[] args) {
int width = 10;
int height = 5;

Rectangle r = new Rectangle(width, height);
System.out.println(“The rectangle’s area is ”
+ RectangleArea.area(r));
}
}

This application instantiates a 10 x 5 rectangle, and then prints out the rectangle’s area using the RectangleArea.area method.


Running AreaApp Without the Extension Mechanism

Let’s first review how you would run the AreaApp application without using the extension mechanism. We’ll assume that the RectangleArea class is bundled in a JAR file named area.jar.

The RectangleArea class is not part of the Java platform, of course, so you would need to place the area.jar file on the class path in order to run AreaApp without getting a runtime exception. If area.jar was in the directory /home/user, for example, you could use this command:


java -classpath .:/home/user/area.jar AreaApp
The class path specified in this command contains both the current directory, containing AreaApp.class, and the path to the JAR file containing the RectangleArea package. You would get the desired output by running this command:
The rectangle’s area is 50


Running AreaApp by Using the Extension Mechanism

Now let’s look at how you would run AreaApp by using the RectangleArea class as an extension.

To make the RectangleArea class into an extension, you place the file area.jar in the lib/ext directory of the JRE. Doing so automatically gives the RectangleArea the status of being an installed extension.


With area.jar installed as an extension, you can run AreaApp without needing to specify the class path:


java AreaApp

Because you’re using area.jar as an installed extension, the runtime environment will be able to find and to load the RectangleArea class even though you haven’t specified it on the class path. Similarly, any applet or application being run by any user on your system would be able to find and use the RectangleArea class.


If there are multiple JREs (Java 6 or later) installed on a system and want the RectangleArea class to be available as an extension to all of them, instead of installing it in the lib/ext directory of a particular JRE, install it in the system-wide location. For example, on system running Linux, install area.jar in the directory /usr/java/packages/lib/ext. Then AreaApp can run using different JREs that are installed on that system, for example if different browsers are configured to use different JREs.


Java Archive (JAR) Files

JAR (Java Archive) is a platform-independent file format that aggregates many files into one. Multiple Java applets and their requisite components (.class files, images and sounds) can be bundled in a JAR file and subsequently downloaded to a browser in a single HTTP transaction, greatly improving the download speed. The JAR format also supports compression, which reduces the file size, further improving the download time. In addition, the applet author can digitally sign individual entries in a JAR file to authenticate their origin. It is fully extensible.


Overview and Specification



API Specification



Tutorials and Programmer’s Guides



Enhancements



  • Enhancements in JDKTM 6 – An annotated list of changes between the 5.0 and 6.0 releases to APIs, the jar command, and the jar/zip implementation.

Packaging Programs in JAR Files


Packaging Programs in JAR Files

The JavaTM Archive (JAR) file format enables you to bundle multiple files into a single archive file. Typically a JAR file contains the class files and auxiliary resources associated with applets and applications.

The JAR file format provides many benefits:



  • Security: You can digitally sign the contents of a JAR file. Users who recognize your signature can then optionally grant your software security privileges it wouldn’t otherwise have.

  • Decreased download time: If your applet is bundled in a JAR file, the applet’s class files and associated resources can be downloaded to a browser in a single HTTP transaction without the need for opening a new connection for each file.

  • Compression: The JAR format allows you to compress your files for efficient storage.

  • Packaging for extensions: The extensions framework provides a means by which you can add functionality to the Java core platform, and the JAR file format defines the packaging for extensions. Java 3D™ and JavaMail™ are examples of extensions developed by SunTM. By using the JAR file format, you can turn your software into extensions as well.

  • Package Sealing: Packages stored in JAR files can be optionally sealed so that the package can enforce version consistency. Sealing a package within a JAR file means that all classes defined in that package must be found in the same JAR file.

  • Package Versioning: A JAR file can hold data about the files it contains, such as vendor and version information.

  • Portability: The mechanism for handling JAR files is a standard part of the Java platform’s core API.

This lesson has four sections:


Using JAR Files: The Basics


This section shows you how to perform basic JAR-file operations, and how to run software that is bundled in JAR files.

Working with Manifest Files: The Basics


This section explains manifest files and how to customize them so you can do such things as seal packages and set an application’s entry point.

Signing and Verifying JAR Files


This section shows you how to digitally sign JAR files and verify the signatures of signed JAR files.

Using JAR-related APIs


This section introduces you to some of the JAR-handling features of the Java platform. The JAR file format is an important part of the Java platform’s extension mechanism. You can learn more about that aspect of JAR files in the The Extension Mechanism trail of this tutorial.

Additional References


The documentation for the Java Development Kit includes information about the Jar tool:

Jar and Zip Enhancements

 This page summarizes enhancements to the jar and zip support provided in JDK 6.

API changes


Two new compressed streams have been added:



  • java.util.zip.DeflaterInputStream: Data read from this stream is compressed.

  • java.util.zip.InflaterOutputStream: Data written to this stream is decompressed.
For example, these can be useful if a client wants to send compressed data over a network. The data can be compressed into packets with DeflaterInputStream, and those packets written over the network connection. The receiving end then reads the compressed packets from the network connection, and decompresses them by writing to an InflaterOutputStream.

Implementation changes


On all platforms, zip files can contain more than 64k entries.


On Windows, some limitations have been removed:



  • File names longer than 256 characters are now supported.

  • The limitation of just over 2,000 simultaneously open zip files has been removed.

Changes to the jar command


There are two changes to the behavior of the jar command:



  • The timestamps of extracted files are those listed in the archive, instead of the time of extraction.

  • When creating a jar, it is possible to specify the entry point for stand-alone applications bundled into an executable jar file. The ‘e’ option specifies the application entry point by creating or overriding the Main-Class attribute value in the jar file’s manifest.

JAR File Specification

Contents



Introduction

JAR file is a file format based on the popular ZIP file format and is used for aggregating many files into one. A  JAR file is essentially a zip file that contains an optional META-INF directory. A JAR file can be created by the command-line jar tool, or by using the  java.util.jar API in the Java platform. There is no restriction on the name of a JAR file, it can be any legal file name on a particular platform.

In many cases, JAR files are not just simple archives of java classes files and/or resources. They are used as building blocks for applications and extensions. The META-INF directory, if it exists, is used to store package and extension configuration data, including security, versioning, extension and services.


The META-INF directory

The following files/directories in the META-INF directory are recognized and interpreted by the Java 2 Platform to configure applications, extensions, class loaders and services:

  • MANIFEST.MF
The manifest file that is used to define extension and package related data.

  • INDEX.LIST
This file is generated by the new “-i” option of the jar tool, which contains location information for packages defined in an application or extension.  It is part of the JarIndex implementation and used by class loaders to speed up their class loading process.

  • x.SF
The signature file for the JAR file.  `x` stands for the base file name.

  • x.DSA
The signature block file associated with the signature file with the same base file name. This file stores the digital signature of the corresponding signature file.

  • services/
This directory stores all the service provider configuration files.

Name-Value pairs and Sections

Before we go to the details of the contents of the individual configuration files, some format convention needs to be defined. In most cases, information contained within the manifest file and signature files is represented as so-called “name: value” pairs inspired by the RFC822 standard.  We also call these pairs headers or attributes.

Groups of name-value pairs are known as a “section”. Sections are separated from other sections by empty lines.


Binary data of any form is represented as base64. Continuations are required for binary data which causes line length to exceed 72 bytes. Examples of binary data are digests and signatures.


Implementations shall support header values of up to 65535 bytes.


All the specifications in this document use the same grammar in which terminal symbols are shown in fixed width font and non-terminal symbols are shown in italic type face.


Specification:

  section:                       *header +newline
  nonempty-section:      +header +newline
  newline:                      CR LF | LF | CR (not followed by LF)
  header:                       name : value
  name:                         alphanum *headerchar
  value:                          SPACE *otherchar newline *continuation
  continuation:              SPACE *otherchar newline
  alphanum:                  {A-Z} | {a-z} | {0-9}
  headerchar:                alphanum | | _
  otherchar:                  any UTF-8 character except NUL, CR and LF

; Also: To prevent mangling of files sent via straight e-mail, no
; header will start with the four letters “From”.
 


Non-terminal symbols defined in the above specification will be referenced in the following specifications.


JAR Manifest


Overview

A JAR file manifest consists of a main section followed by a list of sections for individual JAR file entries, each separated by a newline. Both the main section and individual sections follow the section syntax specified above. They each have their own specific restrictions and rules.

The main section contains security and configuration information about the JAR file itself, as well as the application or extension that this JAR file is a part of. It also defines main attributes that apply to every individual manifest entry.  No attribute in this section can have its name equal to  “Name“. This section is terminated by an empty line.


The individual sections define various attributes for packages or files contained in this JAR file. Not all files in the JAR file need to be listed in the manifest as entries, but all files which are to be signed must be listed. The manifest file itself must not be listed.  Each section must start with an attribute with the name as “Name“, and the value must be a relative path to the file, or an absolute URL referencing data outside the archive.


If there are multiple individual sections for the same file entry, the attributes in these sections are merged. If a certain attribute have different values in different sections, the last one is recognized.


Attributes which are not understood are ignored. Such attributes may include implementation specific information used by applications.


Manifest Specification:

  manifest-file:                    main-section newline *individual-section
  main-section:                    version-info newline *main-attribute
  version-info:                      Manifest-Version : version-number
  version-number :               digit+{.digit+}*
  main-attribute:                 (any legitimate main attribute) newline
  individual-section:             Name : value newline *perentry-attribute
  perentry-attribute:            (any legitimate perentry attribute) newline
  newline :                            CR LF | LF | CR (not followed by LF)
   digit:                                {0-9} 

In the above specification, attributes that can appear in the main section are referred to as main attributes, whereas attributes that can appear in individual sections are referred to as per-entry attributes. Certain attributes can appear both in the main section and the individual sections, in which case the per-entry attribute value overrides the main attribute value for the specified entry. The two types of attributes are defined as follows.
 


Main Attributes

Main attributes are the attributes that are present in the main section of the manifest. They fall into the following different groups:

  • general main attributes




    • Manifest-Version:


    • Defines the manifest file version. The value is a legitimate version number, as described in the above spec.
       
    • Created-By:

    • Defines the version and the vendor of the java implementation on top of which this manifest file is generated. This attribute is generated by the jar tool.
       
    • Signature-Version:

    • Defines the signature version of the jar file. The value should be a valid version-number string.
       
    • Class-Path :

    • The value of this attribute specifies the relative URLs of the extensions or libraries that this application or extension needs. URLs are separated by one or more spaces. The application or extension class loader uses the value of this attribute to construct its internal search path.
       

  • attribute defined for stand-alone applications
  • This attribute is used by stand-alone applications that are bundled into executable jar files which can be invoked by the java runtime directly by running “java -jar x.jar“.

    • Main-Class :

    • The value of this attribute defines the relative path of the main application class which the launcher will load at startup time. The value must not have the .class extension appended to the class name.


  • attributes defined for applets
  • These attributes is used by an applet which is bundled into JAR files to define requirements, version and location information for the extensions which this applet depends on. (see  Extension Versioning ). 

    • Extension-List:

    • This attribute indicates the extensions that are needed by the applet. Each extension listed in this attribute will have a set of additional attributes that the applet uses to specify which version and vendor of the extension it requires.
       
    • <extension>-Extension-Name :

    • This attribute is the unique name of the extension. The Java Plug-in will compare the value of this attribute with the Extension-Name attribute in the manifests of installed extensions to determine if the extension is installed.
       
    • <extension>-Specification-Version

    • This attribute specifies the minimum extension specification version that is required by the applet. The Java Plug-in will compare the value of this attribute with the Specification-Version attribute of the installed extension to determine if the extension is up to date.
       
    • <extension>-Implementation-Version

    • This attritute specifies the minimum extension implementation version number that is required by the applet. The Java Plug-in will compare the value of this attribute with the Implementation-Version attribute of the installed extension to see if a more recent implementation needs to be downloaded.
       
    • <extension>-Implementation-Vendor-Id

    • This attribute can be used to identify the vendor of an extension implementation if the applet requires an implementation from a specific vendor. The Java Plug-in will compare the value of this attribute with the Implementation-Vendor-Id attribute of the installed extension.
       
    • <extension>-Implementation-URL

    • This attribute specifies a URL that can be used to obtain the most recent version of the extension if the required version is not already installed.
       

  • attribute defined for extension identification
  • This attribute is used by extensions to define their unique identity.

    • Extension-Name:
    • This attribute specifies a name for the extension contained in the Jar file. The name should be a unique identifier such as the name of the main package comprising the extension.
     
  • attributes defined for extension and  package versioning  and sealing information
  • These attributes define features of the extension which the JAR file is a part of. The value of these attributes apply to all the packages in the JAR file, but can be overridden by per-entry attributes. 

    • Implementation-Title :
    • The value is a string that defines the title of the extension implementation. 
    • Implementation-Version :

    • The value is a string that defines the version of the extension implementation.
       
    • Implementation-Vendor :

    • The value is a string that defines the organization that maintains the extension implementation.
       
    • Implementation-Vendor-Id :

    • The value is a string id that uniquely defines the organization that maintains the  extension implementation.
       
    • Implementation-URL :

    • This attribute defines the URL from which the extension implementation can be downloaded from.
       
    •  Specification-Title :

    • The value is a string that defines the title of the extension specification.
       
    • Specification-Version :

    • The value is a string that defines the version of the extension specification.
       
    • Specification-Vendor :

    • The value is a string that defines the organization that maintains the extension specification.



  • Sealed :

  • This attribute defines whether this JAR file is sealed or not. The value can be either “true” or “false”, case is ignored. If it is set to “true”, then all the packages in the JAR file are defaulted to be sealed, unless they are defined otherwise individually.

Per-Entry Attributes

Per-entry attributes apply only to the individual JAR file entry to which the manifest entry is associated with.  If the same attribute also appeared in the main section, then the value of the per-entry attribute overwrites the main attribute`s value. For example, if JAR file a.jar has the following manifest content:
Manifest-Version: 1.0
Created-By: 1.2 (Sun Microsystems Inc.)
Sealed: true

Name: foo/bar/
Sealed: false

It means that all the packages archived in a.jar are sealed, except that package foo.bar is not.

The per-entry attributes fall into the following groups:



  • attributes defined for file contents:


    • Content-Type :

    • This attribute can be used to specify the MIME type and subtype of data for a specific file entry in the JAR file. The value should be a string in the form of type/subtype. For example “image/bmp” is an image type with a subtype of bmp (representing bitmap). This would indicate the file entry as an image with the data stored as a bitmap. RFC 1521 and 1522 discuss and define the MIME types definition.


  • attributes defined for package versioning and sealing information:

  • These are the same set of attributes defined above as main attributes that defines the extension package versioning and sealing information. When used as per-entry attributes, these attributes overwrites the main attributes but only apply to the individual file specified by the manifest entry.
     


  • attribute defined for beans objects:


    • Java-Bean:

    • Defines whether the specific jar file entry is a Java Beans object or not. The value should be either “true” or “false”, case is ignored.
       

  • attributes defined for signing:

  • These attributes are used for signing and verifying purposes. More details here.

    • x-Digest-y:

    • The name of this attribute specifies the name of the digest algorithm used to compute the digest value for the corresponding jar file entry. The value of this attribute stores the actual digest value. The prefix `x` specifies the algorithm name and the optional suffix `y`  indicates to which language the digest value should be verified against.
    • Magic:

    • This is an optional attribute that can be used by applications to indicate how verifier should compute the digest value contained in the manifest entry.  The value of this attribute is a set of comma separated context specific strings. Detailed description is here.

Signed JAR File


Overview

A JAR file can be signed by using the command line jarsigner tool or directly through the java.security API. Every file entry, including non-signature related files in the META-INF directory, will be signed if the JAR file is signed by the jarsigner tool. The signature related files are:

  • META-INF/MANIFEST.MF
  • META-INF/*.SF
  • META-INF/*.DSA
  • META-INF/*.RSA
  • META-INF/SIG-*
Note that if such files are located in META-INF subdirectories, they are not considered signature-related. Case-insensitive versions of these filenames are reserved and will also not be signed.

Subsets of a JAR file can be signed by using the java.security API. A signed JAR file is exactly the same as the original JAR file, except that its manifest is updated and two additional files are added to the META-INF directory: a signature file and a signature block file. When jarsigner is not used, the signing program has to construct both the signature file and the signature block file.


For every file entry signed in the signed JAR file, an individual manifest entry is created for it as long as it does not already exist in the manifest. Each manifest entry lists one or more digest attribute and an optional Magic attribute.


Signature File

Each signer is represented by a signature file with extension .SF. The major part of the file is similar to the manifest file. It consists of a main section which includes information supplied by the signer but not specific to any particular jar file entry. The main section entry, x-Digest-Manifest-Main-Attributes (where x is a digest algorithm), contains the digest value for the main attributes of the manifest.

The main section is followed by a list of individual entries whose names must also be present in the manifest file. Each individual entry must contain at least the digest of its corresponding entry in the manifest file.


Paths or URLs appearing in the manifest file but not in the signature file are not used in the calculation.


Signature Validation

The signature over the signature file is first verified when the manifest is first parsed. For efficiency, this verification can be remembered. Note that this verification only validates the signature directions themselves, not the actual archive files.

The manifest main attributes are also verified when verification information is available in the signature file. If an x-Digest-Manifest-Main-Attributes entry exists in the signature file, it is compared against a digest calculated against the main attributes in the manifest file. If this calculation fails, then jar validation fails. This decision can be remembered, for efficiency. If an x-Digest-Manifest-Main-Attributes entry does not exist in the signature file, its nonexistence does not affect jar validation and the manifest main attributes are not verified.


To validate a file, a digest value in the signature file is compared against a digest calculated against the corresponding entry in the manifest file. Then, a digest value in the manifest file is compared against a digest calculated against the actual data referenced in the “Name:” attribute, which specifies either a relative file path or URL.


Example manifest file:


Manifest-Version: 1.0Created-By: 1.3 (Sun Microsystems, Inc) Name: common/class1.classMD5-Digest: (base64 representation of MD5 digest) Name: common/class2.classMD5-Digest: (base64 representation of MD5 digest)SHA-Digest: (base64 representation of SHA digest)
The corresponding signature file would be:
Signature-Version: 1.0MD5-Digest-Manifest-Main-Attributes: (base64 representation of MD5 digest) Name: common/class1.classMD5-Digest: (base64 representation of MD5 digest) Name: common/class2.classMD5-Digest: (base64 representation of MD5 digest)


The Magic Attribute

Another requirement to validate the signature on a given manifest entry is that the verifier understand the value or values of the Magic key-pair value in that entry`s manifest entry.

The Magic attribute is optional but it is required that a parser understand the value of an entry`s Magic key if it is verifying that entry`s signature.


The value or values of the Magic attribute are a set of comma-separated context-specific strings. The spaces before and after the commas are ignored. Case is ignored. The exact meaning of the magic attributes is application specific. These values indicate how to compute the hash value contained in the manifest entry, and are therefore crucial to the proper verification of the signature. The keywords may be used for dynamic or embedded content, multiple hashes for multilingual documents, etc.


Here are two examples of the potential use of Magic attribute in the manifest file:


               Name: http://www.scripts.com/index#script1
        SHA-Digest: (base64 representation of SHA hash)
        Magic: JavaScript, Dynamic


        Name: http://www.tourist.com/guide.html
        SHA-Digest: (base64 representation of SHA hash)
        SHA-Digest-French: (base64 representation of SHA hash)
        SHA-Digest-German: (base64 representation of SHA hash)
        Magic: Multilingual


In the first example, these Magic values may indicate that the result of an http query is the script embedded in the document, as opposed to the document itself, and also that the script is generated dynamically. These two pieces of information indicate how to compute the hash value against which to compare the manifest`s digest value, thus comparing a valid signature.


In the second example, the Magic value indicates that the document retrieved may have been content-negotiated for a specific language, and that the digest to verify against is dependent on which language the document retrieved is written in.


Digital Signatures

A digital signature is a signed version of the .SF signature file. These are binary files not intended to be interpreted by humans.

Digital signature files have the same filenames as the .SF files but different extensions. The extension varies depending on the type of digital signature.


.RSA      (PKCS7 signature, MD5 + RSA).DSA      (PKCS7 signature, DSA)
Digital signature files for signature algorithms not listed above must reside in the META-INF directory and have the prefix “SIG-“. The corresonding signature file (.SF file) must also have the same prefix.

For those formats that do not support external signed data, the file shall consist of a signed copy of the .SF file. Thus some data may be duplicated and a verifier should compare the two files.


Formats that support external data either reference the .SF file, or perform calculations on it with implicit reference.


Each .SF file may have multiple digital signatures, but those signatures should be generated by the same legal entity.


File name extensions may be 1 to 3 alphanum characters. Unrecognized extensions are ignored.


Notes on Manifest and Signature Files

Following is a list of additional restrictions and rules that apply to manifest and signature files.

  • Before parsing:

  • If the last character of the file is an EOF character (code 26), the EOF is treated as whitespace. Two newlines are appended (one for editors that don`t put a newline at the end of the last line, and one so that the grammar doesn`t have to special-case the last entry, which may not have a blank line after it).


  • Attributes:

  • In all cases for all sections, attributes which are not understood are ignored.

    Attribute names are case insensitive. Programs which generate manifest and signature files should use the cases shown in this specification however.


    Attribute names cannot be repeated within a section.



  • Versions:

  • Manifest-Version and Signature-Version must be first, and in exactly that case (so that they can be recognized easily as magic strings). Other than that, the order of attributes within a main section is not significant.
     
  • Ordering:

  • The order of individual manifest entries is not significant.

    The order of individual signature entries is not significant, except that the digests that get signed are in that order.



  • Line length:

  • No line may be longer than 72 bytes (not characters), in its UTF8-encoded form. If a value would make the initial line longer than this, it should be continued on extra lines (each starting with a single SPACE).
     
  • Errors:

  • If a file cannot be parsed according to this spec, a warning should be output, and none of the signatures should be trusted.
     
  • Limitations:

  • Because header names cannot be continued, the maximum length of a header name is 70 bytes (there must be a colon and a SPACE after the name).

    NUL, CR, and LF can`t be embedded in header values, and NUL, CR, LF and “:” can`t be embedded in header names.


    Implementations should support 65535-byte (not character) header values, and 65535 headers per file. They might run out of memory, but there should not be hard-coded limits below these values.



  • Signers:

  • It is technically possible that different entities may use different signing algorithms to share a single signature file. This violates the standard, and the extra signature may be ignored.


  • Algorithms:

  • No digest algorithm or signature algorithm is mandated by this standard. However, at least one of MD5 and SHA digest algorithm must be supported.

JAR Index


Overview

Since 1.3, JarIndex is introduced to optimize the class searching process of class loaders for network applications, especially applets. Originally, an applet class loader uses a simple linear search algorithm to search each element on its internal search path, which is constructed from the “ARCHIVE” tag or the “Class-Path” main attribute. The class loader downloads and opens each element in its search path, until the class or resource is found. If the class loader tries to find a nonexistent resource, then all the jar files within the application or applet will have to be downloaded. For large network applications and applets this could result in slow startup, sluggish response and wasted network bandwidth. The JarIndex mechanism collects the contents of all the jar files defined in an applet and stores the information in an index file in the first jar file on the applet`s class path. After the first jar file is downloaded, the applet class loader will use the collected content information for efficient downloading of jar files.

The existing jar tool is enhanced to be able to examine a list of jar files and generate directory information as to which classes and resources reside in which jar file. This directory information is stored in a simple text file named INDEX.LIST in the META-INF directory of the root jar file. When the classloader loads the root jar file,  it reads the INDEX.LIST file and uses it to construct a hash table of mappings from file and package names to lists of jar file names. In order to find a class or a resource, the class loader queries the hashtable to find the proper jar file and then downloads it if necessary.


Once the class loader finds a INDEX.LIST file in a particular jar file, it always trusts the information listed in it. If a mapping is found for a particular class, but the class loader fails to find it by following the link, an InvalidJarIndexException is thrown. When this occurs, the application developer should rerun the jar tool on the extension to get the right information into the index file.


To prevent adding too much space overhead to the application and to speed up the construction of the in-memory hash table, the INDEX.LIST file is kept as small as possible. For classes with non-null package names, mappings are recorded at the package level. Normally one package name is mapped to one jar file, but if a particular package spans more than one jar file, then the mapped value of this package will be a list of jar files. For resource files with non-empty directory prefixes, mappings are also recorded at the directory level.  Only for classes with null package name, and resource files which reside in the root directory, will the mapping be recorded at the individual file level.


Index File Specification

The INDEX.LIST file contains one or more sections each separated by a single blank line. Each section defines the content of a particular jar file, with a header defining the jar file path name, followed by a list of package or file names, one per line.  All the jar file paths are relative to the code base of the root jar file. These path names are resolved in the same way as the current extension mechanism does for bundled extensions.

The UTF-8 encoding is used to support non ASCII characters in file or package names in the index file.
 


Specification

    index file :                   version-info blankline section*
    version-info :              JarIndex-Version: version-number
    version-number :        digit+{.digit+}*
    section :                      body blankline
    body :                         header name*
    header :                      char+.jar newline
    name :                        char+ newline
    char :                          any valid Unicode character except NULL, CR andLF
    blankline:                    newline newline
    newline :                      CR LF | LF | CR (not followed by LF)
    digit:                           {0-9}
 
The INDEX.LIST file is generated by running jar -i. See the jar man page for more details.

Backward Compatibility

The new class loading scheme is totally backward compatible with applications developed on top of the current extension mechanism.  When the class loader loads the first jar file and an INDEX.LIST file is found in the META-INF directory, it would construct the index hash table and use the new loading scheme for the extension. Otherwise, the class loader will simply use the original linear search algorithm.

Service Provider


Overview

Files in the META-INF/services directory are service provider configuration files. A service is a well-known set of interfaces and (usually abstract) classes. A service provider is a specific implementation of a service. The classes in a provider typically implement the interfaces and subclass the classes defined in the service itself. Service providers may be installed in an implementation of the Java platform in the form of extensions, that is, jar files placed into any of the usual extension directories. Providers may also be made available by adding them to the applet or application class path or by some other platform-specific means.

A service is represented by an abstract class. A provider of a given service contains one or more concrete classes that extend this service class with data and code specific to the provider. This provider class will typically not be the entire provider itself but rather a proxy that contains enough information to decide whether the provider is able to satisfy a particular request together with code that can create the actual provider on demand. The details of provider classes tend to be highly service-specific; no single class or interface could possibly unify them, so no such class has been defined. The only requirement enforced here is that provider classes must have a zero-argument constructor so that they may be instantiated during lookup.
 


Provider-Configuration File

A service provider identifies itself by placing a provider-configuration file in the resource directory META-INF/services. The file`s name should consist of the fully-qualified name of the abstract service class. The file should contain a newline-separated list of unique concrete provider-class names. Space and tab characters, as well as blank lines, are ignored. The comment character is `#` (0x23); on each line all characters following the first comment character are ignored. The file must be encoded in UTF-8.
 

Example

Suppose we have a service class named java.io.spi.CharCodec. It has two abstract methods:

    public abstract CharEncoder getEncoder(String encodingName);
  public abstract CharDecoder getDecoder(String encodingName);


Each method returns an appropriate object or null if it cannot translate the given encoding. Typical CharCodec providers will support more than one encoding.


If sun.io.StandardCodec is a provider of the CharCodec service then its jar file would contain the file META-INF/services/java.io.spi.CharCodec. This file would contain the single line:


   sun.io.StandardCodec    # Standard codecs for the platform


To locate an encoder for a given encoding name, the internal I/O code would do something like this:


   CharEncoder getEncoder(String encodingName) {
       Iterator ps = Service.providers(CharCodec.class);
       while (ps.hasNext()) {
           CharCodec cc = (CharCodec)ps.next();
           CharEncoder ce = cc.getEncoder(encodingName);
           if (ce != null)
               return ce;
       }
       return null;
   }
 


The provider-lookup mechanism always executes in the security context of the caller. Trusted system code should typically invoke the methods in this class from within a privileged security context.


 


API Details

Package java.util.jar

See Also

Package java.security
Package java.util.zip


JAR File Overview


What is JAR?


JAR stands for Java ARchive. It`s a file format based on the popular ZIP file format and is used for aggregating many files into one. Although JAR can be used as a general archiving tool, the primary motivation for its development was so that Java applets and their requisite components (.class files, images and sounds) can be downloaded to a browser in a single HTTP transaction, rather than opening a new connection for each piece. This greatly improves the speed with which an applet can be loaded onto a web page and begin functioning. The JAR format also supports compression, which reduces the size of the file and improves download time still further. Additionally, individual entries in a JAR file may be digitally signed by the applet author to authenticate their origin.


JAR is:



  • the only archive format that is cross-platform
  • the only format that handles audio and image files as well as class files
  • backward-compatible with existing applet code
  • an open standard, fully extendable, and written in java
  • the preferred way to bundle the pieces of a java applet

JAR consists of a zip archive, as defined by PKWARE, containing a manifest file and potentially signature files, as defined in the JAR File Specification.


The APPLET tag


Changing the APPLET tag in your HTML page to accomodate a JAR file is simple. The JAR file on the server is identified by the ARCHIVE parameter, where the directory location of the jar file should be relative to the location of the html page:

    <applet code=Animator.class       archive=”jars/animator.jar”      width=460 height=160>      <param name=foo value=”bar”>    </applet>

Note that the familiar CODE=myApplet.class parameter must still be present. The CODE parameter, as always, identifies the name of the applet where execution begins. However, the class file for the applet and all of its helper classes are loaded from the JAR file.


Th ARCHIVE attribute describes one or more JAR files containing classes and other resources that will be “preloaded”. The classes are loaded using an instance of an AppletClassLoader with the given CODEBASE. It takes the form archive = archiveList. The archives in archiveList are separated by “,”.


Once the archive file is identified, it is downloaded and separated into its components. During the execution of the applet, when a new class, image or audio clip is requested by the applet, it is searched for first in the archives associated with the applet. If the file is not found amongst the archives that were downloaded, it is searched for on the applet`s server, relative to the CODEBASE (that is, it is searched for as in JDK1.0.2).


The archive tag may specify multiple JAR files. Each JAR file must be separated by “,” (comma). Each file is downloaded in turn:

    <applet code=Animator.class       archive=”classes.jar ,  images.jar ,  sounds.jar”      width=460 height=160>      <param name=foo value=”bar”>    </applet>

There can be any amount of white space between entries within the archive parameter. In addition, the archive tag itself is case-insensitive; it can be lower-case, upper-case, or any combination of lower- and upper-case letters, such as ArCHiVe.


Executable JAR Files


On Microsoft Windows systems, the Java 2 Runtime Environment`s installation program will register a default association for JAR files so that double-clicking a JAR file on the desktop will automatically run it with javaw -jar. Dependent extensions bundled with the application will also be loaded automatically. This feature makes the end-user runtime environment easier to use on Microsoft Windows systems.


The Solaris 2.6 kernel has already been extended to recognize the special “magic” number that identifies a JAR file, and to invoke java -jar on such a JAR file as if it were a native Solaris executable. A application packaged in a JAR file can thus be executed directly from the command line or by clicking an icon on the CDE desktop.


Using JAR-related APIs

Using JAR-related APIs

The JavaTM platform contains several classes for use with JAR files. Some of these APIs are:

To give you an idea of the possibilities that are opened up by these new APIs, this lesson guides you through the inner workings of a sample application called JarRunner.


An Example – The JarRunner Application


JarRunner enables you to run an application that’s bundled in a JAR file by specifying the JAR file’s URL on the command line. For example, if an application called TargetApp were bundled in a JAR file at http://www.xxx.yyy/TargetApp.jar, you could run the application using this command:
java JarRunner http://www.xxx.yyy/TargetApp.jar
In order for JarRunner to work, it must be able to perform the following tasks, all of which are accomplished by using the new APIs:

  • Access the remote JAR file and establish a communications link with it.

  • Inspect the JAR file’s manifest to see which of the classes in the archive is the main class.

  • Load the classes in the JAR file.

The JarRunner application consists of two classes, JarRunner and JarClassLoader. JarRunner delegates most of the JAR-handling tasks to the JarClassLoader class. JarClassLoader extends the java.net.URLClassLoader class. You can browse the source code for the JarRunner and JarClassLoader classes before proceeding with the lesson:



This lesson has two parts:


The JarClassLoader Class


This section shows you how JarClassLoader uses some of the new APIs to perform tasks required for the JarRunner application to work.

The JarRunner Class


This section summarizes the JarRunner class that comprises the JarRunner application.

The JarRunner Class


The JarRunner Class

The JarRunner application is launched with a command of this form:
java JarRunner url [arguments]
In the previous section, we’ve seen how JarClassLoader is able to identify and load the main class of a JAR-bundled application from a given URL. To complete the JarRunner application, therefore, we need to be able to take a URL and any arguments from the command line, and pass them to an instance of JarClassLoader. These tasks belong to the JarRunner class, the entry point of the JarRunner application.

It begins by creating a java.net.URL object from the URL specified on the command line:


public static void main(String[] args) {
if (args.length < 1) {
usage();
}
URL url = null;
try {
url = new URL(args[0]);
} catch (MalformedURLException e) {
fatal(“Invalid URL: ” + args[0]);
}

If args.length < 1, that means no URL was specified on the command line, so a usage message is printed. If the first command-line argument is a good URL, a new URL object is created to represent it.

Next, JarRunner creates a new instance of JarClassLoader, passing to the constructor the URL that was specified on the command-line:


JarClassLoader cl = new JarClassLoader(url);
As we saw in the previous section, it’s through JarClassLoader that JarRunner taps into the JAR-handling APIs.

The URL that’s passed to the JarClassLoader constructor is the URL of the JAR-bundled application that you want to run. JarRunner next calls the class loader’s getMainClassName method to identify the entry-point class for the application:


String name = null;
try {
name = cl.getMainClassName();
} catch (IOException e) {
System.err.println(“I/O error while loading JAR file:”);
e.printStackTrace();
System.exit(1);
}
if (name == null) {
fatal(“Specified jar file does not contain a ‘Main-Class'” +
” manifest attribute”);
}
The key statement is highlighted in bold. The other statements are for error handling.

Once JarRunner has identified the application’s entry-point class, only two steps remain: passing any arguments to the application and actually launching the application. JarRunner performs these steps with this code:


// Get arguments for the application
String[] newArgs = new String[args.length – 1];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
// Invoke application’s main class
try {
cl.invokeClass(name, newArgs);
} catch (ClassNotFoundException e) {
fatal(“Class not found: ” + name);
} catch (NoSuchMethodException e) {
fatal(“Class does not define a ‘main’ method: ” + name);
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
System.exit(1);
}
Recall that the first command-line argument was the URL of the JAR-bundled application. Any arguments to be passed to that application are therefore in element 1 and beyond in the args array. JarRunner takes those elements, and creates a new array called newArgs to pass to the application (bold line above). JarRunner then passes the entry-point’s class name and the new argument list to the invokeClass method of JarClassLoader. As we saw in the previous section, invokeClass will load the application’s entry-point class, pass it any arguments, and launch the application.

The JarClassLoader Class

The JarClassLoader Class

The JarClassLoader class extends java.net.URLClassLoader. As its name implies, URLClassLoader is designed to be used for loading classes and resources that are accessed by searching a set of URLs. The URLs can refer either to directories or to JAR files.

In addition to subclassing URLClassLoader, JarClassLoader also makes use of features in two other new JAR-related APIs, the java.util.jar package and the java.net.JarURLConnection class. In this section, we’ll look in detail at the constructor and two methods of JarClassLoader.


The JarClassLoader Constructor


The constructor takes an instance of java.net.URL as an argument. The URL passed to this constructor will be used elsewhere in JarClassLoader to find the JAR file from which classes are to be loaded.
public JarClassLoader(URL url) {
super(new URL[] { url });
this.url = url;
}
The URL object is passed to the constructor of the superclass, URLClassLoader, which takes a URL[] array, rather than a single URL instance, as an argument.

The getMainClassName Method


Once a JarClassLoader object is constructed with the URL of a JAR-bundled application, it’s going to need a way to determine which class in the JAR file is the application’s entry point. That’s the job of the getMainClassName method:
public String getMainClassName() throws IOException {
URL u = new URL(“jar”, “”, url + “!/”);
JarURLConnection uc = (JarURLConnection)u.openConnection();
Attributes attr = uc.getMainAttributes();
return attr != null
? attr.getValue(Attributes.Name.MAIN_CLASS)
: null;
}
You may recall from a previous lesson that a JAR-bundled application’s entry point is specified by the Main-Class header of the JAR file’s manifest. To understand how getMainClassName accesses the Main-Class header value, let’s look at the method in detail, paying special attention to the new JAR-handling features that it uses:

The JarURLConnection class and JAR URLs

The getMainClassName method uses the JAR URL format specified by the java.net.JarURLConnection class. The syntax for the URL of a JAR file is as in this example:
jar:http://www.xxx.yyy/jarfile.jar!/
The terminating !/ separator indicates that the URL refers to an entire JAR file. Anything following the separator refers to specific JAR-file contents, as in this example:
jar:http://www.xxx.yyy/jarfile.jar!/mypackage/myclass.class

The first line in the getMainClassName method is:


URL u = new URL(“jar”, “”, url + “!/”);
This statement constructs a new URL object representing a JAR URL, appending the !/ separator to the URL that was used in creating the JarClassLoader instance.


The java.net.JarURLConnection class

This class represents a communications link between an application and a JAR file. It has methods for accessing the JAR file’s manifest. The second line of getMainClassName is:
JarURLConnection uc = (JarURLConnection)u.openConnection();
In this statement, URL instance created in the first line opens a URLConnection. The URLConnection instance is then cast to JarURLConnection so it can take advantage of JarURLConnection‘s JAR-handling features.

Fetching Manifest Attributes: java.util.jar.Attributes

With a JarURLConnection open to a JAR file, you can access the header information in the JAR file’s manifest by using the getMainAttributes method of JarURLConnection. This method returns an instance of java.util.jar.Attributes, a class that maps header names in JAR-file manifests with their associated string values. The third line in getMainClassName creates an Attributes object:
Attributes attr = uc.getMainAttributes();

To get the value of the manifest’s Main-Class header, the fourth line of getMainClassName invokes the Attributes.getValue method:


return attr != null
? attr.getValue(Attributes.Name.MAIN_CLASS)
: null;

The method’s argument, Attributes.Name.MAIN_CLASS, specifies that it’s the value of the Main-Class header that you want. (The Attributes.Name class also provides static fields such as MANIFEST_VERSION, CLASS_PATH, and SEALED for specifying other standard manifest headers.)

The invokeClass Method


We’ve seen how JarURLClassLoader can identify the main class in a JAR-bundled application. The last method to consider, JarURLClassLoader.invokeClass, enables that main class to be invoked to launch the JAR-bundled application:
public void invokeClass(String name, String[] args)
throws ClassNotFoundException,
NoSuchMethodException,
InvocationTargetException
{
Class c = loadClass(name);
Method m = c.getMethod(“main”, new Class[] { args.getClass() });
m.setAccessible(true);
int mods = m.getModifiers();
if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
!Modifier.isPublic(mods)) {
throw new NoSuchMethodException(“main”);
}
try {
m.invoke(null, new Object[] { args });
} catch (IllegalAccessException e) {
// This should not happen, as we have disabled access checks
}
}

The invokeClass method takes two arguments: the name of the application’s entry-point class and an array of string arguments to pass to the entry-point class’s main method. First, the main class is loaded:


Class c = loadClass(name);
The loadClass method is inherited from java.lang.ClassLoader.


Once the main class is loaded, the reflection API of the java.lang.reflect package is used to pass the arguments to the class and launch it. You can refer to the tutorial on The Reflection API for a review of reflection.