001: /*
002: $Id: RootLoader.java 3870 2006-06-28 12:59:18Z blackdrag $
003:
004: Copyright 2003 (C) Jochen Theodorou. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package org.codehaus.groovy.tools;
047:
048: import java.net.URL;
049: import java.net.URLClassLoader;
050:
051: /**
052: * This ClassLoader should be used as root of class loaders. Any
053: * RootLoader does have it's own classpath. When searching for a
054: * class or resource this classpath will be used. Parent
055: * Classloaders are ignored first. If a class or resource
056: * can't be found in the classpath of the RootLoader, then parent is
057: * checked.
058: *
059: * <b>Note:</b> this is very against the normal behavior of
060: * classloaders. Normal is to frist check parent and then look in
061: * the ressources you gave this classloader.
062: *
063: * It's possible to add urls to the classpath at runtime through
064: * @see #addURL(URL)
065: *
066: * <b>Why using RootLoader?</b>
067: * If you have to load classes with multiple classloaders and a
068: * classloader does know a class which depends on a class only
069: * a child of this loader does know, then you won't be able to
070: * load the class. To load the class the child is not allowed
071: * to redirect it's search for the class to the parent first.
072: * That way the child can load the class. If the child does not
073: * have all classes to do this, this fails of course.
074: *
075: * For example:
076: *
077: * <pre>
078: * parentLoader (has classpath: a.jar;c.jar)
079: * |
080: * |
081: * childLoader (has classpath: a.jar;b.jar;c.jar)
082: * </pre>
083: *
084: * class C (from c.jar) extends B (from b.jar)
085: *
086: * childLoader.find("C")
087: * --> parentLoader does know C.class, try to load it
088: * --> to load C.class it has to load B.class
089: * --> parentLoader is unable to find B.class in a.jar or c.jar
090: * --> NoClassDefFoundException!
091: *
092: * if childLoader had tried to load the class by itself, there
093: * would be no problem. Changing childLoader to be a RootLoader
094: * instance will solve that problem.
095: *
096: * @author Jochen Theodorou
097: */
098: public class RootLoader extends URLClassLoader {
099:
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)
119: return cl;
120: return ClassLoader.getSystemClassLoader();
121: }
122:
123: /**
124: * constructs a new RootLoader with a @see LoaderConfiguration
125: * object which holds the classpath
126: */
127: public RootLoader(LoaderConfiguration lc) {
128: this (chooseParent());
129: Thread.currentThread().setContextClassLoader(this );
130: URL[] urls = lc.getClassPathUrls();
131: for (int i = 0; i < urls.length; i++) {
132: addURL(urls[i]);
133: }
134: }
135:
136: /**
137: * loads a class using the name of the class
138: */
139: protected Class loadClass(final String name, boolean resolve)
140: throws ClassNotFoundException {
141: Class c = this .findLoadedClass(name);
142: if (c != null)
143: return c;
144:
145: try {
146: c = findClass(name);
147: } catch (ClassNotFoundException cnfe) {
148: }
149: if (c == null)
150: c = super .loadClass(name, resolve);
151:
152: if (resolve)
153: resolveClass(c);
154:
155: return c;
156: }
157:
158: /**
159: * returns the URL of a resource, or null if it is not found
160: */
161: public URL getResource(String name) {
162: URL url = findResource(name);
163: if (url == null)
164: url = super .getResource(name);
165: return url;
166: }
167:
168: /**
169: * adds an url to the classpath of this classloader
170: */
171: public void addURL(URL url) {
172: super.addURL(url);
173: }
174: }
|