2.17.2: 2011-06-17

net.sf.basedb.util
Class JarClassLoader

java.lang.Object
  extended by java.lang.ClassLoader
      extended by net.sf.basedb.util.JarClassLoader

public final class JarClassLoader
extends ClassLoader

A class loader implementation that loads classes from JAR files. Each JAR file requires a separate instance of this class. Use the getInstance(String) method to get an existing or create a new instance for a specific JAR file. If the classes in the JAR file requires other classes in another JAR file to work, the paths to those JAR files must be listed in the Class-Path attribute in the META-INF/MANIFEST.MF file. For example:

Manifest-Version: 1.0
Class-Path: OtherJarPlugin.jar
If more than one JAR is needed separate them with one or more spaces. Note! It is only the Class-Path entry for the JAR file passed to the getInstance(String) method that is checked. The manifest file is not checked for the other JARs.

This class loader will by default first look in the specified JAR files for a class or resource and only if not found delegate to the parent class loader. This behaviour can be changed by calling setDelegateFirst(boolean) or by setting X-Delegate-First : true in the MANIFEST.MF file in the main JAR file.

Version:
2.0
Author:
Nicklas
Last modified
$Date: 2010-08-25 14:48:18 +0200 (Wed, 25 Aug 2010) $

Nested Class Summary
(package private) static class JarClassLoader.JarInfo
           
 
Field Summary
private static HashMap<String,JarClassLoader> classLoaders
          A map of all loaded class loaders.
private  Map<String,List<File>> classPath
          Contains mappings from class names to the JAR file in which the class implementation can be found.
private  boolean delegateFirst
          If we should delegate to the parent class loader first.
private  Map<File,JarClassLoader.JarInfo> jarFiles
          For keeping track of jar files listed by Class-Path entry in the manifest file.
private  long jarSize
          The size of the JAR file.
private  long jarTimeStamp
          The timestamp of the JAR file.
private static Logger log
           
private  File mainJarFile
          The main JAR file to load classes from.
 
Constructor Summary
private JarClassLoader(String jarPath)
          Create a new JAR file class loader.
 
Method Summary
private  void addResources(Vector<URL> resources, Enumeration<URL> e)
           
private  String classNameToPath(String className)
          Convert a class name to a file path.
private  Package definePackage(String name, Manifest mf)
          Define the package with the given name using information from a manifest for vendor, title and version.
static boolean exists(String jarPath)
          Check if a class loader for the given JAR file exists.
protected  Class<?> findClass(String name)
           
protected  URL findResource(String name)
           
protected  Enumeration<URL> findResources(String name)
           
 boolean getDelegateFirst()
          If this class loader delegates to the parent class loader before or after trying to find the class by itself.
static ClassLoader getInstance(String jarPath)
          Get a class loader for the specified JAR file.
static ClassLoader getInstance(String jarPath, boolean autoUnload)
          Get a class loader for the specified JAR file, optionally unloading an the old one if the JAR file has been modified.
 URL getResource(String name)
           
 Enumeration<URL> getResources(String name)
           
 boolean hasChanged(boolean checkSecondary)
          Check if the JAR file this class loader loads is classes from has changed since this class loader was created.
protected  Class<?> loadClass(String name, boolean resolve)
           
private  byte[] loadClassData(File file, String name)
          Load the byte[] of the given class.
private  Class<?> loadClassInternal(ClassLoader loader, String name)
           
private  void loadJarFile(File file, boolean followClassPath)
          Open the specified JAR file, list all entries and put them in the classPath mapping.
static ClassLoader newInstance(String jarPath)
          Get a new class loader for the specified jar file.
 void setDelegateFirst(boolean delegateFirst)
          If the class loader should delegate to the parent class loader before trying to find the class by it's own.
static void unload(String jarPath)
          Unload the class loader for the given JAR file.
 
Methods inherited from class java.lang.ClassLoader
clearAssertionStatus, defineClass, defineClass, defineClass, defineClass, definePackage, findLibrary, findLoadedClass, findSystemClass, getPackage, getPackages, getParent, getResourceAsStream, getSystemClassLoader, getSystemResource, getSystemResourceAsStream, getSystemResources, loadClass, resolveClass, setClassAssertionStatus, setDefaultAssertionStatus, setPackageAssertionStatus, setSigners
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

log

private static final Logger log

classLoaders

private static final HashMap<String,JarClassLoader> classLoaders
A map of all loaded class loaders.


mainJarFile

private final File mainJarFile
The main JAR file to load classes from.


classPath

private final Map<String,List<File>> classPath
Contains mappings from class names to the JAR file in which the class implementation can be found.


delegateFirst

private boolean delegateFirst
If we should delegate to the parent class loader first.


jarFiles

private final Map<File,JarClassLoader.JarInfo> jarFiles
For keeping track of jar files listed by Class-Path entry in the manifest file.


jarTimeStamp

private final long jarTimeStamp
The timestamp of the JAR file.


jarSize

private final long jarSize
The size of the JAR file.

