Previous | Next | Trail Map | Beyond the Basics | Miscellaneous

Class Loading

The JNDI is an API defined independent of any specific naming or directory service implementation. For an application, applet, servlet, or any program unit to use the JNDI, it must specify the service provider to use and have access to the provider's class files. A single program might use more than one provider. Furthermore, the program and/or providers might use object factories, state factories, and control factories, all of whose class files must also be made available to the JNDI. In addition, the JNDI needs access to application resource files (see the Application Resource Files (in the Beyond the Basics trail) section) provided by the program, providers, and other components. In all of these cases, the JNDI needs to load in class and resource files. This section explains how the JNDI uses class loaders and how you can affect its use of them.

Background on Class Loaders

The class loader is the means by which JavaTM classes and resources are loaded into the JRE. It controls the policies ranging from where to load class definitions to the data format of the class definitions.

In the JDKTM 1.1 and earlier releases, no relationship exists between various class loaders. A system class loader responsible for loading in the Java runtime, the application, and classes and resources in the application's classpath. An applet class loader is responsible for loading the applets and their related classes and resources, possibly over the network by communicating with a Web server.

In the Java 2 Platform, Standard Edition, v1.2 and later releases, class loaders have a hierarchical relationship. Each class loader has a parent class loader. When a class loader is asked to load a class or resource, it consults its parent class loader before attempting to load the item itself. The parent in turn consults its parent, and so on. So it is only after all of the ancestor class loaders cannot find the item that the current class loader gets involved.

A bootstrap class loader is responsible for loading in the Java runtime. It is the "root" in the class loader hierarchy. The system class loader is a descendant of the bootstrap class loader. It is responsible for loading in the application, as well as for loading classes and resources in the application's classpath.

The Java 2 platform also introduced the notion of context class loader. A thread's context class loader is, by default, set to the context class loader of the thread's parent. The hierarchy of threads is rooted at the primordial thread (the one that runs the program). The context class loader of the primordial thread is set to the class loader that loaded the application. So unless you explicitly change the thread's context class loader, its context class loader will be the application's class loader. That is, the context class loader can load the classes that the application can load. This loader is used by the Java runtime such as the RMI (Java Remote Method Invocation) to load classes and resources on behalf of the user application. The context class loader, like any Java 2 platform class loader, has a parent class loader and supports the same delegation model for class loading described previously.

Class Loading on the JDK 1.1 Software

When you use the JNDI with the JDK 1.1 software, you must place the JNDI JARs, service provider JARs, and JARs or class files containing factories in the application's classpath. If you're using an applet, then you must place those JARs and class files in the applet's codebase directory and/or archive locations. Consequently, the class loader that loads the JNDI JARs is typically the same as the one that loads in the application and the factories.

Note that you cannot use JNDI application resource files with the JDK 1.1 software. See the Application Resource Files (in the Beyond the Basics trail) section for details.

Class Loading on the Java 2 Platform

When you use the JNDI with the Java 2 platform, the class loader that loads the JNDI classes typically differs from the one that loads in the application. For example, in the Java 2 SDK, v1.3, the JNDI classes are loaded by the bootstrap class loader whereas the application classes are loaded by the system class loader. In the Java 2 SDK, v1.2, if you install the JNDI as an installed extension, then the JNDI classes are loaded by the class loader responsible for loading installed extensions, whereas the application classes are loaded by the system class loader. As a result, if the JNDI were to use its class loader to load service providers and factories, then it might not see the same classes as the application. Therefore, to try to see what the application can see, the JNDI uses the calling thread's context class loader when it is loading in classes for the service providers, factories, and application resource files.

In rare circumstances, you want to change a thread's context class loader to affect how the JNDI finds classes. This might occur, for example, when the environment that you're working in does not set the context class loader properly. For example, a bug in the Java 2 SDK, Standard Edition, v1.2.2 causes the AWT (Abstract Window Toolkit) not to set the listener threads' context class loader to be the class loader that loaded the applet. Consequently, callback methods invoked by the listener threads do not have access to service providers and factories that the applet can otherwise load explicitly. Or, you might want to add an additional repository of JARs and class files that contains special providers and factories to your applications/applets. To change a thread's context class loader, you use Thread.setContextClassLoader().

Here is an example.

ClassLoader prevCl = Thread.currentThread().getContextClassLoader();

// Create the class loader by using the given URL
// Use prevCl as parent to maintain current visibility
ClassLoader urlCl = 
    URLClassLoader.newInstance(new URL[]{new URL(url)}, prevCl);

try {
    // Save the class loader so that you can restore it later
    Thread.currentThread().setContextClassLoader(urlCl);

    // Expect that the environment properties are in the
    // application resource file found at "url"
    Context ctx = new InitialContext();

    System.out.println(ctx.lookup("tutorial/report.txt"));

    // Do something useful with ctx
    ...
} catch (NamingException e) {
    // Handle the exception
} finally {
    // Restore
    Thread.currentThread().setContextClassLoader(prevCl);
}
This example creates a URLClassLoader that loads classes from a specified codebase URL. It then creates an initial context and performs other JNDI operations within the context of that class loader. In this example, the class loader affects how the initial context was initialized (via an application resource file found by the new class loader), as well as the result of lookup() (via the object factory named in the application resource file and the class file of the factory found by the new class loader). To run this program, you supply a codebase URL as follows:
# java ChangeClassLoader file:/some/directory/somewhere/
In that codebase, you can specify a jndi.properties file. In particular example, the following jndi.properties file is in the codebase directory.
java.naming.factory.initial=com.sun.jndi.fscontext.FSContextFactory
java.naming.provider.url=file:/tmp
java.naming.factory.object=FooObjectFactory
In the same codebase directory is the class definition for FooObjectFactory, which when given a java.io.File object always returns the string "foo". When you run this program, you see this output:
foo
If you do not see this output, then check the correctness of the codebase URL argument. Remember, if you are naming a codebase directory, then you should include a trailing forward slash character in the URL.

Class Loading from Prespecified Locations

In some cases, the location of class files is specified explicitly. For example, you can specify an object factory's codebase in its Reference(in the API reference documentation). When the JNDI reads such an object from the naming or directory service, it will use a class loader for the codebase named in the Reference to obtain the class files for the factory. The parent of that class loader is the thread's context class loader.


Previous | Next | Trail Map | Beyond the Basics | Miscellaneous