| /* |
| * 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); |
| } |
| } |