blob: 49608e9002f075f4846d23c502b61f05f7a8a6ec [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.
* <p/>
* <b>Note:</b> this is very against the normal behavior of
* classloaders. Normal is to first check parent and then look in
* the resources you gave this classloader.
* <p/>
* It's possible to add urls to the classpath at runtime through
* @see #addURL(URL)
* <p/>
* <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.
* <p/>
* For example:
* <p/>
* <pre>
* parentLoader (has classpath: a.jar;c.jar)
* |
* |
* childLoader (has classpath: a.jar;b.jar;c.jar)
* </pre>
* <p/>
* class C (from c.jar) extends B (from b.jar)
* <p/>
* 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!
* <p/>
* 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 = oldFindClass(name);
} catch (ClassNotFoundException cnfe) {
// IGNORE
}
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);
}
private Class oldFindClass(String name) throws ClassNotFoundException {
return super.findClass(name);
}
protected Class findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
}