Introduction

In this post, I present an alternative to java.net.URLCLassLoader that has some desirable properties that the stock URLClassLoader does not have. The class presented here, com.subhajit.urlclassloader.URLClassLoaderX, extends URLClassLoader, and can therefore be used as a replacement for URLClassLoader in your source code.

URLClassLoaderX has certain desirable traits that URLClassLoader does not have. URLClassLoader holds locks to its URL's during its lifetime, which makes it impossible to update these URL's on operating systems like Windows. (This drawback has been recognized, and is due to be fixed in JDK 7 via the introduction of a new “close” method). URLClassLoaderX, on the other hand, does not behave in this manner. It briefly inspects its URL's upon initialization, caching information about the elements present therein, during which time it does lock the URL's. Immediately following initialization, however, URLClassLoaderX releases locks on the URL's, so that these can be updated on the file system if desired.

The ability to update or delete URL's is important in applications where you generate source code in your applications, compile it, and then load the resulting classes. In this situation, you would typically save the source code in temporary files, and load the compiled byte code from another temporary directory. The trouble with URLClassLoader is that once you have loaded the temporary byte codes, you cannot get rid of the temporary directory from which the byte code was read as long as the URLClassLoader instance is alive (on operating systems like Windows which maintains mandatory locks on files). There might be other situations where you might need to delete temporary directories or files from which you have loaded classes, and once again, using URLClassLoader leads to “locked” files and directories.

As mentioned earlier, URLClassLoaderX does not lock files or directories from which it loads classes and resources for its entire lifetime. Instead, it creates an internal cache of the URL's and the paths of the resources they contain, during initialization. For example, if a directory URL contains two resources named “com/subhajit/test/A.class” and “com/subhajit/test/picture.gif”, URLClassLoaderX initializes its internal cache such that there is an entry for the URL containing a set of strings populated with “com/subhajit/test/A.class” and “com/subhajit/test/picture.gif”. When resources and classes must be loaded, it consults these entries to determine which URL's to load these from. A resource is loaded from the first URL (in the list of URL's used to initialize the URLClassLoaderX instance) in which it is found.

URLClassLoaderX uses a “strategy” instance to which it delegates most calls. Let us first look at the strategy class.

IURLManagementStrategy

The “strategy” instance must implement the “com.subhajit.urlclassloader.IURLManagementStrategy” interface:

public interface IURLManagementStrategy {

/**

* Finds the resource <tt>name</tt> by iterating through the list of

* {@link URL}s being managed, and returns a "path" URL encoding the URL in

* which the resource was found, and a path to the resource within that URL.

*

* @param name

* @return An encoded "path" {@link URL} to the resource if the resource is

* found in one of the {@link URL}s being managed, or null if the

* resource <tt>name</tt> is not found.

* @throws MalformedURLException

*/

URL findResource(String name) throws MalformedURLException;

/**

* Find the resource named <tt>name</tt> in all the {@link URL}s being

* managed.

*

* @param name

* @return

* @throws MalformedURLException

*/

Enumeration<URL> findResources(String name) throws MalformedURLException;

/**

* Resets this object so that it can be reused.

*/

void reset();

}

The source code provided in this post contains a default implementation of IURLManagerStrategy named (somewhat unimaginatively) DefaultURLManagementStrategy.

DefaultURLManagementStrategy contains a ConcurrentMap<URL,Set<String>> named “urlContentNames”, which is initialized when the object is constructed. The initialization code uses a java.util.concurrent.ExecutorService to concurrently open and parse the specified URL's.

The “findResource” method iterates through the URL's looking for the first entry in urlContentNames for which the corresponding Set<String> contains an entry for the resource name being sought. If such an entry is found, it constructs and returns a special URL called a “path” URL that points to the resource.

Path URL's are special URL's that have a protocol named “path”, and contain two pieces of information, viz. the URL in which the resource was found, and the location of the resource within that URL. An example of a path URL (in String form) is “path:file:/C:/var/clearcase/lite-all/tools-lite/url-class-loader-test/./test/temp/#com/subhajit/jgrep/Location.class”. Note the following characteristics of this URL:

  1. It has a protocol named “path”.

  2. The URL containing the resource may be constructed by stripping away the “path:” prefix, parsing the resulting string into tokens separated by “#”, and using the first resulting token (which, in this case, is “file:/C:/var/clearcase/lite-all/tools-lite/url-class-loader-test/./test/temp/”).

  3. The location of the resource is obtained by parsing the string into tokens separated by “#” and using the second token.

As with all custom URL protocols, the “path” protocol requires a set of helper classes in order to be used. These classes are present in the source code provided in the “com.subhajit.tools.urlclassloader” package (see “PathURLConnection”, “PathURLStreamHandler” and “PathURLStreamHandlerFactory”). As a refinement, the findResource method caches URL's generated for resources found in previous calls, for the benefit of subsequent calls to find these same resources.

Note that findResource does not actually open, load or cache resources: it just creates (path) URL's that may be used to refer to these resources.

URLClassLoaderX

Having described the strategy class, let us move on to the URLClassLoaderX class itself. This class implements two types of methods, viz. Those that are relevant to class and resource loading, and other methods such as “equals”, “hasCode”, etc.

URLClassLoaderX implements the following methods relating to class and resource loading:

  1. findResource

  2. findResources

Both methods directly delegate the call to the strategy object as shown below:

@Override

public URL findResource(String name) {

try {

return strategy.findResource(name);

} catch (MalformedURLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

@Override

public Enumeration<URL> findResources(String name) throws IOException {

return strategy.findResources(name);

}

Remaining work

At this time, URLClassLoaderX is functionally complete. The next step is to improve its performance. Some ideas for enhancement that come to find are better URL management strategies (perhaps those that lazily defer work as much as possible), and a way to allow users to specify different types of URL's (and their handler classes) in an open and flexible manner (currently, only “file” URL's are supported).

Using the source code

The source code is provided as a “zip” file named “url-class-loader.zip”. To use it, download it to a temporary directory and unzip it. This results in three files, viz. “src.zip” (which contains the source code), “url-class-loader.jar” (which contains a pre-built version of the source code, compiled for Java 1.5) and “util-lite.jar”, which is a lightweight utility library that I have written. I will be happy to post complete source code for the “util-lite.jar” file if requested. The source code is available here.

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed

This blog copyright 2009 by Subhajit Dasgupta