001 package gate.util;
002
003 /**
004 * A ClassLoader that supports class reloading.
005 * It maintains a list of URLs which are searched for classes not found in the
006 * system classloader.
007 * URLs can be loaded and unloaded. Loading the same URL twice will cause the
008 * jar file or directory pointed by the URL to be reloaded.
009 */
010
011 import java.net.URL;
012 import java.net.URLClassLoader;
013 import java.util.*;
014
015 public class ReloadingClassLoader extends ClassLoader {
016
017 /**
018 * Constructs a ReloadingClassLoader using a custom class loader as parent.
019 *
020 * @param parent the parent class loader. The parent class loader should give
021 * access to the system classes at the least (in order to load a new class
022 * access to {@link java.lang.Object} is required).
023 */
024 public ReloadingClassLoader(ClassLoader parent){
025 this.parent = parent;
026 loaders = new HashMap();
027 }
028
029
030 /**
031 * Constructs a ReloadingClassLoader using the System Class Loader as a
032 * parent.
033 */
034 public ReloadingClassLoader() {
035 this(ClassLoader.getSystemClassLoader());
036 }
037
038 /**
039 * Registers an URL as a location where class files can be found.
040 * If the URL was already registered the the classes found at the location
041 * will be reloaded.
042 * @param url the URL pointing to a jar file or to a directory containing
043 * class files.
044 */
045 public void load(URL url){
046 LocationClassLoader loader = new LocationClassLoader(url);
047 loaders.put(url, loader);
048 }
049
050 /**
051 * Removes a registered URL.
052 * @param url the URl to be unloaded.
053 */
054 public void unload(URL url){
055 loaders.remove(url);
056 }
057
058 /**
059 * Loads the class with the specified name. It searches for classes in the
060 * following order:
061 * <ol>
062 * <li>the parent classloader</li>
063 * <li>all the locations registered with this class loader</li>
064 * </ol>
065 *
066 * @param name The name of the class
067 * @param resolve If <tt>true</tt> then resolve the class
068 * @return The resulting <tt>Class</tt> object
069 * @throws ClassNotFoundException If the class could not be found
070 */
071 protected synchronized Class loadClass(String name, boolean resolve)
072 throws ClassNotFoundException{
073 Class c = null;
074 //check with the parent (most classes are fixed)
075 if(parent != null){
076 try {
077 c = parent.loadClass(name);
078 }catch (ClassNotFoundException cnfe) {}
079 }
080
081 if(c == null){
082 //Check all the loaders for the class
083 Iterator loaderIter = loaders.values().iterator();
084 while (c == null && loaderIter.hasNext()) {
085 LocationClassLoader aLoader = (LocationClassLoader) loaderIter.next();
086 try {
087 c = aLoader.loadClass(name, false);
088 } catch (ClassNotFoundException e) {}
089 }
090 }
091 if(c == null) throw new ClassNotFoundException(name);
092 if (resolve) resolveClass(c);
093 return c;
094 }
095
096 /**
097 * A ClassLoader that loads classes from a location specified by an URL.
098 */
099 protected class LocationClassLoader extends URLClassLoader {
100
101 /**
102 * Constructs a LocationClassLoader for a specified URL.
103 * Uses the same parent classloader as the enclosing ReloadingClassLoader.
104 * @param location the URL to be searched for class files.
105 */
106 public LocationClassLoader(URL location) {
107 super(new URL[]{location}, null);
108 this.location = location;
109 classCache = new HashMap();
110 }
111
112 /**
113 * Loads the class with the specified name. It will search first the parent
114 * class loader, then an internal cache for classes already loaded and then
115 * the registered URL.
116 *
117 * @param name The name of the class
118 * @param resolve If <tt>true</tt> then resolve the class
119 * @return The resulting <tt>Class</tt> object
120 *
121 * @throws ClassNotFoundException If the class could not be found
122 */
123 protected synchronized Class loadClass(String name, boolean resolve)
124 throws ClassNotFoundException{
125 Class c = null;
126 //search the parent first
127 if(parent != null){
128 try {
129 c = parent.loadClass(name);
130 }catch (ClassNotFoundException cnfe) {}
131 }
132 //search the cache
133 if(c == null){
134 c = (Class) classCache.get(name);
135 }
136 //search the registered location
137 if (c == null) {
138 //this will trow ClassNotFoundException if necessary
139 c = findClass(name);
140 //save the class for future searches
141 classCache.put(name, c);
142 }
143 if (resolve) {
144 resolveClass(c);
145 }
146 return c;
147 }
148
149 /**
150 * A cache for classes already found and loaded.
151 */
152 protected Map classCache;
153 /**
154 * The location to be searched for new classes.
155 */
156 protected URL location;
157 }//protected class LocationClassLoader
158
159
160 /**
161 * Map that contains the {@link LocationClassLoader} for each registered URL.
162 */
163 protected Map loaders;
164
165 /**
166 * The parent class loader.
167 */
168 protected ClassLoader parent;
169 }
|