Top 10 in 2008
5 popular archives:
All selections are based on page views.
JW hot topic: Tech careers in a slump
Seems like new layoffs are announced every week, projects are dying and software developers are feeling the IT budget squeeze.
Being nervous isn't a crime, but you're better off with information, advice, and a plan.
From the IDG News Network:
ClassLoaders: providing support for a new class repository and partitioning user code in a server. The applet ClassLoader is an example of the former. It introduces the ability to load classes from an HTTP server. The latter purpose -- partitioning
user code in a server -- is less frequent. For example, consider a servlet engine responsible for running servlets created
by several developers. Those developers may be unaware of each other, as in a commercial Web-hosting environment, and they
will want their Java code to execute independently of any other code using the servlet runner. A custom ClassLoader can maintain a separate ClassLoader for each developer's servlet. Since a class is identified in a Java virtual machine (JVM) by its full name and the ClassLoader that loaded it, classes loaded by a different ClassLoader are effectively separated. This use of custom ClassLoaders provides for multiple pseudoapplications to run concurrently in the JVM.The earlier Java 1.1-style custom ClassLoaders let you load Java classes from all sorts of interesting places. (For information regarding Java 1.1-style custom ClassLoaders, see Resources.) However, this capability carried the price of complexity. The abstract class java.lang.ClassLoader required a custom ClassLoader to implement a single method: loadClass(). Nothing difficult about implementing a single method -- pretty simple, right? Wrong!
The loadClass() method required the custom ClassLoader to implement a laundry list of functions. In the Java 1.1 custom loadClass() they include the following:
As you can see, this is quite a list, given that you are just trying to customize the way classes are input into the virtual
machine (VM). Essentially, the java.lang.ClassLoader design forced you to do all the work for loading a class, rather than only the work required to bring a class into the VM in a new way.
For Java 1.2, a delegation design was put in place for java.lang.ClassLoader. In the delegation design, a custom ClassLoader delegates class loading to its parent. A ClassLoader parent can be either the bootstrap ClassLoader or another custom ClassLoader. In the event the parent ClassLoader can't load a class, a new method, named findClass(), is called on the ClassLoader subclass. In this manner, the custom ClassLoader is responsible for loading only the classes not available to the parent -- presumably classes that come from a new type of
class repository.
Getting down to the nuts and bolts of the code, the loadClass() method is no longer abstract, relieving custom ClassLoaders from having to override it. In fact, new custom ClassLoaders should not override loadClass(); instead they should override the new findClass() method to contain the custom class-loading logic. The java.lang.ClassLoader implementation of findClass() throws a ClassNotFoundException, essentially a no-op awaiting implementation by a custom ClassLoader .
Now I'll explain how to write a simple 1.2-style custom ClassLoader. First, you will subclass java.lang.ClassLoader, overriding findClass() as described earlier. The ClassLoader source file is available in Resources. I should note that the updates to java.lang.ClassLoader for Java 1.2 are backward compatible, so Java 1.1-style custom ClassLoaders will continue to work on a Java 1.2 virtual machine as they did on Java 1.1. Since the Java 1.2 version of java.lang.ClassLoader implements the delegation design in the loadClass() method, Java 1.1 custom ClassLoaders override the delegation code because they provide their own loadClass() implementation. Remember that in Java 1.1, java.lang.ClassLoader's loadClass() method was abstract, requiring subclasses to provide an implementation.
This simple ClassLoader will load Java classes directly from the file system into subdirectories under a fixed directory named store, corresponding to their package specification. The ClassLoader will use Chuck McManis's technique (see Resources) of ensuring that the system ClassLoader will not find the classes you want to load by renaming the class files with the extension .impl Any additional files used with the classes will be loaded from the store directory.
Here is an excerpt from the findClass() method in the SimpleClassLoader:
FileInputStream fi = null;
try
{
System.out.println("Simple1_2ClassLoader finding class: " + name);
String path = name.replace('.', '/');
fi = new FileInputStream("store/" + path + ".impl");
byte[] classBytes = new byte[fi.available()];
fi.read(classBytes);
definePackage(name);
return defineClass(name, classBytes, 0, classBytes.length);
}
The findClass() method is only responsible for loading the class bytes and returning a defined class. The method defineClass will convert the raw class bytes into a Java class suitable for JVM use. The parent ClassLoader, either another custom ClassLoader or the bootstrap ClassLoader, has already made several attempts at loading the class. It first attempts to find the class among the set of classes that
have been previously loaded. If the class has not been previously loaded, it will call loadClass() on the parent ClassLoader (if there is one) or call it on the bootstrap ClassLoader. Only when those attempts have failed will your custom ClassLoader be called to load the class via findClass(). Since a lot of the work is done for you, the 1.2-custom ClassLoader is much simpler than its Java 1.1.x counterpart.
Using the delegation model, you can chain together custom ClassLoaders. Chaining ClassLoaders lets you bring together multiple unique class-loading mechanisms. A new constructor for java.lang.ClassLoader that lets you assign a parent ClassLoader has been added to Java 1.2. Class-loading requests are delegated to the parent ClassLoader, and child ClassLoaders receive requests that the parent is unable to fulfill. If the no-argument ClassLoader constructor is used, the system ClassLoader is automatically assigned as the parent ClassLoader for delegation.
The following code sample shows the constructor you must implement to enable ClassLoader chaining. For completeness, custom ClassLoaders should provide this constructor to allow parent ClassLoader assignment.
Simple1_2ClassLoader(ClassLoader parent)
{
super(parent);
init();
}
Class-loading requests will be delegated to the parent ClassLoader, which will have the first shot at loading a class. This feature lets you create a chain of ClassLoaders that work together without having to use inheritance. Using an inheritance design would result in code with more interdependencies
between the classes. Inheritance would make each subclass exposed to errors introduced by changing the superclass. Note that
a findClass() method in a custom ClassLoader does not need to call its superclass's implementation of findClass(). However, it should throw a ClassNotFoundException whenever it is not able to load the class. When this exception is thrown, another custom ClassLoader in the chain has the chance to load it. In the event the class is never loaded, the ClassNotFoundException will of course be thrown to the application code.
For Java 1.2, runtime package versioning is available. That is, at runtime you can query the specification and implementation
version information for a class. This capability is implemented via modifications to several classes in the Java runtime.
The ClassLoader is central to the modifications that support runtime versioning.
The abstract class java.lang.ClassLoader contains the method definePackage() to define a package. Once a package is defined, you can use the new Java 1.2 java.lang.Package class to identify classes loaded from that package. However, the ClassLoader subclass actually defines a package. This means that java.lang.ClassLoader subclasses, such as java.net.URLClassLoader, actually contain the logic to determine the package-versioning information and call the definePackage method on the java.lang.ClassLoader superclass.
Thus, a custom ClassLoader may need to have the same logic to identify package information and make the appropriate call to java.lang.ClassLoader to define the package at runtime. The package information needs to be written in a manifest, so your custom ClassLoader must read the manifest and define the packages if the runtime-package-versioning system is to work. Of course, for some custom
ClassLoaders, it may be determined that package versioning is not needed, but that should be a conscious choice, not an oversight.
I will illustrate the use of package versioning by enabling the simple ClassLoader to read a manifest from the store directory. Normally, the manifest would be contained in a jar or zip file; this is just an example:
// Check for a manifest in the store directory
try
{
fi = new FileInputStream("store\\MANIFEST.MF");
manifest = new Manifest(fi);
}
In addition to loading classes, ClassLoaders also locate resources in the repositories they are managing. These resources may be image files, audio files, or other types
of data. For completeness, custom ClassLoaders should also provide this capability.
ClassLoader source file at