| |||||||||||||
A huge number of publicly available packages extends the functionality of the Java core platform. Some of them provide access to features of the underlying operating system that are not available through the standard class library, such as missing GUI components, or reader and writer classes for important file formats. Others are exciting technologies in their own right, like Spring, Hibernate or Struts.
Sometimes installing them is a bit tricky, requiring you to modify the class path of your application or tweak options passed to the Java launcher. Others utilize a handy feature called the Java Extension Mechanism. Libraries loaded via the extension mechanism can be accessed by any Java program without further prerequisites (besides copying some files to certain directories). This article explains how the Extension Mechanism works and discusses the steps required to implement your own so-called optional packages.
The virtual machine uses the concept of a class path, which is a set of directories and .zip or .jar archives. To find classes (as well as other resources like properties files, images, or audio content) the Java runtime looks in all locations specified in the class path to find the required resource.
Early versions of Java relied heavily on an environment variable
called CLASSPATH that stored these locations. It is
easy to modify this variable, perhaps too easy: setting the class
path this way turned out to be error-prone, as changes usually
affected other applications. Another shortcoming of this approach
was the missing distinction between user (third-party) and system
classes. Today there is no need to use the CLASSPATH
environment variable.
Since Java 1.2, the virtual machine has distinguished between three types of classes: bootstrap classes, extension classes, and user classes. Each type has its own individual search path that can be modified separately. All three parts together make up the class path. It is worth mentioning, however, that the user class path is commonly referred to as simply "the class path."
The difference between extension classes and user classes may not be clear at first sight, as they both are implemented by third-party developers, and hence do not belong to the core Java classes. The difference is that user classes do not take advantage of the extension mechanism. Additionally, the way that extension classes are found by the virtual machine is different.
The boot class path specifies where core system classes are
searched. The system property sun.boot.class.path
stores these locations. It generally should not be necessary to
change them, but there is a non-standard option of the Java
launcher, -Xbootclasspath, that allows you to use
alternative core system classes.
The user class path specifies where user classes and resources
are searched. A simple program consisting of one class called
Test is invoked through:
java Test
This assumes you use the standard Java launcher. The class path
defaults to the current directory, so Test is
found easily (if the current directory contains
Test.class).
A program consisting of two .jars (the main application in MyApp.jar and a set of utility classes in MyUtils.zip) is invoked through:
java -classpath MyApp.jar;MyUtils.zip myapp.MyAppMain
The path separator is ; on Windows, while Unix
variants like Mac OS X and Linux use : instead.
Using -classpath completely overrides the default
setting; therefore, the current directory is not part of the class
path. Consequently, to access classes that are not part of the
specified .jar or .zip archives, the directory containing them must
be added to the user class path with the -classpath
option.
It is common practice to have a Main-Class:
attribute in the main application .jar's manifest file so the
application can be launched by typing java -jar
MyApp.jar. In this case, the .jar file is the source for
all user classes. Any other class path option is
ignored.
To gain access to classes and resources stored in utility class
.jars, you must add a Class-Path: attribute to your
application's manifest file. Its value contains a space-delimited
list of relative URLs referencing libraries your application wishes
to use. These URLs are assumed to point to directories if they end
with the / character. Otherwise they are assumed to
refer to .jars.
To share a library among multiple projects, you could add its
location to the class paths of these programs using
-classpath or Class-Path: in the manifest
file of each program. This can be a cumbersome task if several
projects are involved. If we used the old-style
CLASSPATH environment variable, it would have been
sufficient to append the location of the library--no need to
explicitly reference it with each application wishing to use it.
But there must be a similar feature in recent Java versions,
right?
The extension mechanism is a convenient and easy to use infrastructure to provide optional packages. These are sets of classes that extend the functionality of the core platform. A key feature is that the virtual machine can find components (we will see shortly what this means) of an optional package without the need to explicitly mention it on the (user) class path.
Optional packages consist of Java classes and other resources like images, sounds, text, and property files. They are wrapped in a .jar file that may be accompanied by platform-specific native code, such as shared libraries and executables.
There are two flavors of optional packages, called bundled and installed optional packages. If it is bundled with an application, the library is provided at the same code base and will therefore be downloaded automatically if necessary. Installed optional packages are shared by all applications using the same Java runtime environment.
There is nothing special about an optional package. To create one, it is sufficient to bundle classes and resources into a .jar archive. The only prerequisite is that the .jar must be copied to a certain location inside of the Java runtime directory tree.
The location of optional packages can be determined and set through system properties. Here is a small program that prints out some interesting values.
public class ShowProperties {
public static void main(String[] args) {
String [] properties = {
"java.ext.dirs",
"java.home",
"path.separator",
"file.separator",
"java.library.path",
"os.arch",
"sun.boot.class.path"
};
for (int i = 0; i < properties.length; i++) {
String key = properties[i];
System.out.println(key + ": " + System.getProperty(key));
}
}
}
The output of this program depends on the underlying operating system, as seen in Figures 1-3.

