A Java Package

By Sean C. Sullivan

Understanding Microsoft's Java Package Manager

The Java Package Manager (JPM) is a feature of the Microsoft Virtual Machine (VM) for Java. The JPM handles package management and installation for the VM, and acts as a storage database for Java packages and the classes they contain. Java developers will directly benefit from the JPM's application namespaces, package versioning, code download services, and standardized security services.

The Problem with CLASSPATHs

In Sun's implementation of Java, the Sun VM uses the CLASSPATH environment variable to find Java classes. The classpath is simply a list of directories and file archives that the VM searches when it needs to load a Java class file. There are some fundamental problems associated with the classpath scheme:

All applications typically share the same classpath. All installed packages are visible to all applications. This can lead to namespace collisions.

All packages on the classpath are fully trusted. This can lead to security issues because every package has unrestricted access to the system.

Installing a new package usually requires modification to the CLASSPATH environment variable. This means that you must reboot the system before the classpath change will take effect.

The classpath approach does not explicitly support package versioning.

The JPM addresses each of these problems.

Java Package Manager Features

The primary features of the JPM are:

Version control. The JPM database keeps a version number for each installed package. This enables installation programs to selectively update and install new packages only when needed.

Namespaces. Packages can be stored in either the global (system) namespace, or in a private application (non-system) namespace. Packages in the global namespace are accessible to all Java programs running on the Microsoft VM. Application namespaces prevent name collisions because they allow certain packages to be isolated from the standard system packages.

Improved security. Packages are no longer implicitly trusted with full system access. Each installed package has specific capabilities ("permissions") associated with it.

Ease of Use. When packages are installed, there is no need to update the CLASSPATH environment variable. As a result, there is no need to reboot the system.

The Software You Need

Before jumping into the technical details of the JPM, you will want to install the following software:

Microsoft Internet Explorer 4.0 (or later)

Microsoft SDK for Java 2.0 (or later)

The JPM is supported by the VM included in Internet Explorer 4.x (IE4). Older versions of IE don't include support for the JPM; you must install IE4 to use the JPM.

The SDK for Java contains the command-line tools for packaging and signing class files. The SDK also includes documentation for the JPM and its associated command-line tools. The command-line tools are explained later in this article.

Package Versioning

The JPM stores a version number for every Java package in the JPM database. Package version numbers have the same form as a Win32 EXE version number. The version number is composed of four comma-separated numbers, e.g. 1,3,0,17.

By tracking version numbers, the JPM database can prevent packages from being downgraded. Downgrading occurs when an out-of-date software component is installed over a more recent software component. Before the JPM, applications that installed classes onto the classpath could accidentally downgrade packages present on the user's system.

Namespaces

As an application developer, you can install your packages into the global namespace, or a private application namespace. Application namespaces allow certain application-specific packages to be isolated from other packages on the system. For example, suppose you created a namespace called mynamespace. Packages in mynamespace are visible only to programs running in that namespace.

There are two ways to run a Java program in an application namespace. To run a Java applet in the application namespace called mynamespace, you must add a namespace parameter to the <APPLET> tag on your Web page:

<PARAM NAME=namespace VALUE="mynamespace">

To run a Java application in an application namespace, you must pass the -n option to the JVIEW command:

jview -n "mynamespace" com.foobar.MyApp param1 param2

The JPM supports a global namespace, which is functionally different from an application namespace. Packages in the global namespace are visible to all Java programs at all times. With IE4, all system packages (java.awt, java.io, java.lang, com.ms.directx, etc.) are installed into the JPM's global namespace. In contrast, IE3 stored all system packages in %WINDIR%\JAVA\CLASSES\CLASSES.ZIP.

Java Package Manager and Security

In Sun's VM, packages that are installed locally on the classpath are implicitly granted unrestricted access to the system. Microsoft's JPM provides a better approach. Instead of granting unrestricted access to packages, the JPM requires that each package explicitly define the set of privileges it needs. Thus, a package will only be granted access to resources outside the sandbox if the package has been authorized with the necessary permissions.

The act of associating security permissions with a Java package is known as Java signing. There are two types of Java signing permissions: default permission levels, and custom permissions.

Default Permission Levels

The default permission levels are High, Medium, and Low:

High. Packages signed with the High permission level are restricted to the Java security sandbox. This permission level grants the same level of access that an untrusted Java applet would have. The code cannot perform I/O on the local file system. Additionally, the code can open network connections only to the host from which the code originated.

Medium. Packages signed with the Medium permission level are allowed to perform a few operations outside the sandbox. The code can use Microsoft's client storage API to store up to 1MB of data in a "scratch space" directory on the client computer. Also, the code can initiate user-directed file I/O. The user-directed I/O functions will prompt the user before allowing the operation to take place.

