/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser; import gw.config.CommonServices; import gw.fs.IDirectory; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.module.IExecutionEnvironment; import gw.lang.reflect.module.IJreModule; import gw.lang.reflect.module.IModule; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ModuleClassLoader extends URLClassLoader implements IModuleClassLoader { private IModule _module; private ModuleClassLoader(URL[] urls, ClassLoader parent, IModule module) { super(urls, parent); _module = module; super.addURL(null); } public Class<?> loadLocalClass(String name, boolean resolve) throws ClassNotFoundException { // Load class without traversing dependent modules. // Note: look in the parent classloader first. That means, all modules try to load class from // JRE module first and only then from itself. return super.loadClass(name, resolve); } public boolean isDeferToParent() { return getURLs().length == 0 && (_module == _module.getExecutionEnvironment().getJreModule()); } @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { if ( _module == null) { throw new RuntimeException("This loader has been disposed and cannot be used for class loading purposes."); } if (name.equalsIgnoreCase("con") || name.toLowerCase().endsWith(".con")) { return null; } Throwable t; try { Class<?> aClass = loadLocalClass(name, resolve); return aClass; } catch (ClassNotFoundException e1) { // Ok, not found locally t = e1; } catch (NoClassDefFoundError e2) { // XXX-isd: One of the class dependencies could not be loaded -- treat as class not being found. t = e2; } for (IModule m : _module.getModuleTraversalList()) { if (m != _module && m != TypeSystem.getGlobalModule() ) { ClassLoader moduleClassLoader = m.getModuleClassLoader(); Class aClass; try { if (moduleClassLoader instanceof IModuleClassLoader) { aClass = ((IModuleClassLoader) moduleClassLoader).loadLocalClass(name, resolve); } else { aClass = moduleClassLoader.loadClass(name); } return aClass; } catch (ClassNotFoundException e2) { // Ignore } } } throw new ClassNotFoundException("Class not found at all: " + name, t); } public static ClassLoader create(IModule module) { List<IDirectory> javaClassPath = module.getJavaClassPath(); List<URL> urls = new ArrayList<URL>(javaClassPath.size()); for (IDirectory entry : javaClassPath) { try { urls.add(entry.toURI().toURL()); } catch (MalformedURLException e) { throw new RuntimeException(e); } } IExecutionEnvironment environment = module.getExecutionEnvironment(); if (environment.isSingleModuleMode()) { // XXX-isd: we need discardable classloader for JRE module, so we can use it for defining throw-away proxy classes. urls = Collections.emptyList(); //return CommonServices.getEntityAccess().getPluginClassLoader(); } // JRE module delegates to plugin classloader, all other modules delegate to JRE module first. ClassLoader parent = (module == environment.getJreModule()) ? CommonServices.getEntityAccess().getPluginClassLoader() : null; //environment.getJreModule().getModuleClassLoader(); return new ModuleClassLoader(urls.toArray(new URL[urls.size()]), parent, module); } public void dispose() { _module = null; } }