diff --git a/README.md b/README.md index 55430c4..dc4e01e 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,6 @@ Artifacts Using Maven ------------------- -First you must install the pf4j artifacts in your local maven repository with: - - mvn clean install - -I will upload these artifacts in maven central repository as soon as possible. - In your pom.xml you must define the dependencies to PF4J artifacts with: ```xml @@ -43,8 +37,8 @@ How to use It's very simple to add pf4j in your application: public static void main(String[] args) { - ... - + ... + PluginManager pluginManager = new DefaultPluginManager(); pluginManager.loadPlugins(); pluginManager.startPlugins(); @@ -118,11 +112,15 @@ In above code I supply an extension for the `Greeting` extension point. You can retrieve all extensions for an extension point with: - List> greetings = pluginManager.getExtensions(Greeting.class); - for (ExtensionWrapper greeting : greetings) { - System.out.println(">>> " + greeting.getInstance().getGreeting()); + List greetings = pluginManager.getExtensions(Greeting.class); + for (Greeting greeting : greetings) { + System.out.println(">>> " + greeting.getGreeting()); } +The output is: + + >>> Welcome + >>> Hello For more information please see the demo sources. diff --git a/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java b/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java index 9a361fa..9f218cf 100644 --- a/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java +++ b/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java @@ -17,7 +17,6 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import ro.fortsoft.pf4j.DefaultPluginManager; -import ro.fortsoft.pf4j.ExtensionWrapper; import ro.fortsoft.pf4j.PluginManager; import ro.fortsoft.pf4j.demo.api.Greeting; @@ -37,9 +36,9 @@ public class Boot { pluginManager.loadPlugins(); pluginManager.startPlugins(); - List> greetings = pluginManager.getExtensions(Greeting.class); - for (ExtensionWrapper greeting : greetings) { - System.out.println(">>> " + greeting.getInstance().getGreeting()); + List greetings = pluginManager.getExtensions(Greeting.class); + for (Greeting greeting : greetings) { + System.out.println(">>> " + greeting.getGreeting()); } pluginManager.stopPlugins(); diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/CyclicDependencyException.java b/pf4j/src/main/java/ro/fortsoft/pf4j/CyclicDependencyException.java new file mode 100644 index 0000000..483665c --- /dev/null +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/CyclicDependencyException.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Decebal Suiu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with + * the License. You may obtain a copy of the License in the LICENSE file, or at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package ro.fortsoft.pf4j; + +/** + * CyclicDependencyException will be thrown if a cyclic dependency is detected. + * + * @author Decebal Suiu + */ +class CyclicDependencyException extends PluginException { + + private static final long serialVersionUID = 1L; + + public CyclicDependencyException(String message) { + super(message); + } + +} diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java index ea56e67..2b36357 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java @@ -15,8 +15,6 @@ package ro.fortsoft.pf4j; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -30,7 +28,6 @@ import ro.fortsoft.pf4j.util.UberClassLoader; import ro.fortsoft.pf4j.util.Unzip; import ro.fortsoft.pf4j.util.ZipFilter; - /** * Default implementation of the PluginManager interface. * @@ -52,7 +49,7 @@ public class DefaultPluginManager implements PluginManager { /** * A map of plugins this manager is responsible for (the key is the 'pluginId'). */ - private Map plugins; + private Map plugins; /** * A map of plugin class loaders (he key is the 'pluginId'). @@ -67,17 +64,17 @@ public class DefaultPluginManager implements PluginManager { /** * A list with unresolved plugins (unresolved dependency). */ - private List unresolvedPlugins; + private List unresolvedPlugins; /** * A list with resolved plugins (resolved dependency). */ - private List resolvedPlugins; + private List resolvedPlugins; /** * A list with disabled plugins. */ - private List disabledPlugins; + private List disabledPlugins; private UberClassLoader uberClassLoader; @@ -96,12 +93,12 @@ public class DefaultPluginManager implements PluginManager { */ public DefaultPluginManager(File pluginsDirectory) { this.pluginsDirectory = pluginsDirectory; - plugins = new HashMap(); + plugins = new HashMap(); pluginClassLoaders = new HashMap(); pathToIdMap = new HashMap(); - unresolvedPlugins = new ArrayList(); - resolvedPlugins = new ArrayList(); - disabledPlugins = new ArrayList(); + unresolvedPlugins = new ArrayList(); + resolvedPlugins = new ArrayList(); + disabledPlugins = new ArrayList(); pluginDescriptorFinder = new DefaultPluginDescriptorFinder(); uberClassLoader = new UberClassLoader(); extensionFinder = new DefaultExtensionFinder(uberClassLoader); @@ -110,23 +107,23 @@ public class DefaultPluginManager implements PluginManager { /** * Retrieves all active plugins. */ - public List getPlugins() { - return new ArrayList(plugins.values()); + public List getPlugins() { + return new ArrayList(plugins.values()); } - public List getResolvedPlugins() { + public List getResolvedPlugins() { return resolvedPlugins; } - public Plugin getPlugin(String pluginId) { + public PluginWrapper getPlugin(String pluginId) { return plugins.get(pluginId); } - public List getUnresolvedPlugins() { + public List getUnresolvedPlugins() { return unresolvedPlugins; } - public List getDisabledPlugins() { + public List getDisabledPlugins() { return disabledPlugins; } @@ -134,13 +131,13 @@ public class DefaultPluginManager implements PluginManager { * Start all active plugins. */ public void startPlugins() { - List resolvedPlugins = getResolvedPlugins(); - for (Plugin plugin : resolvedPlugins) { + List resolvedPlugins = getResolvedPlugins(); + for (PluginWrapper pluginWrapper : resolvedPlugins) { try { - plugin.start(); + LOG.info("Start plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'"); + pluginWrapper.getPlugin().start(); } catch (PluginException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + LOG.error(e.getMessage(), e); } } } @@ -149,13 +146,13 @@ public class DefaultPluginManager implements PluginManager { * Stop all active plugins. */ public void stopPlugins() { - List resolvedPlugins = getResolvedPlugins(); - for (Plugin plugin : resolvedPlugins) { + List resolvedPlugins = getResolvedPlugins(); + for (PluginWrapper pluginWrapper : resolvedPlugins) { try { - plugin.stop(); + LOG.info("Stop plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'"); + pluginWrapper.getPlugin().stop(); } catch (PluginException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + LOG.error(e.getMessage(), e); } } } @@ -178,7 +175,6 @@ public class DefaultPluginManager implements PluginManager { expandPluginArchive(zipFile); } catch (IOException e) { LOG.error(e.getMessage(), e); - e.printStackTrace(); } } @@ -188,9 +184,8 @@ public class DefaultPluginManager implements PluginManager { for (String directory : directories) { try { loadPlugin(directory); - } catch (Exception e) { + } catch (PluginException e) { LOG.error(e.getMessage(), e); - e.printStackTrace(); } } @@ -201,7 +196,11 @@ public class DefaultPluginManager implements PluginManager { } // resolve 'unresolvedPlugins' - resolvePlugins(); + try { + resolvePlugins(); + } catch (PluginException e) { + LOG.error(e.getMessage(), e); + } } /** @@ -211,11 +210,17 @@ public class DefaultPluginManager implements PluginManager { return pluginClassLoaders.get(pluginId); } - public List> getExtensions(Class type) { - return extensionFinder.find(type); + public List getExtensions(Class type) { + List> extensionsWrapper = extensionFinder.find(type); + List extensions = new ArrayList(extensionsWrapper.size()); + for (ExtensionWrapper extensionWrapper : extensionsWrapper) { + extensions.add(extensionWrapper.getInstance()); + } + + return extensions; } - private void loadPlugin(String fileName) throws Exception { + private void loadPlugin(String fileName) throws PluginException { // test for plugin directory File pluginDirectory = new File(pluginsDirectory, fileName); if (!pluginDirectory.isDirectory()) { @@ -244,25 +249,20 @@ public class DefaultPluginManager implements PluginManager { // load plugin LOG.debug("Loading plugin '" + pluginPath + "'"); - PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor); - PluginLoader pluginLoader = new PluginLoader(this, pluginWrapper, pluginDirectory); + PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory); pluginLoader.load(); LOG.debug("Loaded plugin '" + pluginPath + "'"); - // set some variables in plugin wrapper - pluginWrapper.setPluginPath(pluginPath); - pluginWrapper.setPluginClassLoader(pluginLoader.getPluginClassLoader()); - - // create the plugin instance - LOG.debug("Creating instance for plugin '" + pluginPath + "'"); - Plugin plugin = getPluginInstance(pluginWrapper, pluginLoader); - LOG.debug("Created instance '" + plugin + "' for plugin '" + pluginPath + "'"); + // create the plugin wrapper + LOG.debug("Creating wrapper for plugin '" + pluginPath + "'"); + PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader()); + LOG.debug("Created wrapper '" + pluginWrapper + "' for plugin '" + pluginPath + "'"); String pluginId = pluginDescriptor.getPluginId(); // add plugin to the list with plugins - plugins.put(pluginId, plugin); - unresolvedPlugins.add(plugin); + plugins.put(pluginId, pluginWrapper); + unresolvedPlugins.add(pluginWrapper); // add plugin class loader to the list with class loaders PluginClassLoader pluginClassLoader = pluginLoader.getPluginClassLoader(); @@ -289,39 +289,17 @@ public class DefaultPluginManager implements PluginManager { } } - private Plugin getPluginInstance(PluginWrapper pluginWrapper, PluginLoader pluginLoader) - throws Exception { - String pluginClassName = pluginWrapper.getDescriptor().getPluginClass(); - - ClassLoader pluginClassLoader = pluginLoader.getPluginClassLoader(); - Class pluginClass = pluginClassLoader.loadClass(pluginClassName); - - // once we have the class, we can do some checks on it to ensure - // that it is a valid implementation of a plugin. - int modifiers = pluginClass.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers) - || (!Plugin.class.isAssignableFrom(pluginClass))) { - throw new PluginException("The plugin class '" + pluginClassName - + "' is not compatible."); - } - - // create the plugin instance - Constructor constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class }); - Plugin plugin = (Plugin) constructor.newInstance(new Object[] { pluginWrapper }); - - return plugin; - } - - private void resolvePlugins() { - resolveDependencies(); + private void resolvePlugins() throws PluginException { + resolveDependencies(); } - private void resolveDependencies() { + private void resolveDependencies() throws PluginException { DependencyResolver dependencyResolver = new DependencyResolver(unresolvedPlugins); - resolvedPlugins = dependencyResolver.getSortedDependencies(); - for (Plugin plugin : resolvedPlugins) { - unresolvedPlugins.remove(plugin); - uberClassLoader.addLoader(plugin.getWrapper().getPluginClassLoader()); + resolvedPlugins = dependencyResolver.getSortedPlugins(); + for (PluginWrapper pluginWrapper : resolvedPlugins) { + unresolvedPlugins.remove(pluginWrapper); + uberClassLoader.addLoader(pluginWrapper.getPluginClassLoader()); + LOG.info("Plugin '" + pluginWrapper.getDescriptor().getPluginId() + "' resolved"); } } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java index 7485b22..524d4cc 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java @@ -28,24 +28,24 @@ class DependencyResolver { private static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class); - private List plugins; + private List plugins; - public DependencyResolver(List plugins) { + public DependencyResolver(List plugins) { this.plugins = plugins; } /** * Get the list of plugins in dependency sorted order. */ - public List getSortedDependencies() { + public List getSortedPlugins() throws PluginException { DirectedGraph graph = new DirectedGraph(); - for (Plugin plugin : plugins) { - PluginDescriptor descriptor = plugin.getWrapper().getDescriptor(); + for (PluginWrapper pluginWrapper : plugins) { + PluginDescriptor descriptor = pluginWrapper.getDescriptor(); String pluginId = descriptor.getPluginId(); - List dependencies = descriptor.getDependencies(); + List dependencies = descriptor.getDependencies(); if (!dependencies.isEmpty()) { - for (String dependency : dependencies) { - graph.addEdge(pluginId, dependency); + for (PluginDependency dependency : dependencies) { + graph.addEdge(pluginId, dependency.getPluginId()); } } else { graph.addVertex(pluginId); @@ -56,12 +56,11 @@ class DependencyResolver { List pluginsId = graph.reverseTopologicalSort(); if (pluginsId == null) { - LOG.error("Cyclic dependences !!!"); - return null; + throw new CyclicDependencyException("Cyclic dependences !!!" + graph.toString()); } LOG.debug("Plugins order: " + pluginsId); - List sortedPlugins = new ArrayList(); + List sortedPlugins = new ArrayList(); for (String pluginId : pluginsId) { sortedPlugins.add(getPlugin(pluginId)); } @@ -69,14 +68,14 @@ class DependencyResolver { return sortedPlugins; } - private Plugin getPlugin(String pluginId) { - for (Plugin plugin : plugins) { - if (pluginId.equals(plugin.getWrapper().getDescriptor().getPluginId())) { - return plugin; + private PluginWrapper getPlugin(String pluginId) throws PluginNotFoundException { + for (PluginWrapper pluginWrapper : plugins) { + if (pluginId.equals(pluginWrapper.getDescriptor().getPluginId())) { + return pluginWrapper; } } - return null; + throw new PluginNotFoundException(pluginId); } } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java index 1d80c92..2f7ce1e 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java @@ -28,13 +28,13 @@ class PluginClassLoader extends URLClassLoader { private static final String PLUGIN_PACKAGE_PREFIX = "ro.fortsoft.pf4j."; private PluginManager pluginManager; - private PluginWrapper pluginWrapper; - - public PluginClassLoader(PluginManager pluginManager, PluginWrapper pluginWrapper, ClassLoader parent) { + private PluginDescriptor pluginDescriptor; + + public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) { super(new URL[0], parent); this.pluginManager = pluginManager; - this.pluginWrapper = pluginWrapper; + this.pluginDescriptor = pluginDescriptor; } @Override @@ -74,9 +74,9 @@ class PluginClassLoader extends URLClassLoader { } // look in dependencies - List dependencies = pluginWrapper.getDescriptor().getDependencies(); - for (String dependency : dependencies) { - PluginClassLoader classLoader = pluginManager.getPluginClassLoader(dependency); + List dependencies = pluginDescriptor.getDependencies(); + for (PluginDependency dependency : dependencies) { + PluginClassLoader classLoader = pluginManager.getPluginClassLoader(dependency.getPluginId()); try { return classLoader.loadClass(className); } catch (ClassNotFoundException e) { diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDependency.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDependency.java new file mode 100644 index 0000000..d63b66a --- /dev/null +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDependency.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012 Decebal Suiu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with + * the License. You may obtain a copy of the License in the LICENSE file, or at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package ro.fortsoft.pf4j; + +/** + * @author Decebal Suiu + */ +public class PluginDependency { + + private String pluginId; + private PluginVersion pluginVersion; + + public PluginDependency(String dependency) { + /* + int index = dependency.indexOf(':'); + if (index == -1) { + throw new IllegalArgumentException("Illegal dependency specifier "+ dependency); + } + + this.pluginId = dependency.substring(0, index); + this.pluginVersion = PluginVersion.createVersion(dependency.substring(index + 1)); + */ + this.pluginId = dependency; + } + + public String getPluginId() { + return pluginId; + } + + public PluginVersion getPluginVersion() { + return pluginVersion; + } + + @Override + public String toString() { + return "PluginDependency [pluginId=" + pluginId + ", pluginVersion=" + pluginVersion + "]"; + } + +} diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java index 494877e..aa2c495 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java @@ -33,12 +33,11 @@ class PluginDescriptor { private String pluginClass; private PluginVersion version; private String provider; - private String pluginPath; - private List dependencies; + private List dependencies; private PluginClassLoader pluginClassLoader; public PluginDescriptor() { - dependencies = new ArrayList(); + dependencies = new ArrayList(); } /** @@ -69,18 +68,11 @@ class PluginDescriptor { return provider; } - /** - * Returns the path of this plugin relative to plugins directory. - */ - public String getPluginPath() { - return pluginPath; - } - /** * Returns all dependencies declared by this plugin. * Returns an empty array if this plugin does not declare any require. */ - public List getDependencies() { + public List getDependencies() { return dependencies; } @@ -100,7 +92,6 @@ class PluginDescriptor { .append("pluginClass", pluginClass) .append("version", version) .append("provider", provider) - .append("pluginPath", pluginPath) .append("dependencies", dependencies) .toString(); } @@ -120,14 +111,14 @@ class PluginDescriptor { void setProvider(String provider) { this.provider = provider; } - - void setPluginPath(String pluginPath) { - this.pluginPath = pluginPath; - } void setDependencies(String dependencies) { if (dependencies != null) { - this.dependencies = Arrays.asList(StringUtils.split(dependencies, ',')); + this.dependencies = new ArrayList(); + List tokens = Arrays.asList(StringUtils.split(dependencies, ',')); + for (String dependency : tokens) { + this.dependencies.add(new PluginDependency(dependency)); + } } else { this.dependencies = Collections.emptyList(); } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java index 8ae65e7..7533f57 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java @@ -23,7 +23,6 @@ import org.slf4j.LoggerFactory; import ro.fortsoft.pf4j.util.DirectoryFilter; import ro.fortsoft.pf4j.util.JarFilter; - /** * Load all informations needed by a plugin. * This means add all jar files from 'lib' directory, 'classes' @@ -53,12 +52,12 @@ class PluginLoader { private PluginClassLoader pluginClassLoader; - public PluginLoader(PluginManager pluginManager, PluginWrapper pluginWrapper, File pluginRepository) { + public PluginLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, File pluginRepository) { this.pluginRepository = pluginRepository; classesDirectory = new File(pluginRepository, "classes"); libDirectory = new File(pluginRepository, "lib"); ClassLoader parent = getClass().getClassLoader(); - pluginClassLoader = new PluginClassLoader(pluginManager, pluginWrapper, parent); + pluginClassLoader = new PluginClassLoader(pluginManager, pluginDescriptor, parent); LOG.debug("Created class loader " + pluginClassLoader); } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java index e191e22..c8e4fe9 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java @@ -25,7 +25,7 @@ public interface PluginManager { /** * Retrieves all plugins. */ - public List getPlugins(); + public List getPlugins(); /** * Load plugins. @@ -44,6 +44,6 @@ public interface PluginManager { public PluginClassLoader getPluginClassLoader(String pluginId); - public List> getExtensions(Class type); + public List getExtensions(Class type); } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginNotFoundException.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginNotFoundException.java new file mode 100644 index 0000000..67658f3 --- /dev/null +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginNotFoundException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012 Decebal Suiu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with + * the License. You may obtain a copy of the License in the LICENSE file, or at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package ro.fortsoft.pf4j; + +/** + * @author Decebal Suiu + */ +class PluginNotFoundException extends PluginException { + + private static final long serialVersionUID = 1L; + + private String pluginId; + + public PluginNotFoundException(String pluginId) { + super("Plugin '" + pluginId + "' not found."); + + this.pluginId = pluginId; + } + + public String getPluginId() { + return pluginId; + } + +} diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java index 6d935e0..a1a6368 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java @@ -12,6 +12,12 @@ */ package ro.fortsoft.pf4j; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + /** * A wrapper over plugin instance. * @@ -22,9 +28,20 @@ public class PluginWrapper { PluginDescriptor descriptor; String pluginPath; PluginClassLoader pluginClassLoader; + Plugin plugin; - public PluginWrapper(PluginDescriptor descriptor) { + public PluginWrapper(PluginDescriptor descriptor, String pluginPath, PluginClassLoader pluginClassLoader) { this.descriptor = descriptor; + this.pluginPath = pluginPath; + this.pluginClassLoader = pluginClassLoader; + + // TODO + try { + plugin = createPluginInstance(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } /** @@ -50,12 +67,36 @@ public class PluginWrapper { return pluginClassLoader; } - void setPluginPath(String pluginPath) { - this.pluginPath = pluginPath; + public Plugin getPlugin() { + return plugin; } - void setPluginClassLoader(PluginClassLoader pluginClassLoader) { - this.pluginClassLoader = pluginClassLoader; - } + private Plugin createPluginInstance() throws Exception { + String pluginClassName = descriptor.getPluginClass(); + Class pluginClass = pluginClassLoader.loadClass(pluginClassName); + + // once we have the class, we can do some checks on it to ensure + // that it is a valid implementation of a plugin. + int modifiers = pluginClass.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers) + || (!Plugin.class.isAssignableFrom(pluginClass))) { + throw new PluginException("The plugin class '" + pluginClassName + "' is not compatible."); + } + + // create the plugin instance + Constructor constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class }); + Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this }); + + return plugin; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("descriptor", descriptor) + .append("pluginPath", pluginPath) + .append("plugin", plugin) + .toString(); + } }