aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java3
-rw-r--r--pf4j/src/main/java/org/pf4j/PluginClassLoader.java156
-rw-r--r--pf4j/src/main/java/org/pf4j/PluginDescriptor.java4
3 files changed, 111 insertions, 52 deletions
diff --git a/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java b/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java
index 5fa2935..61a7d2a 100644
--- a/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java
+++ b/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java
@@ -20,9 +20,6 @@ import java.util.Collections;
import java.util.List;
/**
- * A plugin descriptor contains information about a plug-in obtained
- * from the manifest (META-INF) file.
- *
* @author Decebal Suiu
*/
public class DefaultPluginDescriptor implements PluginDescriptor {
diff --git a/pf4j/src/main/java/org/pf4j/PluginClassLoader.java b/pf4j/src/main/java/org/pf4j/PluginClassLoader.java
index 586f1b3..6863c3d 100644
--- a/pf4j/src/main/java/org/pf4j/PluginClassLoader.java
+++ b/pf4j/src/main/java/org/pf4j/PluginClassLoader.java
@@ -26,8 +26,9 @@ import java.util.List;
/**
* One instance of this class should be created by plugin manager for every available plug-in.
- * 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.
+ * Use {@link #parentFirst} to change the loading strategy.
*
* @author Decebal Suiu
*/
@@ -35,19 +36,30 @@ public class PluginClassLoader extends URLClassLoader {
private static final Logger log = LoggerFactory.getLogger(PluginClassLoader.class);
+ private static final String JAVA_PACKAGE_PREFIX = "java.";
private static final String PLUGIN_PACKAGE_PREFIX = "org.pf4j.";
private PluginManager pluginManager;
private PluginDescriptor pluginDescriptor;
+ private boolean parentFirst;
- public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) {
+ public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) {
+ this(pluginManager, pluginDescriptor, parent, false);
+ }
+
+ /**
+ * If {@code parentFirst} is {@code true}, indicates that the parent {@link ClassLoader} should be consulted
+ * before trying to load the a class through this loader.
+ */
+ public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent, boolean parentFirst) {
super(new URL[0], parent);
this.pluginManager = pluginManager;
this.pluginDescriptor = pluginDescriptor;
+ this.parentFirst = parentFirst;
}
- @Override
+ @Override
public void addURL(URL url) {
log.debug("Add '{}'", url);
super.addURL(url);
@@ -63,83 +75,133 @@ public class PluginClassLoader extends URLClassLoader {
}
/**
- * 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
* via the standard {@link ClassLoader#loadClass(String)} mechanism.
+ * Use {@link #parentFirst} to change the loading strategy.
*/
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
synchronized (getClassLoadingLock(className)) {
- log.trace("Received request to load class '{}'", className);
+ // first check whether it's a system class, delegate to the system loader
+ if (className.startsWith(JAVA_PACKAGE_PREFIX)) {
+ return findSystemClass(className);
+ }
+
// if the class it's a part of the plugin engine use parent class loader
- if (className.startsWith(PLUGIN_PACKAGE_PREFIX)) {
- log.trace("Delegate the loading of class '{}' to parent", className);
- try {
- return getClass().getClassLoader().loadClass(className);
- } catch (ClassNotFoundException e) {
- // try next step
- }
+ if (className.startsWith(PLUGIN_PACKAGE_PREFIX) && !className.startsWith("org.pf4j.demo")) {
+// log.trace("Delegate the loading of PF4J class '{}' to parent", className);
+ return getParent().loadClass(className);
}
+ log.trace("Received request to load class '{}'", className);
+
// second check whether it's already been loaded
- Class<?> clazz = findLoadedClass(className);
- if (clazz != null) {
+ Class<?> loadedClass = findLoadedClass(className);
+ if (loadedClass != null) {
log.trace("Found loaded class '{}'", className);
- return clazz;
+ return loadedClass;
}
- // nope, try to load locally
- try {
- clazz = findClass(className);
- log.trace("Found class '{}' in plugin classpath", className);
- return clazz;
- } catch (ClassNotFoundException e) {
- // try next step
- }
+ if (!parentFirst) {
+ // 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 {
+ return super.loadClass(className);
+ } catch (ClassCastException e) {
+ // try next step
+ }
- // look in dependencies
- log.trace("Search in dependencies for class '{}'", className);
- List<PluginDependency> dependencies = pluginDescriptor.getDependencies();
- for (PluginDependency dependency : dependencies) {
- ClassLoader classLoader = pluginManager.getPluginClassLoader(dependency.getPluginId());
+ log.trace("Couldn't find class '{}' in parent. Delegating to plugin classpath", className);
+
+ // nope, try to load locally
try {
- return classLoader.loadClass(className);
+ loadedClass = findClass(className);
+ log.trace("Found class '{}' in plugin classpath", className);
+ return loadedClass;
} catch (ClassNotFoundException e) {
- // try next dependency
+ // try next step
}
- }
- log.trace("Couldn't find class '{}' in plugin classpath. Delegating to parent", className);
+ // look in dependencies
+ loadedClass = loadClassFromDependencies(className);
+ if (loadedClass != null) {
+ log.trace("Found class '{}' in dependencies", className);
+ return loadedClass;
+ }
- // use the standard ClassLoader (which follows normal parent delegation)
- return super.loadClass(className);
+ throw new ClassNotFoundException(className);
+ }
}
}
/**
* Load the named resource from this plugin.
- * 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.
*
* @param name the name of the resource.
- * @return the URL to the resource, <code>null</code> if the resource was not found.
+ * @return the URL to the resource, {@code null} if the resource was not found.
*/
@Override
public URL getResource(String name) {
- log.trace("Trying to find resource '{}' in plugin classpath", name);
- URL url = findResource(name);
- if (url != null) {
- log.trace("Found resource '{}' in plugin classpath", name);
- return url;
- }
+ log.trace("Received request to load resource '{}'", name);
+ if (!parentFirst) {
+ URL url = findResource(name);
+ if (url != null) {
+ log.trace("Found resource '{}' in plugin classpath", name);
+ return url;
+ }
+
+ log.trace("Couldn't find resource '{}' in plugin 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 plugin classpath. Delegating to parent");
+ log.trace("Couldn't find resource '{}' in parent", name);
- return super.getResource(name);
+ return findResource(name);
+ }
}
- @Override
- public URL findResource(String name) {
- return super.findResource(name);
+ private Class<?> loadClassFromDependencies(String className) {
+ log.trace("Search in dependencies for class '{}'", className);
+ List<PluginDependency> dependencies = pluginDescriptor.getDependencies();
+ for (PluginDependency dependency : dependencies) {
+ ClassLoader classLoader = pluginManager.getPluginClassLoader(dependency.getPluginId());
+ try {
+ return classLoader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ // try next dependency
+ }
+ }
+
+ return null;
}
}
diff --git a/pf4j/src/main/java/org/pf4j/PluginDescriptor.java b/pf4j/src/main/java/org/pf4j/PluginDescriptor.java
index ab08d68..75bacfc 100644
--- a/pf4j/src/main/java/org/pf4j/PluginDescriptor.java
+++ b/pf4j/src/main/java/org/pf4j/PluginDescriptor.java
@@ -18,8 +18,7 @@ package org.pf4j;
import java.util.List;
/**
- * A plugin descriptor contains information about a plug-in obtained
- * from the manifest (META-INF) file.
+ * A plugin descriptor contains information about a plug-in.
*
* @author Decebal Suiu
*/
@@ -40,4 +39,5 @@ public interface PluginDescriptor {
String getLicense();
List<PluginDependency> getDependencies();
+
}