Low. Packages signed with the Low permission level are fully trusted. They can perform any operation, including file I/O, network I/O, and modification of Java system properties.

Use the SIGNCODE utility to sign distribution units with a permission level. The signing syntax is explained later in this article.

Custom Java Permissions

Custom permissions are a set of operations that you, the developer, define for your package. You typically only need to use custom permissions when the default permission levels (High, Medium, and Low) don't meet your needs. For example, you may write code that can run in the sandbox except that it needs to read and write C:\SOMEFILE.txt. To accommodate this, you would define custom file I/O permissions that allow access to the text file.

Custom permissions are specified in an .INI file. The .INI file is simply a text file that you can view with any text editor. The permissions .INI file may be created by hand, or with Microsoft's PINIEDIT utility. PINIEDIT is a graphical tool that allows you to interactively create the .INI file. The .INI file contains a section for each permission type. For example, this section allows the read-write permission on C:\SOMEFILE.txt:

[com.ms.security.permissions.FileIOPermission]
IncludeRead=c:\\somefile.txt
ExcludeRead=
IncludeWrite=c:\\somefile.txt
ExcludeWrite=
IncludeDelete=
ExcludeDelete=
ReadFileURLCodebase=true
...

For more information about PINIEDIT, read the documentation in the Microsoft SDK for Java.

Distribution Units and OSD Files

To install a Java package into the JPM database, you must first store your package in a distribution unit (DU). A distribution unit is simply a cabinet file. Distribution units have a .CAB file extension. Every distribution unit contains an OSD (Open Software Description) file. OSD is an XML-based specification for describing software components, version information, and the relationships and dependencies between components. An OSD file might look like this:

<?XML version="1.0"?>
<!DOCTYPE SOFTPKG SYSTEM
  "http://www.microsoft.com/standards/osd/osd.dtd">
<?XML::namespace
  href="http://www.microsoft.com/standards/osd/msicd.dtd"
  as="MSICD"?>

<SOFTPKG NAME="Fish game" VERSION="1,0,0,17">
<!-- created by DUBuild version 4.79.2252 -->

  <TITLE>Fish game</TITLE>

  <MSICD::JAVA>

    <NAMESPACE>Fun and games</NAMESPACE>

    <PACKAGE NAME="com.foobar.fishgame" VERSION="1,0,0,17">
      <IMPLEMENTATION/>
    </PACKAGE>

  </MSICD::JAVA>

</SOFTPKG>

The <MSICD::JAVA> and <PACKAGE> tags indicate that the distribution unit contains a Java package. The package's class files are stored in the distribution unit along with the OSD file.

There are three fundamental tasks associated with distribution units:

creating a distribution unit;

signing a distribution unit; and

testing a signed distribution unit.

These tasks are explained in the next three sections.

Creating a Distribution Unit

You create distribution units with Microsoft's DUBUILD utility. After you install the Microsoft SDK for Java, you will find DUBUILD in the C:\SDK-JAVA.20\BIN\PACKSIGN directory. DUBUILD is a command-line utility that provides three main functions:

creating OSD files and distribution units;

creating split distribution units; and

packaging a JavaBean as an ActiveX control.

Suppose you have a package named com.foobar.fishgame. The package contains five classes: Fish, FishingRod, Worm, Fishtank, and FishGameApplet. The goal is to create a distribution unit for the package. The package will be stored in a private application namespace called Fun and games. To create the distribution unit, you would run this command:

dubuild fishgame.cab .
  /D "Fish game"
  /N "Fun and games"
  /I *.class
  /V 1,0,0,17

The resulting distribution unit contains six files:

Fish game.osd

com\foobar\fishgame\FishGameApplet.class

com\foobar\fishgame\Fishtank.class

com\foobar\fishgame\Worm.class

com\foobar\fishgame\FishingRod.class

com\foobar\fishgame\Fish.class

Notice that the DUBUILD utility automatically created the Fish game.osd file. A summary of DUBUILD's command-line options is listed in Figure 1.

