diff options
author | Decebal Suiu <decebal.suiu@gmail.com> | 2014-06-11 13:30:30 +0300 |
---|---|---|
committer | Decebal Suiu <decebal.suiu@gmail.com> | 2014-06-11 13:30:30 +0300 |
commit | e58e71a0980e8a87d51903006c7a7cba6f317135 (patch) | |
tree | 54fd1bae7c857277ded67fab03bce2f37147d41b /pf4j | |
parent | f508484004b0d71bd146eadd0cb1f7de1db43952 (diff) | |
download | pf4j-e58e71a0980e8a87d51903006c7a7cba6f317135.tar.gz pf4j-e58e71a0980e8a87d51903006c7a7cba6f317135.zip |
load extensions from classpath; before this commit only plugins can declare extensions
Diffstat (limited to 'pf4j')
-rw-r--r-- | pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java | 69 | ||||
-rw-r--r-- | pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java | 59 |
2 files changed, 98 insertions, 30 deletions
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java index 3234163..0f04ed7 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java @@ -57,16 +57,24 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe for (Map.Entry<String, Set<String>> entry : entries.entrySet()) { String pluginId = entry.getKey(); - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId); - if (PluginState.STARTED != pluginWrapper.getPluginState()) { - continue; + if (pluginId != null) { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId); + if (PluginState.STARTED != pluginWrapper.getPluginState()) { + continue; + } } Set<String> extensionClassNames = entry.getValue(); for (String className : extensionClassNames) { try { - Class<?> extensionType = pluginManager.getPluginClassLoader(pluginId).loadClass(className); + Class<?> extensionType; + if (pluginId != null) { + extensionType = pluginManager.getPluginClassLoader(pluginId).loadClass(className); + } else { + extensionType = getClass().getClassLoader().loadClass(className); + } + log.debug("Checking extension type '{}'", extensionType.getName()); if (type.isAssignableFrom(extensionType)) { Object instance = extensionFactory.create(extensionType); @@ -140,36 +148,71 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe return entries; } - entries = new HashMap<String, Set<String>>(); + entries = new LinkedHashMap<String, Set<String>>(); + + readClasspathIndexFiles(); + readPluginsIndexFiles(); + + return entries; + } + + private void readClasspathIndexFiles() { + log.debug("Reading extensions index files from classpath"); + + Set<String> bucket = new HashSet<String>(); + try { + Enumeration<URL> urls = getClass().getClassLoader().getResources(ExtensionsIndexer.EXTENSIONS_RESOURCE); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + log.debug("Read '{}'", url.getFile()); + Reader reader = new InputStreamReader(url.openStream(), "UTF-8"); + ExtensionsIndexer.readIndex(reader, bucket); + } + + if (bucket.isEmpty()) { + log.debug("No extensions found"); + } else { + log.debug("Found possible {} extensions:", bucket.size()); + for (String entry : bucket) { + log.debug(" " + entry); + } + } + + entries.put(null, bucket); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + + private void readPluginsIndexFiles() { + log.debug("Reading extensions index files from plugins"); List<PluginWrapper> plugins = pluginManager.getPlugins(); for (PluginWrapper plugin : plugins) { String pluginId = plugin.getDescriptor().getPluginId(); log.debug("Reading extensions index file for plugin '{}'", pluginId); - Set<String> entriesPerPlugin = new HashSet<String>(); + Set<String> bucket = new HashSet<String>(); try { URL url = plugin.getPluginClassLoader().getResource(ExtensionsIndexer.EXTENSIONS_RESOURCE); log.debug("Read '{}'", url.getFile()); Reader reader = new InputStreamReader(url.openStream(), "UTF-8"); - ExtensionsIndexer.readIndex(reader, entriesPerPlugin); + ExtensionsIndexer.readIndex(reader, bucket); - if (entriesPerPlugin.isEmpty()) { + if (bucket.isEmpty()) { log.debug("No extensions found"); } else { - log.debug("Found possible {} extensions:", entriesPerPlugin.size()); - for (String entry : entriesPerPlugin) { + log.debug("Found possible {} extensions:", bucket.size()); + for (String entry : bucket) { log.debug(" " + entry); } } - entries.put(pluginId, entriesPerPlugin); + entries.put(pluginId, bucket); } catch (IOException e) { log.error(e.getMessage(), e); } } - - return entries; } private boolean isExtensionPoint(Class<?> type) { diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java index 055c163..8167565 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java @@ -29,8 +29,6 @@ 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 JAVAX_PACKAGE_PREFIX = "javax."; private static final String PLUGIN_PACKAGE_PREFIX = "ro.fortsoft.pf4j."; private PluginManager pluginManager; @@ -48,41 +46,45 @@ public class PluginClassLoader extends URLClassLoader { super.addURL(url); } + /** + * This implementation of loadClass 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 ClassLoader.loadClass(String) mechanism. + */ @Override public Class<?> loadClass(String className) throws ClassNotFoundException { -// System.out.println(">>>" + className); - - /* - // javax.mail is not in JDK ?! - // first check whether it's a system class, delegate to the system loader - if (className.startsWith(JAVA_PACKAGE_PREFIX) || className.startsWith(JAVAX_PACKAGE_PREFIX)) { - return findSystemClass(className); - } - */ - + log.debug("Received request to load class '{}'", className); // if the class it's a part of the plugin engine use parent class loader if (className.startsWith(PLUGIN_PACKAGE_PREFIX)) { + log.debug("Delegate the loading of class '{}' to parent", className); try { - return PluginClassLoader.class.getClassLoader().loadClass(className); + return getClass().getClassLoader().loadClass(className); } catch (ClassNotFoundException e) { // try next step + // TODO if I uncomment below lines (the correct approach) I received ClassNotFoundException for demo (ro.fortsoft.pf4j.demo) +// log.error(e.getMessage(), e); +// throw e; } } // second check whether it's already been loaded - Class<?> loadedClass = findLoadedClass(className); - if (loadedClass != null) { - return loadedClass; + Class<?> clazz = findLoadedClass(className); + if (clazz != null) { + log.debug("Found loaded class '{}'", className); + return clazz; } // nope, try to load locally try { - return findClass(className); + clazz = findClass(className); + log.debug("Found class '{}' in plugin classpath", className); + return clazz; } catch (ClassNotFoundException e) { // try next step } // look in dependencies + log.debug("Look in dependencies for class '{}'", className); List<PluginDependency> dependencies = pluginDescriptor.getDependencies(); for (PluginDependency dependency : dependencies) { PluginClassLoader classLoader = pluginManager.getPluginClassLoader(dependency.getPluginId()); @@ -93,11 +95,34 @@ public class PluginClassLoader extends URLClassLoader { } } + log.debug("Couldn't find class '{}' in plugin classpath. Delegating to parent"); + // use the standard URLClassLoader (which follows normal parent delegation) return super.loadClass(className); } /** + * Load the named resource from this plugin. This implementation checks the plugin's classpath first + * then delegates to the parent. + * + * @param name the name of the resource. + * @return the URL to the resource, <code>null</code> if the resource was not found. + */ + @Override + public URL getResource(String name) { + log.debug("Trying to find resource '{}' in plugin classpath", name); + URL url = findResource(name); + if (url != null) { + log.debug("Found resource '{}' in plugin classpath", name); + return url; + } + + log.debug("Couldn't find resource '{}' in plugin classpath. Delegating to parent"); + + return super.getResource(name); + } + + /** * Release all resources acquired by this class loader. * The current implementation is incomplete. * For now, this instance can no longer be used to load |