Figure 1. Running ShowProperties on Mac OS X Panther
|
|
|
|
java.home is a very important system property, as it
points to the base directory of the Java runtime.
path.separator contains the delimiter for search path
lists, as we have seen with the -classpath option.
file.separator contains the delimiter for files and
directories. In my examples here, I will use the backslash, but please keep
in mind that on Unix variants you must substitute it with the
slash. java.ext.dirs stores one or more directories to
be searched for optional packages. The default location is
java.home\lib\ext.
If an optional package requires native code, the Java runtime
looks in java.home\bin and
java.home\lib\ext\<arch>.
<arch> specifies the architecture for which the
native code has been compiled. It can be determined through the
os.arch system property. Please note that Windows and
Linux return different values, even when running on the same
machine. Pictures 2 and 3 were taken on a Toshiba notebook running
Windows Media Center Edition 2005 and SuSE Linux 9.2.
Installed optional packages are, by default, granted the same security privileges as core platform classes, because they often need to load and access native code. This can be modified by editing the security policy configuration file called java.policy, which is located in java.home\lib\security.
So far, there is no standard procedure to make an optional package system global; that is, to share it among Java runtimes. If you have several versions of Java installed on your machine, you need to copy all files associated with an optional package to the ext directories of all Java installations. Undoubtedly, this is a cumbersome task.
To solve this, you might pass -Djava.ext.dirs=... as
an additional argument when you invoke Java programs. As many
applications are launched through startup scripts or shortcuts, you
would need to modify all of them.
Apple offers a very nice solution to this problem. In Mac OS X, you can throw .jars in /Library/Java/Extensions. The classes will be visible in all Java runtimes. /System/Library/Java/Extensions is reserved for Apple extensions, and therefore should not be used by third-party developers.
Fortunately, it is possible to simulate this behavior on other operating systems.
On Linux, it is easy to achieve the same effect. You just need to create symbolic links in the lib directories of the Java installations you want to benefit from shared classes. These links point to a directory that will contain the .jars.
cd to the lib directory of the Java
installation you would like to have participate in the optional packages
sharing.mv ext
ext.old).ln -s
/usr/java/extensions ext.From now on, any optional package you copy to /usr/java/extensions will be visible to any Java version you've modified as described.
Unfortunately, current versions of Windows do not support symbolic links out of the box. The native NTFS file system does, however, provide a similar concept, called junctions, which is based upon NTFS reparse points. Sadly enough, typical Windows installations do not contain tools to create them. but you can use a freeware tool by Mark Russinovich called Junction. Please consult the Resources [13] section to download the program.
With the Junction tool, it is easy to adapt the steps described in the Linux section.
ext
that points to C:\Program Files\Java\Extensions. This
is done as follows (please open cmd.exe):
junction.exe C:\Programme\Java\jdk1.5.0\jre\lib\ext
C:\Programme\Java\Extensions. The pathnames, of course,
reflect my machine and need to be modified to meet your
configuration. The first argument to junction.exe is
the name of the junction to be created, which is the
ext directory. The second argument specifies the
directory this junction shall point to. In our case, this is the
newly created directory that will contain all shared optional
packages.Follow these steps for all Java versions you would like to have participate in optional packages sharing.
The manifest file of installed optional packages should contain some attributes that describe the extension.
Sun Microsystems,
Inc and 1.0.de.thomaskuenneth.Thomas Kuenneth.1.0.An optional package should use these attributes to identify itself. There is an additional set of attributes that should be used for applets.
Installed optional packages are visible to any Java program in the context of a runtime environment without the need to modify the class path. They are very easy to install, as they just need to be copied to certain directories. If you receive an enhanced or bug-fixed version, an existing program is easy to update, as you just have to replace the library.
On the other hand, applications may no longer work correctly if a new version of an optional package changes its behavior. This may be the case if classes or methods are removed or method signatures are modified without providing backwards-compatible versions.
So far, Sun has specified a versioning scheme for optional packages only for applets. In this case, the Java plugin checks for appropriate version numbers. For installed optional packages, no versioning mechanism is applied.
Another point worth mentioning is that classes of optional packages will be found prior to application classes, as they are treated like core platform classes. The user class path is searched last. So even if your application .jar contains a newer version of a class, the class belonging to the optional package will be used.
The Java extension mechanism offers an easy-to-use
infrastructure for providing optional packages. Packages can be
used by all Java programs without the need to modify the user
class path. Instead of requiring the user to work with the
-classpath option, please consider taking advantage of
the extension mechanism.
However, the current approach has some shortcomings, such as the inability to share optional packages among Java installations. Additionally, just like for applets, Sun needs to specify a versioning scheme that ensures that applications will use the appropriate version of an installed optional package.
Links:
[1] http://www.java.net/author/thomas-k252nneth
[2] http://www.java.net/article/2005/04/21/java-extension-mechanism#class_path
[3] http://www.java.net/article/2005/04/21/java-extension-mechanism#how_classes_found
[4] http://www.java.net/article/2005/04/21/java-extension-mechanism#sharing_jar_archives
[5] http://www.java.net/article/2005/04/21/java-extension-mechanism#optional_packages
[6] http://www.java.net/article/2005/04/21/java-extension-mechanism#location_optional_pkgs
[7] http://www.java.net/article/2005/04/21/java-extension-mechanism#sharing_optional_pkgs
[8] http://www.java.net/article/2005/04/21/java-extension-mechanism#linux
[9] http://www.java.net/article/2005/04/21/java-extension-mechanism#windows
[10] http://www.java.net/article/2005/04/21/java-extension-mechanism#tweaking_manifest_file
[11] http://www.java.net/article/2005/04/21/java-extension-mechanism#pros_cons
[12] http://www.java.net/article/2005/04/21/java-extension-mechanism#conclusion
[13] http://www.java.net/article/2005/04/21/java-extension-mechanism#resources
[14] http://www.java.net/images/2005/04/ShowPropertiesLinux.gif
[15] http://www.java.net/images/2005/04/ShowPropertiesWindows.gif
[16] http://www.sysinternals.com/ntw2k/source/misc.shtml#junction
[17] http://java.sun.com/j2se/1.5.0/docs/tooldocs/findingclasses.html
[18] http://java.sun.com/j2se/1.5.0/docs/guide/extensions/versioning.html