Option Description
/H or /? Displays help text.
/D "friendlyname" Specifies the distribution unit's friendly name.
/P oldDUname.cab Specifies the file name of a previous version of the distribution unit.
/M Create a multi-CAB distribution unit.
/I {pattern} Include all files that match {pattern}.
/X {pattern} Exclude all files that match {pattern}.
/N "namespace" Specifies the namespace for the distribution unit. This is optional. If omitted, the package will be installed into the global (system) namespace.
/B {beaninfo} Provides ActiveX registration information about each JavaBean from the package. Use this option if your package contains a JavaBean you need to register as an ActiveX control.
/S {pattern} Each package that matches the pattern is marked as a system package.
/V version Specifies a version number for the VD, VP, and VN options. The version number must take the form: A, B, C, D.
/VD version Specifies the minimum version number for the distribution unit.
/VP version Specifies the minimum version number for the packages in the distribution unit.
/VN version Specifies the minimum version number for new packages in the distribution unit. (This option should be used when creating split distribution units.)
/Z Build the distribution unit with MSZIP compatibility. This is useful when you need the CAB file to be compatible with IE3. If this option is omitted, DUBUILD defaults to LZX compression.

Figure 1: DUBUILD's command-line options.

You can use Microsoft's CABARC utility to view the contents of the distribution unit. The following command lists the contents of fishgame.cab:

cabarc L fishgame.cab

Signing a Distribution Unit

You assign Java permissions to a Java package by signing a distribution unit with the SIGNCODE utility. The process of signing a distribution unit with permissions is known as Java signing. As mentioned earlier, Java signing supports different permission levels. You can sign a distribution unit with High, Medium, Low, or custom permissions.

The basic steps for signing a distribution unit are:

obtain a certificate and a private key from a certificate authority (such as VeriSign);

create the distribution unit using DUBUILD;

decide the type of permission that you want to sign with: High, Medium, Low, or custom;

if you want to sign with custom permissions, create a permissions .INI file using Microsoft's PINIEDIT utility; and

sign the distribution unit with Microsoft's SIGNCODE utility.

A certificate is an electronic statement that identifies a person or entity. Using a certificate and a private key, you digitally sign the distribution unit. SIGNCODE generates a digital signature for the distribution unit. The digital signature identifies the creator of the distribution unit. IE4 uses the digital signature to verify the authenticity of the distribution unit.

