
gnu.util.ReloadableClassLoader Maven / Gradle / Ivy
Show all versions of escher Show documentation
package gnu.util;
import java.io.File;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
/**
* A neat hack to do class reloading.
*
* Class reloading is, if not impossible and ugly, inconvenient in
* current class loader architecture. Sun should _really_ provide a
* standard way to do it. Many packages have implemented class reloading of
* their own, but none of them are cleanly designed to be reused IMHO. I
* ended up hacking my own version.
*
*
The problem of class reloading is that JVM does not provision the
* need. Once a class is loaded into JVM, it stays until some
* non-deterministic garbage collect time when no ones references a class
* anymore. However, JVM _does_ provide "namespace", to which different
* versions of the same class data can be loaded. A namespace is actually
* the "local scope" of an instance of a class loader. That is, a class
* can be loaded once and only once by the same intance of a class loader;
* but a new instance of a class loader can be created to load a new
* version of a class. Therefore, the trick of class reloading is to create a
* new instance of a class loader, and cache the loaded and reloaded
* classes in a global static place.
*
*
Note that dependent classes must be reloaded and resolved manually
* after the modified class is reloaded. For instance, given Class A and
* Class B (which depends on Class A) are loaded, and then Class A is
* modified and reloaded, Class B has to be reloaded to get the new version
* of Class A. It is because we can only force resolution of the new Class
* A for Class B through reloading Class B, as implied in The JavaTM
* Virtual Machine Specificatio.
*
*
Each of the following packages has its own reloadable class loader:
* BeanShell, GNU Server Pages, Jigsaw HTTPD, Resin's DynamicClassLoader,
* and Echidna multi-process system.
*
* @see
* bill's article
*
* @see
* bill's book
*
* @see
* Liang and Bracha
*/
public class ReloadableClassLoader extends ClassLoader {
public static Hashtable classes = new Hashtable ();
public static ReloadableClassLoader instance
= new ReloadableClassLoader ();
/**
* Load class file data into namespace of this class loader.
*
* @param name fully-qualified class name
* @param data raw bytes of class file
*/
public Class load (String name, byte [] data, boolean resolve) {
Class klass = defineClass (name, data, 0, data.length);
if (resolve) resolveClass (klass);
classes.put (name, klass);
return klass;
}
/**
* Force loading a class. Consider using {@link #reload_classes(String[],
* boolean)} for efficiency.
*
* @see #reload_classes(String[], boolean)
*/
public static void reload_class (String name, boolean resolve)
throws ClassNotFoundException {
String [] names = {name};
reload_classes (names, resolve);
}
/**
* Force loading a list of classes.
*
* @param wildnames a list of wildnames; a wildname can be a class name
* to indicate a class to be reloaded, or a package name appended with
* ".*" to indicate a package to be reloaded
*/
public static void reload_classes (String [] wildnames,
boolean resolve) throws ClassNotFoundException {
Vector file_pool = new Vector ();
Vector name_pool = new Vector ();
for (int i=0; inull
if class not
* found
*/
public static byte [] read (File file) {
if (file == null) return null;
byte [] data = new byte [(int) file.length ()];
try {
new java.io.FileInputStream (file).read (data);
return data;
} catch (java.io.IOException e) {
return null;
}
}
/**
* There are several mysterious problems relating to VerifyError and
* LinkageError because of dependency and type-safety of reloading
* classes. I cannot understand the issue well enough to solve the problem. This
* method resets all caches and starts with a brand new classloader so
* as to trade caching for correctness.
*/
public static void reset () {
instance = new gnu.util.ReloadableClassLoader ();
classes.clear ();
}
}