Browse Source

work on plugin dependecy

pull/3/head
Decebal Suiu 12 years ago
parent
commit
07550657ef
  1. 20
      README.md
  2. 7
      demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java
  3. 28
      pf4j/src/main/java/ro/fortsoft/pf4j/CyclicDependencyException.java
  4. 130
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
  5. 31
      pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java
  6. 14
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
  7. 49
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginDependency.java
  8. 25
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java
  9. 5
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
  10. 4
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
  11. 34
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginNotFoundException.java
  12. 53
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java

20
README.md

@ -20,12 +20,6 @@ Artifacts
Using Maven 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: In your pom.xml you must define the dependencies to PF4J artifacts with:
```xml ```xml
@ -43,8 +37,8 @@ How to use
It's very simple to add pf4j in your application: It's very simple to add pf4j in your application:
public static void main(String[] args) { public static void main(String[] args) {
... ...
PluginManager pluginManager = new DefaultPluginManager(); PluginManager pluginManager = new DefaultPluginManager();
pluginManager.loadPlugins(); pluginManager.loadPlugins();
pluginManager.startPlugins(); 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: You can retrieve all extensions for an extension point with:
List<ExtensionWrapper<Greeting>> greetings = pluginManager.getExtensions(Greeting.class); List<Greeting> greetings = pluginManager.getExtensions(Greeting.class);
for (ExtensionWrapper<Greeting> greeting : greetings) { for (Greeting greeting : greetings) {
System.out.println(">>> " + greeting.getInstance().getGreeting()); System.out.println(">>> " + greeting.getGreeting());
} }
The output is:
>>> Welcome
>>> Hello
For more information please see the demo sources. For more information please see the demo sources.

7
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 org.apache.commons.lang.StringUtils;
import ro.fortsoft.pf4j.DefaultPluginManager; import ro.fortsoft.pf4j.DefaultPluginManager;
import ro.fortsoft.pf4j.ExtensionWrapper;
import ro.fortsoft.pf4j.PluginManager; import ro.fortsoft.pf4j.PluginManager;
import ro.fortsoft.pf4j.demo.api.Greeting; import ro.fortsoft.pf4j.demo.api.Greeting;
@ -37,9 +36,9 @@ public class Boot {
pluginManager.loadPlugins(); pluginManager.loadPlugins();
pluginManager.startPlugins(); pluginManager.startPlugins();
List<ExtensionWrapper<Greeting>> greetings = pluginManager.getExtensions(Greeting.class); List<Greeting> greetings = pluginManager.getExtensions(Greeting.class);
for (ExtensionWrapper<Greeting> greeting : greetings) { for (Greeting greeting : greetings) {
System.out.println(">>> " + greeting.getInstance().getGreeting()); System.out.println(">>> " + greeting.getGreeting());
} }
pluginManager.stopPlugins(); pluginManager.stopPlugins();

28
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);
}
}

130
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java

