|
|
@ -33,7 +33,7 @@ import java.util.Objects; |
|
|
|
* One instance of this class should be created by plugin manager for every available plug-in. |
|
|
|
* One instance of this class should be created by plugin manager for every available plug-in. |
|
|
|
* By default, this class loader is a Parent Last ClassLoader - it loads the classes from the plugin's jars |
|
|
|
* By default, this class loader is a Parent Last ClassLoader - it loads the classes from the plugin's jars |
|
|
|
* before delegating to the parent class loader. |
|
|
|
* before delegating to the parent class loader. |
|
|
|
* Use {@link #parentFirst} to change the loading strategy. |
|
|
|
* Use {@link #classLoadingStrategy} to change the loading strategy. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Decebal Suiu |
|
|
|
* @author Decebal Suiu |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -46,7 +46,7 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
|
|
|
|
|
|
|
|
private PluginManager pluginManager; |
|
|
|
private PluginManager pluginManager; |
|
|
|
private PluginDescriptor pluginDescriptor; |
|
|
|
private PluginDescriptor pluginDescriptor; |
|
|
|
private boolean parentFirst; |
|
|
|
private ClassLoadingStrategy classLoadingStrategy; |
|
|
|
|
|
|
|
|
|
|
|
public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) { |
|
|
|
public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) { |
|
|
|
this(pluginManager, pluginDescriptor, parent, false); |
|
|
|
this(pluginManager, pluginDescriptor, parent, false); |
|
|
@ -57,11 +57,19 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
* before trying to load the a class through this loader. |
|
|
|
* before trying to load the a class through this loader. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent, boolean parentFirst) { |
|
|
|
public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent, boolean parentFirst) { |
|
|
|
|
|
|
|
this(pluginManager, pluginDescriptor, parent, parentFirst ? ClassLoadingStrategy.APD : ClassLoadingStrategy.PDA); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* classloading according to {@code classLoadingStrategy} |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent, ClassLoadingStrategy classLoadingStrategy) { |
|
|
|
super(new URL[0], parent); |
|
|
|
super(new URL[0], parent); |
|
|
|
|
|
|
|
|
|
|
|
this.pluginManager = pluginManager; |
|
|
|
this.pluginManager = pluginManager; |
|
|
|
this.pluginDescriptor = pluginDescriptor; |
|
|
|
this.pluginDescriptor = pluginDescriptor; |
|
|
|
this.parentFirst = parentFirst; |
|
|
|
this.classLoadingStrategy = classLoadingStrategy; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
@ -83,7 +91,7 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
* By default, it uses a child first delegation model rather than the standard parent first. |
|
|
|
* By default, it uses a child first delegation model rather than the standard parent first. |
|
|
|
* If the requested class cannot be found in this class loader, the parent class loader will be consulted |
|
|
|
* If the requested class cannot be found in this class loader, the parent class loader will be consulted |
|
|
|
* via the standard {@link ClassLoader#loadClass(String)} mechanism. |
|
|
|
* via the standard {@link ClassLoader#loadClass(String)} mechanism. |
|
|
|
* Use {@link #parentFirst} to change the loading strategy. |
|
|
|
* Use {@link #classLoadingStrategy} to change the loading strategy. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public Class<?> loadClass(String className) throws ClassNotFoundException { |
|
|
|
public Class<?> loadClass(String className) throws ClassNotFoundException { |
|
|
@ -107,63 +115,39 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
log.trace("Found loaded class '{}'", className); |
|
|
|
log.trace("Found loaded class '{}'", className); |
|
|
|
return loadedClass; |
|
|
|
return loadedClass; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (ClassLoadingStrategy.Source classLoadingSource : classLoadingStrategy.getSources()) { |
|
|
|
if (!parentFirst) { |
|
|
|
Class<?> c = null; |
|
|
|
// nope, try to load locally
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
loadedClass = findClass(className); |
|
|
|
|
|
|
|
log.trace("Found class '{}' in plugin classpath", className); |
|
|
|
|
|
|
|
return loadedClass; |
|
|
|
|
|
|
|
} catch (ClassNotFoundException e) { |
|
|
|
|
|
|
|
// try next step
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// look in dependencies
|
|
|
|
|
|
|
|
loadedClass = loadClassFromDependencies(className); |
|
|
|
|
|
|
|
if (loadedClass != null) { |
|
|
|
|
|
|
|
log.trace("Found class '{}' in dependencies", className); |
|
|
|
|
|
|
|
return loadedClass; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.trace("Couldn't find class '{}' in plugin classpath. Delegating to parent", className); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// use the standard ClassLoader (which follows normal parent delegation)
|
|
|
|
|
|
|
|
return super.loadClass(className); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// try to load from parent
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
return super.loadClass(className); |
|
|
|
switch (classLoadingSource) { |
|
|
|
} catch (ClassNotFoundException e) { |
|
|
|
case APPLICATION: |
|
|
|
// try next step
|
|
|
|
c = super.loadClass(className); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case PLUGIN: |
|
|
|
log.trace("Couldn't find class '{}' in parent. Delegating to plugin classpath", className); |
|
|
|
c = findClass(className); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DEPENDENCIES: |
|
|
|
|
|
|
|
c = loadClassFromDependencies(className); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (ClassNotFoundException ignored) { |
|
|
|
|
|
|
|
|
|
|
|
// nope, try to load locally
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
loadedClass = findClass(className); |
|
|
|
|
|
|
|
log.trace("Found class '{}' in plugin classpath", className); |
|
|
|
|
|
|
|
return loadedClass; |
|
|
|
|
|
|
|
} catch (ClassNotFoundException e) { |
|
|
|
|
|
|
|
// try next step
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (c != null) { |
|
|
|
// look in dependencies
|
|
|
|
log.trace("Found class '{}' in {} classpath", className,classLoadingSource); |
|
|
|
loadedClass = loadClassFromDependencies(className); |
|
|
|
return c; |
|
|
|
if (loadedClass != null) { |
|
|
|
} else { |
|
|
|
log.trace("Found class '{}' in dependencies", className); |
|
|
|
log.trace("Couldn't find class '{}' in {} classpath", className,classLoadingSource); |
|
|
|
return loadedClass; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
throw new ClassNotFoundException(className); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
throw new ClassNotFoundException(className); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Load the named resource from this plugin. |
|
|
|
* Load the named resource from this plugin. |
|
|
|
* By default, this implementation checks the plugin's classpath first then delegates to the parent. |
|
|
|
* By default, this implementation checks the plugin's classpath first then delegates to the parent. |
|
|
|
* Use {@link #parentFirst} to change the loading strategy. |
|
|
|
* Use {@link #classLoadingStrategy} to change the loading strategy. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param name the name of the resource. |
|
|
|
* @param name the name of the resource. |
|
|
|
* @return the URL to the resource, {@code null} if the resource was not found. |
|
|
|
* @return the URL to the resource, {@code null} if the resource was not found. |
|
|
@ -171,66 +155,55 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public URL getResource(String name) { |
|
|
|
public URL getResource(String name) { |
|
|
|
log.trace("Received request to load resource '{}'", name); |
|
|
|
log.trace("Received request to load resource '{}'", name); |
|
|
|
if (!parentFirst) { |
|
|
|
for (ClassLoadingStrategy.Source classLoadingSource : classLoadingStrategy.getSources()) { |
|
|
|
URL url = findResource(name); |
|
|
|
URL url = null; |
|
|
|
if (url != null) { |
|
|
|
switch (classLoadingSource) { |
|
|
|
log.trace("Found resource '{}' in plugin classpath", name); |
|
|
|
case APPLICATION: |
|
|
|
return url; |
|
|
|
url = super.getResource(name); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case PLUGIN: |
|
|
|
|
|
|
|
url = findResource(name); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DEPENDENCIES: |
|
|
|
|
|
|
|
url = findResourceFromDependencies(name); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
url = findResourceFromDependencies(name); |
|
|
|
|
|
|
|
if (url != null) { |
|
|
|
if (url != null) { |
|
|
|
log.trace("Found resource '{}' in plugin dependencies", name); |
|
|
|
log.trace("Found resource '{}' in {} classpath", name,classLoadingSource); |
|
|
|
return url; |
|
|
|
return url; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
log.trace("Couldn't find resource '{}' in {}.", name,classLoadingSource); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.trace("Couldn't find resource '{}' in plugin or dependencies classpath. Delegating to parent", name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return super.getResource(name); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
URL url = super.getResource(name); |
|
|
|
|
|
|
|
if (url != null) { |
|
|
|
|
|
|
|
log.trace("Found resource '{}' in parent", name); |
|
|
|
|
|
|
|
return url; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.trace("Couldn't find resource '{}' in parent", name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
url = findResourceFromDependencies(name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (url != null) { |
|
|
|
|
|
|
|
log.trace("Found resource '{}' in dependencies", name); |
|
|
|
|
|
|
|
return url; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return findResource(name); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public Enumeration<URL> getResources(String name) throws IOException { |
|
|
|
public Enumeration<URL> getResources(String name) throws IOException { |
|
|
|
List<URL> resources = new ArrayList<>(); |
|
|
|
List<URL> resources = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
|
|
if (!parentFirst) { |
|
|
|
log.trace("Received request to load resources '{}'", name); |
|
|
|
resources.addAll(Collections.list(findResources(name))); |
|
|
|
for (ClassLoadingStrategy.Source classLoadingSource : classLoadingStrategy.getSources()) { |
|
|
|
resources.addAll(findResourcesFromDependencies(name)); |
|
|
|
switch (classLoadingSource) { |
|
|
|
|
|
|
|
case APPLICATION: |
|
|
|
if (getParent() != null) { |
|
|
|
if (getParent() != null) { |
|
|
|
resources.addAll(Collections.list(getParent().getResources(name))); |
|
|
|
resources.addAll(Collections.list(getParent().getResources(name))); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
break; |
|
|
|
if (getParent() != null) { |
|
|
|
case PLUGIN: |
|
|
|
resources.addAll(Collections.list(getParent().getResources(name))); |
|
|
|
resources.addAll(Collections.list(findResources(name))); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DEPENDENCIES: |
|
|
|
|
|
|
|
resources.addAll(findResourcesFromDependencies(name)); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
resources.addAll(findResourcesFromDependencies(name)); |
|
|
|
|
|
|
|
resources.addAll(Collections.list(super.findResources(name))); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Collections.enumeration(resources); |
|
|
|
|
|
|
|
|
|
|
|
return Collections.enumeration(resources); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Class<?> loadClassFromDependencies(String className) { |
|
|
|
protected Class<?> loadClassFromDependencies(String className) { |
|
|
|
log.trace("Search in dependencies for class '{}'", className); |
|
|
|
log.trace("Search in dependencies for class '{}'", className); |
|
|
|
List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); |
|
|
|
List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); |
|
|
|
for (PluginDependency dependency : dependencies) { |
|
|
|
for (PluginDependency dependency : dependencies) { |
|
|
@ -251,7 +224,7 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private URL findResourceFromDependencies(String name) { |
|
|
|
protected URL findResourceFromDependencies(String name) { |
|
|
|
log.trace("Search in dependencies for resource '{}'", name); |
|
|
|
log.trace("Search in dependencies for resource '{}'", name); |
|
|
|
List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); |
|
|
|
List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); |
|
|
|
for (PluginDependency dependency : dependencies) { |
|
|
|
for (PluginDependency dependency : dependencies) { |
|
|
@ -264,14 +237,14 @@ public class PluginClassLoader extends URLClassLoader { |
|
|
|
|
|
|
|
|
|
|
|
URL url = classLoader.findResource(name); |
|
|
|
URL url = classLoader.findResource(name); |
|
|
|
if (Objects.nonNull(url)) { |
|
|
|
if (Objects.nonNull(url)) { |
|
|
|
return url; |
|
|
|
return url; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Collection<URL> findResourcesFromDependencies(String name) throws IOException { |
|
|
|
protected Collection<URL> findResourcesFromDependencies(String name) throws IOException { |
|
|
|
log.trace("Search in dependencies for resources '{}'", name); |
|
|
|
log.trace("Search in dependencies for resources '{}'", name); |
|
|
|
List<URL> results = new ArrayList<>(); |
|
|
|
List<URL> results = new ArrayList<>(); |
|
|
|
List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); |
|
|
|
List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); |
|
|
|