package de.skuzzle.polly.core.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; public class ProxyClassLoader extends ClassLoader { private final static Logger logger = Logger.getLogger(ProxyClassLoader.class .getName()); private final List<PluginClassLoader> children; public ProxyClassLoader() { this(ClassLoader.getSystemClassLoader()); } public ProxyClassLoader(ClassLoader parent) { super(parent); if (!registerAsParallelCapable()) { logger.error("Failed to register ClassLoader as parallel capable"); } this.children = new LinkedList<PluginClassLoader>(); } // this method is adapted from jdtsoft.com's JarClassLoader public void invokeMain(String sClass, String[] args) throws Throwable { // The default is sun.misc.Launcher$AppClassLoader (run from file system or JAR) Thread.currentThread().setContextClassLoader(this); Class<?> clazz = loadClass(sClass); Method method = clazz.getMethod("main", new Class<?>[] { String[].class }); boolean bValidModifiers = false; boolean bValidVoid = false; if (method != null) { method.setAccessible(true); // Disable IllegalAccessException int nModifiers = method.getModifiers(); // main() must be "public static" bValidModifiers = Modifier.isPublic(nModifiers) && Modifier.isStatic(nModifiers); Class<?> clazzRet = method.getReturnType(); // main() must be "void" bValidVoid = (clazzRet == void.class); } if (method == null || !bValidModifiers || !bValidVoid) { throw new NoSuchMethodException( "The main() method in class \"" + sClass + "\" not found."); } // Invoke method. // Crazy cast "(Object)args" because param is: "Object... args" try { method.invoke(null, (Object)args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } public void addLoader(PluginClassLoader child) { synchronized (this.children) { this.children.add(child); } } public void removeLoader(PluginClassLoader child) { synchronized (this.children) { this.children.remove(child); } } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { final List<PluginClassLoader> children; synchronized (this.children) { // copy children to avoid further synchronization children = new ArrayList<>(this.children); } for (PluginClassLoader cl : children) { try { return cl.findClass(name); } catch (ClassNotFoundException ignore){}; } throw new ClassNotFoundException(name); } @Override protected URL findResource(String name) { final List<PluginClassLoader> children; synchronized (this.children) { // copy children to avoid further synchronization children = new ArrayList<>(this.children); } for (PluginClassLoader cl : children) { final URL result = cl.findResource(name); if (result != null) { return result; } } return null; } @Override public String toString() { return this.getClass().getName(); } }