blob: 61fc5eb9c7ef194573c2e3f8c0944759f9c3eb9d [file] [log] [blame]
/*
$Id$
Copyright 2003 (C) Jochen Theodorou. All Rights Reserved.
Redistribution and use of this software and associated documentation
("Software"), with or without modification, are permitted provided
that the following conditions are met:
1. Redistributions of source code must retain copyright
statements and notices. Redistributions must also contain a
copy of this document.
2. Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
3. The name "groovy" must not be used to endorse or promote
products derived from this Software without prior written
permission of The Codehaus. For written permission,
please contact info@codehaus.org.
4. Products derived from this Software may not be called "groovy"
nor may "groovy" appear in their names without prior written
permission of The Codehaus. "groovy" is a registered
trademark of The Codehaus.
5. Due credit should be given to The Codehaus -
http://groovy.codehaus.org/
THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.groovy.tools;
import java.net.URL;
import java.net.URLClassLoader;
/**
* This ClassLoader should be used as root of class loaders. Any
* RootLoader does have it's own classpath. When searching for a
* class or resource this classpath will be used. Parent
* Classloaders are ignored first. If a class or resource
* can't be found in the classpath of the RootLoader, then parent is
* checked.
*
* <b>Note:</b> this is very against the normal behavior of
* classloaders. Normal is to frist check parent and then look in
* the ressources you gave this classloader.
*
* It's possible to add urls to the classpath at runtime through
* @see #addURL(URL)
*
* <b>Why using RootLoader?</b>
* If you have to load classes with multiple classloaders and a
* classloader does know a class which depends on a class only
* a child of this loader does know, then you won't be able to
* load the class. To load the class the child is not allowed
* to redirect it's search for the class to the parent first.
* That way the child can load the class. If the child does not
* have all classes to do this, this fails of course.
*
* For example:
*
* <pre>
* parentLoader (has classpath: a.jar;c.jar)
* |
* |
* childLoader (has classpath: a.jar;b.jar;c.jar)
* </pre>
*
* class C (from c.jar) extends B (from b.jar)
*
* childLoader.find("C")
* --> parentLoader does know C.class, try to load it
* --> to load C.class it has to load B.class
* --> parentLoader is unable to find B.class in a.jar or c.jar
* --> NoClassDefFoundException!
*
* if childLoader had tried to load the class by itself, there
* would be no problem. Changing childLoader to be a RootLoader
* instance will solve that problem.
*
* @author Jochen Theodorou
*/
public class RootLoader extends URLClassLoader {
/**
* constructs a new RootLoader without classpath
* @param parent the parent Loader
*/
private RootLoader(ClassLoader parent) {
this(new URL[0],parent);
}
/**
* constructs a new RootLoader with a parent loader and an
* array of URLs as classpath
*/
public RootLoader(URL[] urls, ClassLoader parent) {
super(urls,parent);
}
private static ClassLoader chooseParent(){
ClassLoader cl = RootLoader.class.getClassLoader();
if (cl!=null) return cl;
return ClassLoader.getSystemClassLoader();
}
/**
* constructs a new RootLoader with a @see LoaderConfiguration
* object which holds the classpath
*/
public RootLoader(LoaderConfiguration lc) {
this(chooseParent());
Thread.currentThread().setContextClassLoader(this);
URL[] urls = lc.getClassPathUrls();
for (int i=0; i<urls.length; i++) {
addURL(urls[i]);
}
}
/**
* loads a class using the name of the class
*/
protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException {
Class c = this.findLoadedClass(name);
if (c!=null) return c;
try {
c = findClass(name);
} catch (ClassNotFoundException cnfe) {}
if (c==null) c= super.loadClass(name,resolve);
if (resolve) resolveClass(c);
return c;
}
/**
* returns the URL of a resource, or null if it is not found
*/
public URL getResource(String name) {
URL url = findResource(name);
if (url==null) url=super.getResource(name);
return url;
}
/**
* adds an url to the classpath of this classloader
*/
public void addURL(URL url) {
super.addURL(url);
}
}