@ -15,8 +15,6 @@ package ro.fortsoft.pf4j;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; 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.Unzip;
import ro.fortsoft.pf4j.util.ZipFilter; import ro.fortsoft.pf4j.util.ZipFilter;
/** /**
* Default implementation of the PluginManager interface. * 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'). * A map of plugins this manager is responsible for (the key is the 'pluginId').
*/ */
private Map<String, Plugin> plugins; private Map<String, PluginWrapper> plugins;
/** /**
* A map of plugin class loaders (he key is the 'pluginId'). * 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). * A list with unresolved plugins (unresolved dependency).
*/ */
private List<Plugin> unresolvedPlugins; private List<PluginWrapper> unresolvedPlugins;
/** /**
* A list with resolved plugins (resolved dependency). * A list with resolved plugins (resolved dependency).
*/ */
private List<Plugin> resolvedPlugins; private List<PluginWrapper> resolvedPlugins;
/** /**
* A list with disabled plugins. * A list with disabled plugins.
*/ */
private List<Plugin> disabledPlugins; private List<PluginWrapper> disabledPlugins;
private UberClassLoader uberClassLoader; private UberClassLoader uberClassLoader;
@ -96,12 +93,12 @@ public class DefaultPluginManager implements PluginManager {
*/ */
public DefaultPluginManager(File pluginsDirectory) { public DefaultPluginManager(File pluginsDirectory) {
this.pluginsDirectory = pluginsDirectory; this.pluginsDirectory = pluginsDirectory;
plugins = new HashMap<String, Plugin>(); plugins = new HashMap<String, PluginWrapper>();
pluginClassLoaders = new HashMap<String, PluginClassLoader>(); pluginClassLoaders = new HashMap<String, PluginClassLoader>();
pathToIdMap = new HashMap<String, String>(); pathToIdMap = new HashMap<String, String>();
unresolvedPlugins = new ArrayList<Plugin>(); unresolvedPlugins = new ArrayList<PluginWrapper>();
resolvedPlugins = new ArrayList<Plugin>(); resolvedPlugins = new ArrayList<PluginWrapper>();
disabledPlugins = new ArrayList<Plugin>(); disabledPlugins = new ArrayList<PluginWrapper>();
pluginDescriptorFinder = new DefaultPluginDescriptorFinder(); pluginDescriptorFinder = new DefaultPluginDescriptorFinder();
uberClassLoader = new UberClassLoader(); uberClassLoader = new UberClassLoader();
extensionFinder = new DefaultExtensionFinder(uberClassLoader); extensionFinder = new DefaultExtensionFinder(uberClassLoader);
@ -110,23 +107,23 @@ public class DefaultPluginManager implements PluginManager {
/** /**
* Retrieves all active plugins. * Retrieves all active plugins.
*/ */
public List<Plugin> getPlugins() { public List<PluginWrapper> getPlugins() {
return new ArrayList<Plugin>(plugins.values()); return new ArrayList<PluginWrapper>(plugins.values());
} }
public List<Plugin> getResolvedPlugins() { public List<PluginWrapper> getResolvedPlugins() {
return resolvedPlugins; return resolvedPlugins;
} }
public Plugin getPlugin(String pluginId) { public PluginWrapper getPlugin(String pluginId) {
return plugins.get(pluginId); return plugins.get(pluginId);
} }
public List<Plugin> getUnresolvedPlugins() { public List<PluginWrapper> getUnresolvedPlugins() {
return unresolvedPlugins; return unresolvedPlugins;
} }
public List<Plugin> getDisabledPlugins() { public List<PluginWrapper> getDisabledPlugins() {
return disabledPlugins; return disabledPlugins;
} }
@ -134,13 +131,13 @@ public class DefaultPluginManager implements PluginManager {
* Start all active plugins. * Start all active plugins.
*/ */
public void startPlugins() { public void startPlugins() {
List<Plugin> resolvedPlugins = getResolvedPlugins(); List<PluginWrapper> resolvedPlugins = getResolvedPlugins();
for (Plugin plugin : resolvedPlugins) { for (PluginWrapper pluginWrapper : resolvedPlugins) {
try { try {
plugin.start(); LOG.info("Start plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
pluginWrapper.getPlugin().start();
} catch (PluginException e) { } catch (PluginException e) {
// TODO Auto-generated catch block LOG.error(e.getMessage(), e);
e.printStackTrace();
} }
} }
} }
@ -149,13 +146,13 @@ public class DefaultPluginManager implements PluginManager {
* Stop all active plugins. * Stop all active plugins.
*/ */
public void stopPlugins() { public void stopPlugins() {
List<Plugin> resolvedPlugins = getResolvedPlugins(); List<PluginWrapper> resolvedPlugins = getResolvedPlugins();
for (Plugin plugin : resolvedPlugins) { for (PluginWrapper pluginWrapper : resolvedPlugins) {
try { try {
plugin.stop(); LOG.info("Stop plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
pluginWrapper.getPlugin().stop();
} catch (PluginException e) { } catch (PluginException e) {
// TODO Auto-generated catch block LOG.error(e.getMessage(), e);
e.printStackTrace();
} }
} }
} }
@ -178,7 +175,6 @@ public class DefaultPluginManager implements PluginManager {
expandPluginArchive(zipFile); expandPluginArchive(zipFile);
} catch (IOException e) { } catch (IOException e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
e.printStackTrace();
} }
} }
@ -188,9 +184,8 @@ public class DefaultPluginManager implements PluginManager {
for (String directory : directories) { for (String directory : directories) {
try { try {
loadPlugin(directory); loadPlugin(directory);
} catch (Exception e) { } catch (PluginException e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
e.printStackTrace();
} }
} }
@ -201,7 +196,11 @@ public class DefaultPluginManager implements PluginManager {
} }
// resolve 'unresolvedPlugins' // 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); return pluginClassLoaders.get(pluginId);
} }
public <T> List<ExtensionWrapper<T>> getExtensions(Class<T> type) { public <T> List<T> getExtensions(Class<T> type) {
return extensionFinder.find(type); List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
List<T> extensions = new ArrayList<T>(extensionsWrapper.size());
for (ExtensionWrapper<T> 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 // test for plugin directory
File pluginDirectory = new File(pluginsDirectory, fileName); File pluginDirectory = new File(pluginsDirectory, fileName);
if (!pluginDirectory.isDirectory()) { if (!pluginDirectory.isDirectory()) {
@ -244,25 +249,20 @@ public class DefaultPluginManager implements PluginManager {
// load plugin // load plugin
LOG.debug("Loading plugin '" + pluginPath + "'"); LOG.debug("Loading plugin '" + pluginPath + "'");
PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor); PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory);
PluginLoader pluginLoader = new PluginLoader(this, pluginWrapper, pluginDirectory);
pluginLoader.load(); pluginLoader.load();
LOG.debug("Loaded plugin '" + pluginPath + "'"); LOG.debug("Loaded plugin '" + pluginPath + "'");
// set some variables in plugin wrapper // create the plugin wrapper
pluginWrapper.setPluginPath(pluginPath); LOG.debug("Creating wrapper for plugin '" + pluginPath + "'");
pluginWrapper.setPluginClassLoader(pluginLoader.getPluginClassLoader()); PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader());
LOG.debug("Created wrapper '" + pluginWrapper + "' for plugin '" + pluginPath + "'");
// create the plugin instance
LOG.debug("Creating instance for plugin '" + pluginPath + "'");
Plugin plugin = getPluginInstance(pluginWrapper, pluginLoader);
LOG.debug("Created instance '" + plugin + "' for plugin '" + pluginPath + "'");
String pluginId = pluginDescriptor.getPluginId(); String pluginId = pluginDescriptor.getPluginId();
// add plugin to the list with plugins // add plugin to the list with plugins
plugins.put(pluginId, plugin); plugins.put(pluginId, pluginWrapper);
unresolvedPlugins.add(plugin); unresolvedPlugins.add(pluginWrapper);
// add plugin class loader to the list with class loaders // add plugin class loader to the list with class loaders
PluginClassLoader pluginClassLoader = pluginLoader.getPluginClassLoader(); PluginClassLoader pluginClassLoader = pluginLoader.getPluginClassLoader();
@ -289,39 +289,17 @@ public class DefaultPluginManager implements PluginManager {
} }
} }
private Plugin getPluginInstance(PluginWrapper pluginWrapper, PluginLoader pluginLoader) private void resolvePlugins() throws PluginException {
throws Exception { resolveDependencies();
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 resolveDependencies() { private void resolveDependencies() throws PluginException {
DependencyResolver dependencyResolver = new DependencyResolver(unresolvedPlugins); DependencyResolver dependencyResolver = new DependencyResolver(unresolvedPlugins);
resolvedPlugins = dependencyResolver.getSortedDependencies(); resolvedPlugins = dependencyResolver.getSortedPlugins();
for (Plugin plugin : resolvedPlugins) { for (PluginWrapper pluginWrapper : resolvedPlugins) {
unresolvedPlugins.remove(plugin); unresolvedPlugins.remove(pluginWrapper);
uberClassLoader.addLoader(plugin.getWrapper().getPluginClassLoader()); uberClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
LOG.info("Plugin '" + pluginWrapper.getDescriptor().getPluginId() + "' resolved");
} }
} }

31
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 static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class);
private List<Plugin> plugins; private List<PluginWrapper> plugins;
public DependencyResolver(List<Plugin> plugins) { public DependencyResolver(List<PluginWrapper> plugins) {
this.plugins = plugins; this.plugins = plugins;
} }
/** /**
* Get the list of plugins in dependency sorted order. * Get the list of plugins in dependency sorted order.
*/ */
public List<Plugin> getSortedDependencies() { public List<PluginWrapper> getSortedPlugins() throws PluginException {
DirectedGraph<String> graph = new DirectedGraph<String>(); DirectedGraph<String> graph = new DirectedGraph<String>();
for (Plugin plugin : plugins) { for (PluginWrapper pluginWrapper : plugins) {
PluginDescriptor descriptor = plugin.getWrapper().getDescriptor(); PluginDescriptor descriptor = pluginWrapper.getDescriptor();
String pluginId = descriptor.getPluginId(); String pluginId = descriptor.getPluginId();
List<String> dependencies = descriptor.getDependencies(); List<PluginDependency> dependencies = descriptor.getDependencies();
if (!dependencies.isEmpty()) { if (!dependencies.isEmpty()) {
for (String dependency : dependencies) { for (PluginDependency dependency : dependencies) {
graph.addEdge(pluginId, dependency); graph.addEdge(pluginId, dependency.getPluginId());
} }
} else { } else {
graph.addVertex(pluginId); graph.addVertex(pluginId);
@ -56,12 +56,11 @@ class DependencyResolver {
List<String> pluginsId = graph.reverseTopologicalSort(); List<String> pluginsId = graph.reverseTopologicalSort();
if (pluginsId == null) { if (pluginsId == null) {
LOG.error("Cyclic dependences !!!"); throw new CyclicDependencyException("Cyclic dependences !!!" + graph.toString());
return null;
} }
LOG.debug("Plugins order: " + pluginsId); LOG.debug("Plugins order: " + pluginsId);
List<Plugin> sortedPlugins = new ArrayList<Plugin>(); List<PluginWrapper> sortedPlugins = new ArrayList<PluginWrapper>();
for (String pluginId : pluginsId) { for (String pluginId : pluginsId) {
sortedPlugins.add(getPlugin(pluginId)); sortedPlugins.add(getPlugin(pluginId));
} }
@ -69,14 +68,14 @@ class DependencyResolver {
return sortedPlugins; return sortedPlugins;
} }
private Plugin getPlugin(String pluginId) { private PluginWrapper getPlugin(String pluginId) throws PluginNotFoundException {
for (Plugin plugin : plugins) { for (PluginWrapper pluginWrapper : plugins) {
if (pluginId.equals(plugin.getWrapper().getDescriptor().getPluginId())) { if (pluginId.equals(pluginWrapper.getDescriptor().getPluginId())) {
return plugin; return pluginWrapper;
} }
} }
return null; throw new PluginNotFoundException(pluginId);
} }
} }

14
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 static final String PLUGIN_PACKAGE_PREFIX = "ro.fortsoft.pf4j.";
private PluginManager pluginManager; private PluginManager pluginManager;
private PluginWrapper pluginWrapper; private PluginDescriptor pluginDescriptor;
public PluginClassLoader(PluginManager pluginManager, PluginWrapper pluginWrapper, ClassLoader parent) { public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) {
super(new URL[0], parent); super(new URL[0], parent);
this.pluginManager = pluginManager; this.pluginManager = pluginManager;
this.pluginWrapper = pluginWrapper; this.pluginDescriptor = pluginDescriptor;
} }
@Override @Override
@ -74,9 +74,9 @@ class PluginClassLoader extends URLClassLoader {
} }
// look in dependencies // look in dependencies
List<String> dependencies = pluginWrapper.getDescriptor().getDependencies(); List<PluginDependency> dependencies = pluginDescriptor.getDependencies();
for (String dependency : dependencies) { for (PluginDependency dependency : dependencies) {
PluginClassLoader classLoader = pluginManager.getPluginClassLoader(dependency); PluginClassLoader classLoader = pluginManager.getPluginClassLoader(dependency.getPluginId());
try { try {
return classLoader.loadClass(className); return classLoader.loadClass(className);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {

49
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 + "]";
}
}

25
pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java

@ -33,12 +33,11 @@ class PluginDescriptor {
private String pluginClass; private String pluginClass;
private PluginVersion version; private PluginVersion version;
private String provider; private String provider;
private String pluginPath; private List<PluginDependency> dependencies;
private List<String> dependencies;
private PluginClassLoader pluginClassLoader; private PluginClassLoader pluginClassLoader;
public PluginDescriptor() { public PluginDescriptor() {
dependencies = new ArrayList<String>(); dependencies = new ArrayList<PluginDependency>();
} }
/** /**
@ -69,18 +68,11 @@ class PluginDescriptor {
return provider; 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 all dependencies declared by this plugin.
* Returns an empty array if this plugin does not declare any require. * Returns an empty array if this plugin does not declare any require.
*/ */
public List<String> getDependencies() { public List<PluginDependency> getDependencies() {
return dependencies; return dependencies;
} }
@ -100,7 +92,6 @@ class PluginDescriptor {
.append("pluginClass", pluginClass) .append("pluginClass", pluginClass)
.append("version", version) .append("version", version)
.append("provider", provider) .append("provider", provider)
.append("pluginPath", pluginPath)
.append("dependencies", dependencies) .append("dependencies", dependencies)
.toString(); .toString();
} }
@ -120,14 +111,14 @@ class PluginDescriptor {
void setProvider(String provider) { void setProvider(String provider) {
this.provider = provider; this.provider = provider;
} }
void setPluginPath(String pluginPath) {
this.pluginPath = pluginPath;
}
void setDependencies(String dependencies) { void setDependencies(String dependencies) {
if (dependencies != null) { if (dependencies != null) {
this.dependencies = Arrays.asList(StringUtils.split(dependencies, ',')); this.dependencies = new ArrayList<PluginDependency>();
List<String> tokens = Arrays.asList(StringUtils.split(dependencies, ','));
for (String dependency : tokens) {
this.dependencies.add(new PluginDependency(dependency));
}
} else { } else {
this.dependencies = Collections.emptyList(); this.dependencies = Collections.emptyList();
} }

5
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.DirectoryFilter;
import ro.fortsoft.pf4j.util.JarFilter; import ro.fortsoft.pf4j.util.JarFilter;
/** /**
* Load all informations needed by a plugin. * Load all informations needed by a plugin.
* This means add all jar files from 'lib' directory, 'classes' * This means add all jar files from 'lib' directory, 'classes'
@ -53,12 +52,12 @@ class PluginLoader {
private PluginClassLoader pluginClassLoader; private PluginClassLoader pluginClassLoader;
public PluginLoader(PluginManager pluginManager, PluginWrapper pluginWrapper, File pluginRepository) { public PluginLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, File pluginRepository) {
this.pluginRepository = pluginRepository; this.pluginRepository = pluginRepository;
classesDirectory = new File(pluginRepository, "classes"); classesDirectory = new File(pluginRepository, "classes");
libDirectory = new File(pluginRepository, "lib"); libDirectory = new File(pluginRepository, "lib");
ClassLoader parent = getClass().getClassLoader(); ClassLoader parent = getClass().getClassLoader();
pluginClassLoader = new PluginClassLoader(pluginManager, pluginWrapper, parent); pluginClassLoader = new PluginClassLoader(pluginManager, pluginDescriptor, parent);
LOG.debug("Created class loader " + pluginClassLoader); LOG.debug("Created class loader " + pluginClassLoader);
} }

4
pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java

@ -25,7 +25,7 @@ public interface PluginManager {
/** /**
* Retrieves all plugins. * Retrieves all plugins.
*/ */
public List<Plugin> getPlugins(); public List<PluginWrapper> getPlugins();
/** /**
* Load plugins. * Load plugins.
@ -44,6 +44,6 @@ public interface PluginManager {
public PluginClassLoader getPluginClassLoader(String pluginId); public PluginClassLoader getPluginClassLoader(String pluginId);
public <T> List<ExtensionWrapper<T>> getExtensions(Class<T> type); public <T> List<T> getExtensions(Class<T> type);
} }

34
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;
}
}

53
pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java

@ -12,6 +12,12 @@
*/ */
package ro.fortsoft.pf4j; 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. * A wrapper over plugin instance.
* *
@ -22,9 +28,20 @@ public class PluginWrapper {
PluginDescriptor descriptor; PluginDescriptor descriptor;
String pluginPath; String pluginPath;
PluginClassLoader pluginClassLoader; PluginClassLoader pluginClassLoader;
Plugin plugin;
public PluginWrapper(PluginDescriptor descriptor) { public PluginWrapper(PluginDescriptor descriptor, String pluginPath, PluginClassLoader pluginClassLoader) {
this.descriptor = descriptor; 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; return pluginClassLoader;
} }
void setPluginPath(String pluginPath) { public Plugin getPlugin() {
this.pluginPath = pluginPath; return plugin;
} }
void setPluginClassLoader(PluginClassLoader pluginClassLoader) { private Plugin createPluginInstance() throws Exception {
this.pluginClassLoader = pluginClassLoader; 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();
}
} }

Loading…
Cancel
Save