/*
* Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
* Distributed under the terms of either:
* - the common development and distribution license (CDDL), v1.0; or
* - the GNU Lesser General Public License, v2.1 or later
*/
package winstone.classLoader;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import winstone.Logger;
import winstone.WinstoneResourceBundle;
/**
* Implements the servlet spec model (v2.3 section 9.7.2) for classloading, which
* is different to the standard JDK model in that it delegates *after* checking
* local repositories. This has the effect of isolating copies of classes that exist
* in 2 webapps from each other.
*
* Thanks to James Berry for the changes to use the system classloader to prevent
* loading servlet spec or system classpath classes again.
*
* @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
* @version $Id: WebappClassLoader.java,v 1.3 2007/12/29 03:32:54 rickknowles Exp $
*/
public class WebappClassLoader extends URLClassLoader {
private static final WinstoneResourceBundle CL_RESOURCES = new WinstoneResourceBundle("winstone.classLoader.LocalStrings");
protected ClassLoader system = getSystemClassLoader();
public WebappClassLoader(URL[] urls) {
super(urls);
}
public WebappClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public WebappClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
super(urls, parent, factory);
}
protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
// Try the system loader first, to ensure that system classes are not
// overridden by webapps. Note that this includes any classes in winstone,
// including the javax.servlet classes
if (c == null) {
try {
c = system.loadClass(name);
if (c != null) {
Logger.log(Logger.MAX, CL_RESOURCES, "WebappClassLoader.LoadedBySystemCL", name);
}
} catch (ClassNotFoundException e) {
c = null;
}
}
// If an allowed class, load it locally first
if (c == null) {
try {
// If still not found, then invoke findClass in order to find the class.
c = findClass(name);
if (c != null) {
Logger.log(Logger.MAX, CL_RESOURCES, "WebappClassLoader.LoadedByThisCL", name);
}
} catch (ClassNotFoundException e) {
c = null;
}
}
// otherwise, and only if we have a parent, delegate to our parent
// Note that within winstone, the only difference between this and the system
// class loader we've already tried is that our parent might include the common/shared lib.
if (c == null) {
ClassLoader parent = getParent();
if (parent != null) {
c = parent.loadClass(name);
if (c != null) {
Logger.log(Logger.MAX, CL_RESOURCES, "WebappClassLoader.LoadedByParentCL", name);
}
} else {
// We have no other hope for loading the class, so throw the class not found exception
throw new ClassNotFoundException(name);
}
}
if (resolve && (c != null)) {
resolveClass(c);
}
return c;
}
public InputStream getResourceAsStream(String name) {
if ((name != null) && name.startsWith("/")) {
name = name.substring(1);
}
return super.getResourceAsStream(name);
}
}