If you plan to distribute your Java packages over the Internet, you will want to purchase a certificate from VeriSign (http://www.versign.com). For your internal development and testing, however, you can create test certificates using Microsoft's MAKECERT and CERT2SPC utilities. MAKECERT creates X.509 certificates, and CERT2SPC converts the X.509 certificate into a Microsoft Software Publisher Certificate.

You'll find detailed documentation for MAKECERT and CERT2SPC in Microsoft's SDK for Java.

Using SIGNCODE to sign the distribution unit. When you sign your distribution unit, you are assigning a set of permissions for the Java packages in the distribution unit. To sign a distribution unit with Java permissions, you must pass JAVASIGN.DLL as a parameter to SIGNCODE. JAVASIGN.DLL is required. If you omit JAVASIGN.DLL, SIGNCODE will default to ActiveX signing permissions, which are not compatible with the JPM.

The following example signs fishgame.cab with a set of custom permissions. The permissions are stored in the file rem.ini:

signcode -j javasign.dll  -jp perm.ini
-t http://timestamp.verisign.com/scripts/timstamp.dll
-spc cert.spc -v privatekey.pvk fishgame.cab

You can obtain additional information about SIGNCODE in the Microsoft SDK for Java documentation.

Testing a Signed Distribution Unit

After signing the distribution unit, you can use the CHKJAVA utility to check the permissions on a signed cabinet file:

chkjava fishgame.cab

The CHKJAVA command operates similarly to Microsoft's CHKTRUST command for ActiveX controls.

Installing a Java Package from the Web

To install a Java package from the Web, you must author your Web page with the correct <APPLET> parameters. IE 4 introduces four new <APPLET> parameters:

useslibrary specifies a name for the distribution unit.

useslibrarycodebase specifies the codebase for the distribution unit CAB file.

useslibraryversion specifies the version number of the distribution unit.

namespace is an optional parameter that specifies a namespace for the applet. The applet will execute in the given namespace.

When IE4 encounters the <APPLET> tag on a Web page, it checks for these four parameters. The browser uses these parameters to determine whether to download and install the distribution unit. A typical <APPLET> tag looks like this:

<APPLET CODE=com.foobar.fishgame.FishGameApplet
        WIDTH=400 HEIGHT=400>
  <PARAM NAME=useslibrary VALUE="Fish game">
  <PARAM NAME=useslibrarycodebase VALUE="fishgame.cab">
  <PARAM NAME=useslibraryversion VALUE="1,0,0,17">
  <PARAM NAME=namespace VALUE="Fun and games">
</APPLET>

After installation, the class files are permanently stored in the JPM database. The only time the browser will fetch classes from the Web server is if the package version changes. Note that IE3 and Netscape Navigator will ignore these <APPLET> parameters.

Getting a List of Installed Packages

To get a list of packages in the JPM database, you can use the CLSPACK command-line utility. CLSPACK provides a way to list and extract packages from the database. When you extract packages, they are stored in an uncompressed ZIP archive. The extracted ZIP file is useful when you need to use the packages with other third-party Java development tools.

The CLSPACK command-line options are listed in Figure 2. For more information on CLSPACK, see the documentation in the Microsoft SDK for Java.

Option Description Example Usage
-auto Automatically generate a ZIP file containing all system classes in the JPM. The resulting ZIP file is named CLASSES.ZIP and is located in %WINDIR%\Java\Classes. (Note: By default, this command skips all non-system classes.) clspack -auto
-dump Writes a list of all system packages to filename.txt. (Note: By default, this command skips all non-system classes.) clspack -dump filename.txt
-nonsystem Generates a ZIP file containing all non-system classes in the JPM. The resulting ZIP file is named NONSYSTM.ZIP and is located in %WINDIR%\java\trustlib. clspack -nonsystem

Figure 2: CLSPACK's command-line options.

How the Microsoft VM Locates Java Classes

Unlike Sun's VM, the Microsoft VM doesn't rely exclusively on the CLASSPATH environment variable to locate Java class files. Instead, it uses a multi-step search algorithm:

Check the explicitly specified classpath. Applications that are launched with JVIEW can explicitly specify a classpath on the command line by using the /cp option.

Search the packages contained in the JPM database.

Check the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\TrustedClasspath registry value. (Note: This step is ignored when an untrusted applet is running.)

Check the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\TrustedLibsDirectory registry value. (Note: This step is ignored when an untrusted applet is running.)

Check the HKEY_LOCAL_MACHINE\SOFTWARE\Java VM\Classpath registry value.

Check the HKEY_LOCAL_MACHINE\SOFTWARE\Java VM\LibsDirectory registry value.

Check the locations specified by the CLASSPATH environment variable.

When code is served from a Web page, the VM also searches the following locations: any cabinet files referenced by the applet's cabinets parameter; any cabinet file referenced by the applet's cabbase parameter; and any ZIP or JAR file referenced by the archive attribute in the <APPLET> tag.

Check for classes relative to the applet's code base.

Notice that the Microsoft VM searches the JPM database (step 2) before searching the CLASSPATH environment variable (step 7).

Cross-platform Issues

The Microsoft VM is available on multiple platforms: Windows 95, Windows NT, Windows CE, Windows 3.1, Macintosh, and Solaris. However, the JPM technology is not supported on all these platforms (see Figure 3).

Platform JPM
IE4 for Windows 95 Yes
IE4 for Windows NT 4.0 Yes
IE4 for Windows 3.1 (Win16 JVM) No
IE4 for the Macintosh No
IE4 for Solaris No
Windows CE Java VM No

Figure 3: Who supports JPM.

Java Package Manager: Under the Hood

When a package is installed, the JPM extracts the OSD file and the class files from the distribution unit. The OSD file is copied into the %WINDIR%\Downloaded Program Files directory. The package class files are stored in ZIP files in the %WINDIR%\java\packages directory.

The JPM uses the Win32 registry to keep track of which packages are installed as well as their version numbers. During package installation, the JPM updates registry keys in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database. The Code Store Database branch contains these subkeys:

Application namespaces

Distribution units

Global namespace

To view the registry keys, run REGEDIT.EXE and navigate down to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database. In general, you should never edit these keys by hand. However, it is beneficial to view the keys to get a better understanding of how the JPM stores your packages.

Conclusion

The JPM is a feature of the Microsoft VM. The JPM handles package management and installation for the VM. The JPM acts as a storage database for Java packages and the classes they contain. Java developers will directly benefit from the JPM's application namespaces, package versioning, code download services, and standardized security services. For more detailed information about the JPM, see documentation in Microsoft's SDK for Java.

Additional Resources

Microsoft SDK for Java: http://www.microsoft.com/java/sdk/

Microsoft Internet Explorer: http://www.microsoft.com/ie/

VeriSign: http://www.verisign.com

Open Software Description: http://www.microsoft.com/standards/osd/

Sean C. Sullivan is a Software Engineer in the Java Technologies department within Intel Architecture Labs (IAL) in Hillsboro, OR. His current work includes development of multimedia class libraries for Java. Prior to his position at Intel, Sean worked on operating system and CAD software projects at IBM and Image Systems Technology. Sean holds a B.Sc. in Computer Science from Rensselaer Polytechnic Institute. He is also the author of Programming with the Java Media Framework [John Wiley & Sons, Inc., 1998].