View Javadoc

1   /*
2   $Id: RootLoader.java,v 1.13 2006/06/28 12:59:18 blackdrag Exp $
3   
4   Copyright 2003 (C) Jochen Theodorou. All Rights Reserved.
5   
6   Redistribution and use of this software and associated documentation
7   ("Software"), with or without modification, are permitted provided
8   that the following conditions are met:
9   
10  1. Redistributions of source code must retain copyright
11     statements and notices.  Redistributions must also contain a
12     copy of this document.
13  
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18  
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus.  For written permission,
22     please contact info@codehaus.org.
23  
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28  
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31  
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45  */
46  package org.codehaus.groovy.tools;
47  
48  import java.net.URL;
49  import java.net.URLClassLoader;
50  
51  /***
52   * This ClassLoader should be used as root of class loaders. Any
53   * RootLoader does have it's own classpath. When searching for a 
54   * class or resource this classpath will be used. Parent 
55   * Classloaders are ignored first. If a class or resource 
56   * can't be found in the classpath of the RootLoader, then parent is
57   * checked.
58   * 
59   * <b>Note:</b> this is very against the normal behavior of 
60   * classloaders. Normal is to frist check parent and then look in
61   * the ressources you gave this classloader.
62   * 
63   * It's possible to add urls to the classpath at runtime through
64   * @see #addURL(URL)
65   * 
66   * <b>Why using RootLoader?</b>
67   * If you have to load classes with multiple classloaders and a
68   * classloader does know a class which depends on a class only 
69   * a child of this loader does know, then you won't be able to 
70   * load the class. To load the class the child is not allowed 
71   * to redirect it's search for the class to the parent first.
72   * That way the child can load the class. If the child does not
73   * have all classes to do this, this fails of course.
74   *  
75   * For example:
76   *  
77   *  <pre>
78   *  parentLoader   (has classpath: a.jar;c.jar)
79   *      |
80   *      |
81   *  childLoader    (has classpath: a.jar;b.jar;c.jar)
82   *  </pre>
83   *  
84   *  class C (from c.jar) extends B (from b.jar)
85   *  
86   *  childLoader.find("C")
87   *  --> parentLoader does know C.class, try to load it
88   *  --> to load C.class it has to load B.class
89   *  --> parentLoader is unable to find B.class in a.jar or c.jar
90   *  --> NoClassDefFoundException!
91   *  
92   *  if childLoader had tried to load the class by itself, there
93   *  would be no problem. Changing childLoader to be a RootLoader 
94   *  instance will solve that problem.
95   *   
96   * @author Jochen Theodorou
97   */
98  public class RootLoader extends URLClassLoader {
99  
100     /***
101      * constructs a new RootLoader without classpath
102      * @param parent the parent Loader
103      */   
104     private RootLoader(ClassLoader parent) {
105         this(new URL[0],parent);
106     }
107     
108     /***
109      * constructs a new RootLoader with a parent loader and an
110      * array of URLs as classpath
111      */
112     public RootLoader(URL[] urls, ClassLoader parent) {
113         super(urls,parent);
114     }
115     
116     private static ClassLoader chooseParent(){
117       ClassLoader cl = RootLoader.class.getClassLoader();
118       if (cl!=null) return cl;
119       return ClassLoader.getSystemClassLoader();
120     }
121     
122     /***
123      * constructs a new RootLoader with a @see LoaderConfiguration
124      * object which holds the classpath
125      */
126     public RootLoader(LoaderConfiguration lc) {
127         this(chooseParent());
128         Thread.currentThread().setContextClassLoader(this);
129         URL[] urls = lc.getClassPathUrls();
130         for (int i=0; i<urls.length; i++) {
131             addURL(urls[i]);
132         }
133     }
134 
135     /***
136      * loads a class using the name of the class
137      */
138     protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException {
139         Class c = this.findLoadedClass(name);
140         if (c!=null) return c;
141      
142         try {
143             c = findClass(name);
144         } catch (ClassNotFoundException cnfe) {}
145         if (c==null) c= super.loadClass(name,resolve);
146 
147         if (resolve) resolveClass(c);
148         
149         return c;
150     }
151         
152     /***
153      * returns the URL of a resource, or null if it is not found
154      */
155     public URL getResource(String name) {
156         URL url = findResource(name);
157         if (url==null) url=super.getResource(name);
158         return url;
159     } 
160  
161     /***
162      * adds an url to the classpath of this classloader
163      */
164     public void addURL(URL url) {
165         super.addURL(url);
166     }
167 }