Constructor Detail

JarClassLoader

private JarClassLoader(String jarPath)
                throws IOException
Create a new JAR file class loader.

Parameters:
jarPath - The path to the JAR file
Throws:
InvalidDataException - If the JAR file can't be loaded
IOException - If there is another IO-related error
Method Detail

getInstance

public static final ClassLoader getInstance(String jarPath)
                                     throws IOException
Get a class loader for the specified JAR file. If a class loader for the specified file already exists, that class loader is returned, otherwise a new class loader is created.

Parameters:
jarPath - The path to a JAR file
Returns:
A class loader
Throws:
IOException - If the jar file can't be loaded

getInstance

public static final ClassLoader getInstance(String jarPath,
                                            boolean autoUnload)
                                     throws IOException
Get a class loader for the specified JAR file, optionally unloading an the old one if the JAR file has been modified. A new class loader is created if no class loader exists or if autoUnload is true and the JAR file has changed since the existing class loader was created.

Parameters:
jarPath - The path to a JAR file
autoUnload - If TRUE the old class loaded will automatically be unloaded if the JAR file or any one it depends on (listed in the Class-Path attribute in the manifest file) has been modified (if the timestamp and/or size) is different
Returns:
A class loader
Throws:
IOException - If the jar file can't be loaded
Since:
2.4

newInstance

public static final ClassLoader newInstance(String jarPath)
                                     throws IOException
Get a new class loader for the specified jar file.

Parameters:
jarPath - The path to the jar file
Returns:
A class loader object
Throws:
IOException - If the jar file can't be loaded

unload

public static final void unload(String jarPath)
Unload the class loader for the given JAR file. The class loader will not be unloaded if the calling application has object references to the class loader or any class loaded by the class loader. However, if the getInstance(String) method is called again, a new class loader instance will be created.

Parameters:
jarPath - The path to the JAR file

exists

public static final boolean exists(String jarPath)
Check if a class loader for the given JAR file exists.

Parameters:
jarPath - The path to the JAR file
Returns:
TRUE if a class loader exists, FALSE otherwise

findClass

protected Class<?> findClass(String name)
                      throws ClassNotFoundException
Overrides:
findClass in class ClassLoader
Throws:
ClassNotFoundException

findResource

protected URL findResource(String name)
Overrides:
findResource in class ClassLoader

findResources

protected Enumeration<URL> findResources(String name)
Overrides:
findResources in class ClassLoader

loadClass

protected Class<?> loadClass(String name,
                             boolean resolve)
                      throws ClassNotFoundException
Overrides:
loadClass in class ClassLoader
Throws:
ClassNotFoundException

getResource

public URL getResource(String name)
Overrides:
getResource in class ClassLoader

getResources

public Enumeration<URL> getResources(String name)
                              throws IOException
Overrides:
getResources in class ClassLoader
Throws:
IOException

setDelegateFirst

public void setDelegateFirst(boolean delegateFirst)
If the class loader should delegate to the parent class loader before trying to find the class by it's own.

Parameters:
delegateFirst - TRUE to delegate to parent first, FALSE to only delegate if the class is not found
Since:
2.13

getDelegateFirst

public boolean getDelegateFirst()
If this class loader delegates to the parent class loader before or after trying to find the class by itself.

Since:
2.13

hasChanged

public boolean hasChanged(boolean checkSecondary)
Check if the JAR file this class loader loads is classes from has changed since this class loader was created.

Parameters:
checkSecondary - TRUE to also check secondary JAR files listed in the Class-Path entry of the manifest file
Since:
2.8

classNameToPath

private String classNameToPath(String className)
Convert a class name to a file path. Ie. replace dots with slahses and add .class to the end: net.sf.basedb.util.JarClassLoader -> net/sf/basedb/util/JarClassLoader.class


loadJarFile

private void loadJarFile(File file,
                         boolean followClassPath)
                  throws IOException
Open the specified JAR file, list all entries and put them in the classPath mapping.

Parameters:
file - The JAR file to open
followClassPath - If the MANIFEST file should be checked for a Class-Path entry that lists other JAR files that also should be checked.
Throws:
IOException - If there is an error reading the JAR files

loadClassData

private byte[] loadClassData(File file,
                             String name)
                      throws ClassNotFoundException
Load the byte[] of the given class.

Parameters:
file - The JAR file in which the class implmentation is located
name - The name of the class using regular naming convention, ie. net.sf.basedb.util.JarClassLoader
Throws:
ClassNotFoundException - If the class can't be loaded

definePackage

private Package definePackage(String name,
                              Manifest mf)
Define the package with the given name using information from a manifest for vendor, title and version. The package should not already exist.

Parameters:
name - The name of the package
mf - An optional manifest
Returns:
A package
Since:
2.16

loadClassInternal

private Class<?> loadClassInternal(ClassLoader loader,
                                   String name)

addResources

private void addResources(Vector<URL> resources,
                          Enumeration<URL> e)

2.17.2: 2011-06-17