diff --git a/README.md b/README.md
index 1914775..6542dcc 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,23 @@
Plugin Framework for Java (PF4J)
=====================
-
A plugin is a way for a third party to extend the functionality of an application. A plugin implements extension points
-declared by application or other plugins. Also a plugin can define extension points.
+declared by application or other plugins. Also a plugin can define extension points.
-Components
+Current build status: [![Build Status](https://buildhive.cloudbees.com/job/decebals/job/pf4j/badge/icon)](https://buildhive.cloudbees.com/job/decebals/job/pf4j/)
+
+Features/Benefits
-------------------
+With PF4J you can easily transform a monolithic java application in a modular application.
+PF4J is an open source (Apache license) lightweight (around 35KB) plugin framework for java, with minimal dependencies and very extensible (see PluginDescriptorFinder and ExtensionFinder).
+
+No XML, only Java.
+
+You can mark any interface or abstract class as an extension point (with marker interface ExtensionPoint) and you specified that an class is an extension with @Extension annotation.
+
+Also, PF4J can be used in web applications. For my web applications when I want modularity I use [Wicket Plugin](https://github.com/decebals/wicket-plugin).
+Components
+-------------------
- **Plugin** is the base class for all plugins types. Each plugin is loaded into a separate class loader to avoid conflicts.
- **PluginManager** is used for all aspects of plugins management (loading, starting, stopping).
- **ExtensionPoint** is a point in the application where custom code can be invoked. It's a java interface marker.
@@ -15,13 +26,11 @@ Any java interface or abstract class can be marked as an extension point (implem
Artifacts
-------------------
-
- PF4J `pf4j` (jar)
- PF4J Demo `pf4j-demo` (executable jar)
Using Maven
-------------------
-
In your pom.xml you must define the dependencies to PF4J artifacts with:
```xml
@@ -34,9 +43,10 @@ In your pom.xml you must define the dependencies to PF4J artifacts with:
where ${pf4j.version} is the last pf4j version.
+You may want to check for the latest released version using [Maven Search](http://search.maven.org/#search%7Cga%7C1%7Cpf4j)
+
How to use
-------------------
-
It's very simple to add pf4j in your application:
public static void main(String[] args) {
@@ -51,7 +61,7 @@ It's very simple to add pf4j in your application:
In above code, I created a **DefaultPluginManager** (it's the default implementation for
**PluginManager** interface) that loads and starts all active(resolved) plugins.
-The available plugins are loaded using a **PluginClassLoader**.
+Each available plugin is loaded using a **PluginClassLoader**.
The **PluginClassLoader** contains only classes found in _classes_ and _lib_ folders of plugin and runtime classes and libraries of the required plugins.
The plugins are stored in a folder. You can specify the plugins folder in the constructor of DefaultPluginManager. If the plugins folder is not specified
than the location is returned by `System.getProperty("pf4j.pluginsDir", "plugins")`.
@@ -125,22 +135,77 @@ The output is:
>>> Welcome
>>> Hello
+You can inject your custom component (for example PluginDescriptorFinder, ExtensionFinder) in DefaultPluginManager just override createXXX methods (factory method pattern).
+
+Example:
+
+ protected PluginDescriptorFinder createPluginDescriptorFinder() {
+ return new PropertiesPluginDescriptorFinder();
+ }
+
+and in plugin respository you must have a plugin.properties file with the below content:
+
+ plugin.class=ro.fortsoft.pf4j.demo.welcome.WelcomePlugin
+ plugin.dependencies=x, y, z
+ plugin.id=welcome-plugin
+ plugin.provider=Decebal Suiu
+ plugin.version=0.0.1
+
+
For more information please see the demo sources.
-Demo
+Enable/Disable plugins
-------------------
+In theory, it's a relation **1:N** between an extension point and the extensions for this extension point.
+This works well, except for when you develop multiple plugins for this extension point as different options for your clients to decide on which one to use.
+In this situation you wish a possibility to disable all but one extension.
+For example I have an extension point for sending mail (EmailSender interface) with two extensions: one based on Sendgrid and another
+based on Amazon Simple Email Service.
+The first extension is located in Plugin1 and the second extension is located in Plugin2.
+I want to go only with one extension ( **1:1** relation between extension point and extensions) and to achieve this I have two options:
+1) uninstall Plugin1 or Plugin2 (remove folder pluginX.zip and pluginX from plugins folder)
+2) disable Plugin1 or Plugin2
+
+For option two you must create a simple file **enabled.txt** or **disabled.txt** in your plugins folder.
+The content for **enabled.txt** is similar with:
+
+ ########################################
+ # - load only these plugins
+ # - add one plugin id on each line
+ # - put this file in plugins folder
+ ########################################
+ welcome-plugin
+
+The content for **disabled.txt** is similar with:
+
+ ########################################
+ # - load all plugins except these
+ # - add one plugin id on each line
+ # - put this file in plugins folder
+ ########################################
+ welcome-plugin
+
+All comment lines (line that start with # character) are ignored.
+If a file with enabled.txt exists than disabled.txt is ignored. See enabled.txt and disabled.txt from the demo folder.
+Demo
+-------------------
I have a tiny demo application. The demo application is in demo folder.
In demo/api folder I declared an extension point (_Greeting_).
In demo/plugin* I implemented two plugins: plugin1, plugin2 (each plugin adds an extension for _Greeting_).
To run the demo application use:
- ./run-demo.sh
+ ./run-demo.sh (for Linux/Unix)
+ ./run-demo.bat (for Windows)
+
+Mailing list
+--------------
+
+Much of the conversation between developers and users is managed through [mailing list] (http://groups.google.com/group/pf4j).
License
--------------
-
Copyright 2012 Decebal Suiu
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with
diff --git a/demo/api/pom.xml b/demo/api/pom.xml
index 1b99d58..2a2a04b 100644
--- a/demo/api/pom.xml
+++ b/demo/api/pom.xml
@@ -3,24 +3,16 @@
ro.fortsoft.pf4j.demo
- pom
- 0.4-SNAPSHOT
+ pf4j-demo-parent
+ 0.5-SNAPSHOT
4.0.0
pf4j-demo-api
- 0.4-SNAPSHOT
+ 0.5-SNAPSHOT
jar
Demo Api
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
-
diff --git a/demo/app/pom.xml b/demo/app/pom.xml
index b9db6ab..cef9586 100644
--- a/demo/app/pom.xml
+++ b/demo/app/pom.xml
@@ -3,23 +3,15 @@
ro.fortsoft.pf4j.demo
- pom
- 0.4-SNAPSHOT
+ pf4j-demo-parent
+ 0.5-SNAPSHOT
4.0.0
pf4j-demo-app
- 0.4-SNAPSHOT
+ 0.5-SNAPSHOT
jar
Demo App
-
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
ro.fortsoft.pf4j.demo.Boot
diff --git a/demo/app/src/main/resources/log4j.properties b/demo/app/src/main/resources/log4j.properties
index b3e5aa8..f2160e8 100644
--- a/demo/app/src/main/resources/log4j.properties
+++ b/demo/app/src/main/resources/log4j.properties
@@ -4,7 +4,3 @@ log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n
-log4j.logger.org.apache.wicket=INFO
-log4j.logger.org.apache.wicket.protocol.http.HttpSessionStore=INFO
-log4j.logger.org.apache.wicket.version=INFO
-log4j.logger.org.apache.wicket.RequestCycle=INFO
diff --git a/demo/disabled.txt b/demo/disabled.txt
new file mode 100644
index 0000000..b8fedab
--- /dev/null
+++ b/demo/disabled.txt
@@ -0,0 +1,6 @@
+########################################
+# - load all plugins except these
+# - add one plugin id on each line
+# - put this file in plugins folder
+########################################
+welcome-plugin
diff --git a/demo/enabled.txt b/demo/enabled.txt
new file mode 100644
index 0000000..96a92b3
--- /dev/null
+++ b/demo/enabled.txt
@@ -0,0 +1,6 @@
+########################################
+# - load only these plugins
+# - add one plugin id on each line
+# - put this file in plugins folder
+########################################
+welcome-plugin
diff --git a/demo/plugin1/pom.xml b/demo/plugin1/pom.xml
index b332a96..49cf1df 100644
--- a/demo/plugin1/pom.xml
+++ b/demo/plugin1/pom.xml
@@ -3,24 +3,16 @@
ro.fortsoft.pf4j.demo
- pom
- 0.4-SNAPSHOT
+ pf4j-demo-parent
+ 0.5-SNAPSHOT
4.0.0
pf4j-demo-plugin1
- 0.4-SNAPSHOT
+ 0.5-SNAPSHOT
jar
Demo Plugin #1
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
-
welcome-plugin
ro.fortsoft.pf4j.demo.welcome.WelcomePlugin
diff --git a/demo/plugin2/pom.xml b/demo/plugin2/pom.xml
index 88e586f..b69f767 100644
--- a/demo/plugin2/pom.xml
+++ b/demo/plugin2/pom.xml
@@ -3,24 +3,16 @@
ro.fortsoft.pf4j.demo
- pom
- 0.4-SNAPSHOT
+ pf4j-demo-parent
+ 0.5-SNAPSHOT
4.0.0
pf4j-demo-plugin2
- 0.4-SNAPSHOT
+ 0.5-SNAPSHOT
jar
Demo Plugin #2
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
-
hello-plugin
ro.fortsoft.pf4j.demo.hello.HelloPlugin
diff --git a/demo/pom.xml b/demo/pom.xml
index 6520ea5..76bd4d7 100644
--- a/demo/pom.xml
+++ b/demo/pom.xml
@@ -3,24 +3,16 @@
ro.fortsoft.pf4j
- pom
- 0.4-SNAPSHOT
+ pf4j-parent
+ 0.5-SNAPSHOT
4.0.0
ro.fortsoft.pf4j.demo
- pom
- 0.4-SNAPSHOT
+ pf4j-demo-parent
+ 0.5-SNAPSHOT
pom
- PF4J Demo
-
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
+ Demo Parent
diff --git a/pf4j/pom.xml b/pf4j/pom.xml
index e0ccfb8..68b0710 100644
--- a/pf4j/pom.xml
+++ b/pf4j/pom.xml
@@ -3,31 +3,16 @@
ro.fortsoft.pf4j
- pom
- 0.4-SNAPSHOT
+ pf4j-parent
+ 0.5-SNAPSHOT
4.0.0
pf4j
- 0.4-SNAPSHOT
+ 0.5-SNAPSHOT
jar
- PF4J Library
+ PF4J
Plugin Framework for Java
-
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
-
-
- scm:git:https://github.com/decebals/pf4j.git
- scm:git:https://github.com/decebals/pf4j.git
- git@github.com/decebals/pf4j.git
- HEAD
-
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
index 66c896c..492a701 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
@@ -30,7 +30,7 @@ import net.java.sezpoz.IndexItem;
*/
public class DefaultExtensionFinder implements ExtensionFinder {
- private static final Logger LOG = LoggerFactory.getLogger(DefaultExtensionFinder.class);
+ private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFinder.class);
private volatile List> indices;
private ClassLoader classLoader;
@@ -41,7 +41,7 @@ public class DefaultExtensionFinder implements ExtensionFinder {
@Override
public List> find(Class type) {
- LOG.debug("Find extensions for " + type);
+ log.debug("Find extensions for " + type);
List> result = new ArrayList>();
getIndices();
// System.out.println("indices = "+ indices);
@@ -49,16 +49,16 @@ public class DefaultExtensionFinder implements ExtensionFinder {
try {
AnnotatedElement element = item.element();
Class> extensionType = (Class>) element;
- LOG.debug("Checking extension type " + extensionType);
+ log.debug("Checking extension type " + extensionType);
if (type.isAssignableFrom(extensionType)) {
Object instance = item.instance();
if (instance != null) {
- LOG.debug("Added extension " + extensionType);
+ log.debug("Added extension " + extensionType);
result.add(new ExtensionWrapper(type.cast(instance), item.annotation().ordinal()));
}
}
} catch (InstantiationException e) {
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
}
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java
index 201ebb1..3e23ff1 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java
@@ -19,6 +19,8 @@ import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
+import ro.fortsoft.pf4j.util.StringUtils;
+
/**
* Read the plugin descriptor from the manifest file.
*
@@ -31,7 +33,6 @@ public class DefaultPluginDescriptorFinder implements PluginDescriptorFinder {
// TODO it's ok with classes/ ?
File manifestFile = new File(pluginRepository, "classes/META-INF/MANIFEST.MF");
if (!manifestFile.exists()) {
- // not found a 'plugin.xml' file for this plugin
throw new PluginException("Cannot find '" + manifestFile + "' file");
}
@@ -60,19 +61,19 @@ public class DefaultPluginDescriptorFinder implements PluginDescriptorFinder {
// TODO validate !!!
Attributes attrs = manifest.getMainAttributes();
String id = attrs.getValue("Plugin-Id");
- if (isEmpty(id)) {
+ if (StringUtils.isEmpty(id)) {
throw new PluginException("Plugin-Id cannot be empty");
}
pluginDescriptor.setPluginId(id);
String clazz = attrs.getValue("Plugin-Class");
- if (isEmpty(clazz)) {
+ if (StringUtils.isEmpty(clazz)) {
throw new PluginException("Plugin-Class cannot be empty");
}
pluginDescriptor.setPluginClass(clazz);
String version = attrs.getValue("Plugin-Version");
- if (isEmpty(version)) {
+ if (StringUtils.isEmpty(version)) {
throw new PluginException("Plugin-Version cannot be empty");
}
pluginDescriptor.setPluginVersion(PluginVersion.createVersion(version));
@@ -84,8 +85,5 @@ public class DefaultPluginDescriptorFinder implements PluginDescriptorFinder {
return pluginDescriptor;
}
-
- private boolean isEmpty(String value) {
- return (value == null) || value.isEmpty();
- }
+
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
index 750e334..20aba2d 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import ro.fortsoft.pf4j.util.CompoundClassLoader;
import ro.fortsoft.pf4j.util.DirectoryFilter;
+import ro.fortsoft.pf4j.util.FileUtils;
import ro.fortsoft.pf4j.util.Unzip;
import ro.fortsoft.pf4j.util.ZipFilter;
@@ -36,7 +37,7 @@ import ro.fortsoft.pf4j.util.ZipFilter;
*/
public class DefaultPluginManager implements PluginManager {
- private static final Logger LOG = LoggerFactory.getLogger(DefaultPluginManager.class);
+ private static final Logger log = LoggerFactory.getLogger(DefaultPluginManager.class);
/**
* The plugins repository.
@@ -71,21 +72,19 @@ public class DefaultPluginManager implements PluginManager {
* A list with resolved plugins (resolved dependency).
*/
private List resolvedPlugins;
-
- /**
- * A list with disabled plugins.
- */
- private List disabledPlugins;
/**
* A list with started plugins.
*/
private List startedPlugins;
+ private List enabledPlugins;
+ private List disabledPlugins;
+
/**
* A compound class loader of resolved plugins.
*/
- private CompoundClassLoader compoundClassLoader;
+ protected CompoundClassLoader compoundClassLoader;
/**
* Th plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins").
@@ -108,16 +107,29 @@ public class DefaultPluginManager implements PluginManager {
pathToIdMap = new HashMap();
unresolvedPlugins = new ArrayList();
resolvedPlugins = new ArrayList();
- disabledPlugins = new ArrayList();
startedPlugins = new ArrayList();
- pluginDescriptorFinder = new DefaultPluginDescriptorFinder();
+ disabledPlugins = new ArrayList();
compoundClassLoader = new CompoundClassLoader();
- extensionFinder = new DefaultExtensionFinder(compoundClassLoader);
+ pluginDescriptorFinder = createPluginDescriptorFinder();
+ extensionFinder = createExtensionFinder();
+
+ try {
+ // create a list with plugin identifiers that should be only accepted by this manager (whitelist from plugins/enabled.txt file)
+ enabledPlugins = FileUtils.readLines(new File(pluginsDirectory, "enabled.txt"), true);
+ log.info("Enabled plugins: " + enabledPlugins);
+
+ // create a list with plugin identifiers that should not be accepted by this manager (blacklist from plugins/disabled.txt file)
+ disabledPlugins = FileUtils.readLines(new File(pluginsDirectory, "disabled.txt"), true);
+ log.info("Disabled plugins: " + disabledPlugins);
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+
System.setProperty("pf4j.pluginsDir", pluginsDirectory.getAbsolutePath());
}
- @Override
+ @Override
public List getPlugins() {
return new ArrayList(plugins.values());
}
@@ -136,10 +148,6 @@ public class DefaultPluginManager implements PluginManager {
return unresolvedPlugins;
}
- public List getDisabledPlugins() {
- return disabledPlugins;
- }
-
@Override
public List getStartedPlugins() {
return startedPlugins;
@@ -152,12 +160,12 @@ public class DefaultPluginManager implements PluginManager {
public void startPlugins() {
for (PluginWrapper pluginWrapper : resolvedPlugins) {
try {
- LOG.info("Start plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
+ log.info("Start plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
pluginWrapper.getPlugin().start();
pluginWrapper.setPluginState(PluginState.STARTED);
startedPlugins.add(pluginWrapper);
} catch (PluginException e) {
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
}
}
}
@@ -171,11 +179,11 @@ public class DefaultPluginManager implements PluginManager {
Collections.reverse(startedPlugins);
for (PluginWrapper pluginWrapper : startedPlugins) {
try {
- LOG.info("Stop plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
+ log.info("Stop plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
pluginWrapper.getPlugin().stop();
pluginWrapper.setPluginState(PluginState.STOPPED);
} catch (PluginException e) {
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
}
}
}
@@ -187,7 +195,7 @@ public class DefaultPluginManager implements PluginManager {
public void loadPlugins() {
// check for plugins directory
if (!pluginsDirectory.exists() || !pluginsDirectory.isDirectory()) {
- LOG.error("No '" + pluginsDirectory + "' directory");
+ log.error("No '" + pluginsDirectory + "' directory");
return;
}
@@ -198,32 +206,32 @@ public class DefaultPluginManager implements PluginManager {
try {
expandPluginArchive(zipFile);
} catch (IOException e) {
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
}
}
- // load any plugin from plugins directory
+ // check for no plugins
FilenameFilter directoryFilter = new DirectoryFilter();
String[] directories = pluginsDirectory.list(directoryFilter);
+ if (directories.length == 0) {
+ log.info("No plugins");
+ return;
+ }
+
+ // load any plugin from plugins directory
for (String directory : directories) {
try {
loadPlugin(directory);
} catch (PluginException e) {
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
}
}
- // check for no plugins
- if (directories.length == 0) {
- LOG.info("No plugins");
- return;
- }
-
// resolve 'unresolvedPlugins'
try {
resolvePlugins();
} catch (PluginException e) {
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
}
}
@@ -270,33 +278,34 @@ public class DefaultPluginManager implements PluginManager {
// try to load the plugin
String pluginPath = "/".concat(fileName);
- // test for disabled plugin
- if (disabledPlugins.contains(pluginPath)) {
- return;
- }
-
// test for plugin duplication
if (plugins.get(pathToIdMap.get(pluginPath)) != null) {
return;
}
// retrieves the plugin descriptor
- LOG.debug("Find plugin descriptor '" + pluginPath + "'");
+ log.debug("Find plugin descriptor '" + pluginPath + "'");
PluginDescriptor pluginDescriptor = pluginDescriptorFinder.find(pluginDirectory);
- LOG.debug("Descriptor " + pluginDescriptor);
+ log.debug("Descriptor " + pluginDescriptor);
String pluginClassName = pluginDescriptor.getPluginClass();
- LOG.debug("Class '" + pluginClassName + "'" + " for plugin '" + pluginPath + "'");
+ log.debug("Class '" + pluginClassName + "'" + " for plugin '" + pluginPath + "'");
+
+ // test for disabled plugin
+ if (isPluginDisabled(pluginDescriptor.getPluginId())) {
+ log.info("Plugin '" + pluginPath + "' is disabled");
+ return;
+ }
// load plugin
- LOG.debug("Loading plugin '" + pluginPath + "'");
+ log.debug("Loading plugin '" + pluginPath + "'");
PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory);
pluginLoader.load();
- LOG.debug("Loaded plugin '" + pluginPath + "'");
+ log.debug("Loaded plugin '" + pluginPath + "'");
// create the plugin wrapper
- LOG.debug("Creating wrapper for plugin '" + pluginPath + "'");
+ log.debug("Creating wrapper for plugin '" + pluginPath + "'");
PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader());
- LOG.debug("Created wrapper '" + pluginWrapper + "' for plugin '" + pluginPath + "'");
+ log.debug("Created wrapper '" + pluginWrapper + "' for plugin '" + pluginPath + "'");
String pluginId = pluginDescriptor.getPluginId();
@@ -309,6 +318,28 @@ public class DefaultPluginManager implements PluginManager {
pluginClassLoaders.put(pluginId, pluginClassLoader);
}
+ /**
+ * Add the possibility to override the PluginDescriptorFinder.
+ */
+ protected PluginDescriptorFinder createPluginDescriptorFinder() {
+ return new DefaultPluginDescriptorFinder();
+ }
+
+ /**
+ * Add the possibility to override the ExtensionFinder.
+ */
+ protected ExtensionFinder createExtensionFinder() {
+ return new DefaultExtensionFinder(compoundClassLoader);
+ }
+
+ protected boolean isPluginDisabled(String pluginId) {
+ if (enabledPlugins.isEmpty()) {
+ return disabledPlugins.contains(pluginId);
+ }
+
+ return !enabledPlugins.contains(pluginId);
+ }
+
private void expandPluginArchive(String fileName) throws IOException {
File pluginArchiveFile = new File(pluginsDirectory, fileName);
long pluginArchiveDate = pluginArchiveFile.lastModified();
@@ -316,7 +347,7 @@ public class DefaultPluginManager implements PluginManager {
File pluginDirectory = new File(pluginsDirectory, pluginName);
// check if exists directory or the '.zip' file is "newer" than directory
if (!pluginDirectory.exists() || (pluginArchiveDate > pluginDirectory.lastModified())) {
- LOG.debug("Expand plugin archive '" + pluginArchiveFile + "' in '" + pluginDirectory + "'");
+ log.debug("Expand plugin archive '" + pluginArchiveFile + "' in '" + pluginDirectory + "'");
// create directorie for plugin
pluginDirectory.mkdirs();
@@ -338,8 +369,8 @@ public class DefaultPluginManager implements PluginManager {
for (PluginWrapper pluginWrapper : resolvedPlugins) {
unresolvedPlugins.remove(pluginWrapper);
compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
- LOG.info("Plugin '" + pluginWrapper.getDescriptor().getPluginId() + "' resolved");
+ 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 70c1b90..8611fef 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java
@@ -25,7 +25,7 @@ import ro.fortsoft.pf4j.util.DirectedGraph;
*/
class DependencyResolver {
- private static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class);
+ private static final Logger log = LoggerFactory.getLogger(DependencyResolver.class);
private List plugins;
@@ -51,14 +51,14 @@ class DependencyResolver {
}
}
- LOG.debug("Graph: " + graph);
+ log.debug("Graph: " + graph);
List pluginsId = graph.reverseTopologicalSort();
if (pluginsId == null) {
throw new CyclicDependencyException("Cyclic dependences !!!" + graph.toString());
}
- LOG.debug("Plugins order: " + pluginsId);
+ log.debug("Plugins order: " + pluginsId);
List sortedPlugins = new ArrayList();
for (String pluginId : pluginsId) {
sortedPlugins.add(getPlugin(pluginId));
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
index 80832bc..60c79ca 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
@@ -23,8 +23,8 @@ import java.util.List;
*/
public class PluginClassLoader extends URLClassLoader {
- private static final String JAVA_PACKAGE_PREFIX = "java.";
- private static final String JAVAX_PACKAGE_PREFIX = "javax.";
+// 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;
@@ -46,10 +46,13 @@ public class PluginClassLoader extends URLClassLoader {
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);
}
+ */
// second check whether it's already been loaded
Class> loadedClass = findLoadedClass(className);
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
index 7533f57..78603f4 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
@@ -33,7 +33,7 @@ import ro.fortsoft.pf4j.util.JarFilter;
*/
class PluginLoader {
- private static final Logger LOG = LoggerFactory.getLogger(PluginLoader.class);
+ private static final Logger log = LoggerFactory.getLogger(PluginLoader.class);
/*
* The plugin repository.
@@ -58,7 +58,7 @@ class PluginLoader {
libDirectory = new File(pluginRepository, "lib");
ClassLoader parent = getClass().getClassLoader();
pluginClassLoader = new PluginClassLoader(pluginManager, pluginDescriptor, parent);
- LOG.debug("Created class loader " + pluginClassLoader);
+ log.debug("Created class loader " + pluginClassLoader);
}
public File getPluginRepository() {
@@ -100,14 +100,14 @@ class PluginLoader {
classesDirectory = classesDirectory.getAbsoluteFile();
if (classesDirectory.exists() && classesDirectory.isDirectory()) {
- LOG.debug("Found '" + classesDirectory.getPath() + "' directory");
+ log.debug("Found '" + classesDirectory.getPath() + "' directory");
try {
pluginClassLoader.addURL(classesDirectory.toURI().toURL());
- LOG.debug("Added '" + classesDirectory + "' to the class loader path");
+ log.debug("Added '" + classesDirectory + "' to the class loader path");
} catch (MalformedURLException e) {
e.printStackTrace();
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
return false;
}
}
@@ -128,10 +128,10 @@ class PluginLoader {
File jarFile = new File(libDirectory, jar);
try {
pluginClassLoader.addURL(jarFile.toURI().toURL());
- LOG.debug("Added '" + jarFile + "' to the class loader path");
+ log.debug("Added '" + jarFile + "' to the class loader path");
} catch (MalformedURLException e) {
e.printStackTrace();
- LOG.error(e.getMessage(), e);
+ log.error(e.getMessage(), e);
return false;
}
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java
new file mode 100644
index 0000000..4f0e753
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java
@@ -0,0 +1,97 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import ro.fortsoft.pf4j.util.StringUtils;
+
+/**
+ * Find a plugin descriptor in a properties file (in plugin repository).
+ *
+ * @author Decebal Suiu
+ */
+public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder {
+
+ private String propertiesFileName;
+
+ public PropertiesPluginDescriptorFinder() {
+ this("plugin.properties");
+ }
+
+ public PropertiesPluginDescriptorFinder(String propertiesFileName) {
+ this.propertiesFileName = propertiesFileName;
+ }
+
+ @Override
+ public PluginDescriptor find(File pluginRepository) throws PluginException {
+ File propertiesFile = new File(pluginRepository, propertiesFileName);
+ if (!propertiesFile.exists()) {
+ throw new PluginException("Cannot find '" + propertiesFile + "' file");
+ }
+
+ InputStream input = null;
+ try {
+ input = new FileInputStream(propertiesFile);
+ } catch (FileNotFoundException e) {
+ // not happening
+ }
+
+ Properties properties = new Properties();
+ try {
+ properties.load(input);
+ } catch (IOException e) {
+ throw new PluginException(e.getMessage(), e);
+ } finally {
+ try {
+ input.close();
+ } catch (IOException e) {
+ throw new PluginException(e.getMessage(), e);
+ }
+ }
+
+ PluginDescriptor pluginDescriptor = new PluginDescriptor();
+
+ // TODO validate !!!
+ String id = properties.getProperty("plugin.id");
+ if (StringUtils.isEmpty(id)) {
+ throw new PluginException("plugin.id cannot be empty");
+ }
+ pluginDescriptor.setPluginId(id);
+
+ String clazz = properties.getProperty("plugin.class");
+ if (StringUtils.isEmpty(clazz)) {
+ throw new PluginException("plugin.class cannot be empty");
+ }
+ pluginDescriptor.setPluginClass(clazz);
+
+ String version = properties.getProperty("plugin.version");
+ if (StringUtils.isEmpty(version)) {
+ throw new PluginException("plugin.version cannot be empty");
+ }
+ pluginDescriptor.setPluginVersion(PluginVersion.createVersion(version));
+
+ String provider = properties.getProperty("plugin.provider");
+ pluginDescriptor.setProvider(provider);
+ String dependencies = properties.getProperty("plugin.dependencies");
+ pluginDescriptor.setDependencies(dependencies);
+
+ return pluginDescriptor;
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java
new file mode 100644
index 0000000..0b8c38a
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Decebal Suiu
+ */
+public class FileUtils {
+
+ public static List readLines(File file, boolean ignoreComments) throws IOException {
+ if (!file.exists() || !file.isFile()) {
+ return Collections.emptyList();
+ }
+
+ List lines = new ArrayList();
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (ignoreComments && !line.startsWith("#") && !lines.contains(line)) {
+ lines.add(line);
+ }
+ }
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ return lines;
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/StringUtils.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/StringUtils.java
new file mode 100644
index 0000000..c133255
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/StringUtils.java
@@ -0,0 +1,24 @@
+/*
+ * 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.util;
+
+/**
+ * @author Decebal Suiu
+ */
+public class StringUtils {
+
+ public static boolean isEmpty(String str) {
+ return (str == null) || str.isEmpty();
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java
index 4a2c9a3..e3f3ed3 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java
@@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory;
*/
public class Unzip {
- private static final Logger LOG = LoggerFactory.getLogger(Unzip.class);
+ private static final Logger log = LoggerFactory.getLogger(Unzip.class);
/**
* Holds the destination directory.
@@ -61,7 +61,7 @@ public class Unzip {
}
public void extract() throws IOException {
- LOG.debug("Extract content of " + source + " to " + destination);
+ log.debug("Extract content of " + source + " to " + destination);
// delete destination file if exists
removeDirectory(destination);
@@ -91,7 +91,7 @@ public class Unzip {
fos.close();
}
} catch (FileNotFoundException e) {
- LOG.error("File '" + zipEntry.getName() + "' not found");
+ log.error("File '" + zipEntry.getName() + "' not found");
}
}
diff --git a/pom.xml b/pom.xml
index 14a07b5..3c9bb2e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,10 +9,10 @@
4.0.0
ro.fortsoft.pf4j
- pom
- 0.4-SNAPSHOT
+ pf4j-parent
+ 0.5-SNAPSHOT
pom
- PF4J
+ PF4J Parent
Plugin Framework for Java