ReloadingClassLoader.java
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 = (LocationClassLoaderloaderIter.next();
086         try {
087           c = aLoader.loadClass(name, false);
088         catch (ClassNotFoundException e) {}
089       }
090     }
091     if(c == nullthrow new ClassNotFoundException(name);
092     if (resolveresolveClass(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 = (ClassclassCache.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 }