aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java55
-rw-r--r--demo/plugins/disabled.txt (renamed from demo/disabled.txt)2
-rw-r--r--demo/plugins/enabled.txt (renamed from demo/enabled.txt)2
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java129
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java211
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java13
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java37
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java28
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java38
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java31
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java33
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java22
12 files changed, 417 insertions, 184 deletions
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 8dde182..453e2c2 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
@@ -1,11 +1,11 @@
/*
* 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.
@@ -13,11 +13,13 @@
package ro.fortsoft.pf4j.demo;
import java.util.List;
+import java.util.Set;
import org.apache.commons.lang.StringUtils;
import ro.fortsoft.pf4j.DefaultPluginManager;
import ro.fortsoft.pf4j.PluginManager;
+import ro.fortsoft.pf4j.PluginWrapper;
import ro.fortsoft.pf4j.demo.api.Greeting;
/**
@@ -26,24 +28,41 @@ import ro.fortsoft.pf4j.demo.api.Greeting;
* @author Decebal Suiu
*/
public class Boot {
-
+
public static void main(String[] args) {
- // print logo
- printLogo();
-
- // create the plugin manager
+ // print logo
+ printLogo();
+
+ // create the plugin manager
final PluginManager pluginManager = new DefaultPluginManager();
-
- // load and start (active/resolved) the plugins
+
+ // load the plugins
pluginManager.loadPlugins();
+
+ // enable a disabled plugin
+// pluginManager.enablePlugin("welcome-plugin");
+
+ // start (active/resolved) the plugins
pluginManager.startPlugins();
-
- // retrieves the extensions for Greeting extension point
+
+ // retrieves the extensions for Greeting extension point
List<Greeting> greetings = pluginManager.getExtensions(Greeting.class);
+ System.out.println(String.format("Found %d extensions for extension point '%s'", greetings.size(), Greeting.class.getName()));
for (Greeting greeting : greetings) {
- System.out.println(">>> " + greeting.getGreeting());
+ System.out.println(">>> " + greeting.getGreeting());
+ }
+
+ // print extensions for each started plugin
+ List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins();
+ for (PluginWrapper plugin : startedPlugins) {
+ String pluginId = plugin.getDescriptor().getPluginId();
+ System.out.println(String.format("Extensions added by plugin '%s':", pluginId));
+ Set<String> extensionClassNames = pluginManager.getExtensionClassNames(pluginId);
+ for (String extension : extensionClassNames) {
+ System.out.println(" " + extension);
+ }
}
-
+
// stop the plugins
pluginManager.stopPlugins();
/*
@@ -53,15 +72,15 @@ public class Boot {
public void run() {
pluginManager.stopPlugins();
}
-
+
});
*/
- }
+ }
private static void printLogo() {
System.out.println(StringUtils.repeat("#", 40));
System.out.println(StringUtils.center("PF4J-DEMO", 40));
- System.out.println(StringUtils.repeat("#", 40));
+ System.out.println(StringUtils.repeat("#", 40));
}
-
+
}
diff --git a/demo/disabled.txt b/demo/plugins/disabled.txt
index b8fedab..fcaef50 100644
--- a/demo/disabled.txt
+++ b/demo/plugins/disabled.txt
@@ -3,4 +3,4 @@
# - add one plugin id on each line
# - put this file in plugins folder
########################################
-welcome-plugin
+#welcome-plugin \ No newline at end of file
diff --git a/demo/enabled.txt b/demo/plugins/enabled.txt
index 96a92b3..5594017 100644
--- a/demo/enabled.txt
+++ b/demo/plugins/enabled.txt
@@ -3,4 +3,4 @@
# - add one plugin id on each line
# - put this file in plugins folder
########################################
-welcome-plugin
+#welcome-plugin \ No newline at end of file
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
index 99f7eca..c31f5d3 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
@@ -16,12 +16,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,21 +32,16 @@ public class DefaultExtensionFinder implements ExtensionFinder {
private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFinder.class);
- private ClassLoader classLoader;
+ private PluginManager pluginManager;
private ExtensionFactory extensionFactory;
- private volatile Set<String> entries;
+ private volatile Map<String, Set<String>> entries; // cache by pluginId
- public DefaultExtensionFinder(ClassLoader classLoader) {
- this.classLoader = classLoader;
+ public DefaultExtensionFinder(PluginManager pluginManager) {
+ this.pluginManager = pluginManager;
this.extensionFactory = createExtensionFactory();
}
- @Override
- public void reset() {
- entries = null;
- }
-
- @Override
+ @Override
public <T> List<ExtensionWrapper<T>> find(Class<T> type) {
log.debug("Checking extension point '{}'", type.getName());
if (!isExtensionPoint(type)) {
@@ -61,28 +51,31 @@ public class DefaultExtensionFinder implements ExtensionFinder {
}
log.debug("Finding extensions for extension point '{}'", type.getName());
- List<ExtensionWrapper<T>> result = new ArrayList<ExtensionWrapper<T>>();
- if (entries == null) {
- entries = readIndexFiles();
- }
+ readIndexFiles();
- for (String entry : entries) {
- try {
- Class<?> extensionType = classLoader.loadClass(entry);
- log.debug("Checking extension type '{}'", extensionType.getName());
- if (type.isAssignableFrom(extensionType)) {
- Object instance = extensionFactory.create(extensionType);
- if (instance != null) {
- Extension extension = extensionType.getAnnotation(Extension.class);
- log.debug("Added extension '{}' with ordinal {}", extensionType.getName(), extension.ordinal());
- result.add(new ExtensionWrapper<T>(type.cast(instance), extension.ordinal()));
+ List<ExtensionWrapper<T>> result = new ArrayList<ExtensionWrapper<T>>();
+ for (Map.Entry<String, Set<String>> entry : entries.entrySet()) {
+ String pluginId = entry.getKey();
+ Set<String> extensionClassNames = entry.getValue();
+
+ for (String className : extensionClassNames) {
+ try {
+ Class<?> extensionType = pluginManager.getPluginClassLoader(pluginId).loadClass(className);
+ log.debug("Checking extension type '{}'", extensionType.getName());
+ if (type.isAssignableFrom(extensionType)) {
+ Object instance = extensionFactory.create(extensionType);
+ if (instance != null) {
+ Extension extension = extensionType.getAnnotation(Extension.class);
+ log.debug("Added extension '{}' with ordinal {}", extensionType.getName(), extension.ordinal());
+ result.add(new ExtensionWrapper<T>(type.cast(instance), extension.ordinal()));
+ }
+ } else {
+ log.warn("'{}' is not an extension for extension point '{}'", extensionType.getName(), type.getName());
}
- } else {
- log.warn("'{}' is not an extension for extension point '{}'", extensionType.getName(), type.getName());
- }
- } catch (ClassNotFoundException e) {
- log.error(e.getMessage(), e);
- }
+ } catch (ClassNotFoundException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
}
if (entries.isEmpty()) {
@@ -97,7 +90,18 @@ public class DefaultExtensionFinder implements ExtensionFinder {
return result;
}
- /**
+ @Override
+ public Set<String> findClassNames(String pluginId) {
+ return entries.get(pluginId);
+ }
+
+ @Override
+ public void reset() {
+ // clear cache
+ entries = null;
+ }
+
+ /**
* Add the possibility to override the ExtensionFactory.
* The default implementation uses Class.newInstance() method.
*/
@@ -122,28 +126,43 @@ public class DefaultExtensionFinder implements ExtensionFinder {
};
}
- private Set<String> readIndexFiles() {
- log.debug("Reading extensions index files");
- Set<String> entries = new HashSet<String>();
+ private Map<String, Set<String>> readIndexFiles() {
+ // checking cache
+ if (entries != null) {
+ return entries;
+ }
- try {
- Enumeration<URL> indexFiles = classLoader.getResources(ExtensionsIndexer.EXTENSIONS_RESOURCE);
- while (indexFiles.hasMoreElements()) {
- Reader reader = new InputStreamReader(indexFiles.nextElement().openStream(), "UTF-8");
- ExtensionsIndexer.readIndex(reader, entries);
- }
- } catch (IOException e) {
- log.error(e.getMessage(), e);
- }
+ entries = new HashMap<String, Set<String>>();
+
+ List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins();
+ for (PluginWrapper plugin : startedPlugins) {
+ String pluginId = plugin.getDescriptor().getPluginId();
+ log.debug("Reading extensions index file for plugin '{}'", pluginId);
+ Set<String> entriesPerPlugin = 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);
+
+ if (entriesPerPlugin.isEmpty()) {
+ log.debug("No extensions found");
+ } else {
+ log.debug("Found possible {} extensions:", entriesPerPlugin.size());
+ for (String entry : entriesPerPlugin) {
+ log.debug(" " + entry);
+ }
+ }
- if (entries.isEmpty()) {
- log.debug("No extensions found");
- } else {
- log.debug("Found possible {} extensions", entries.size());
+ entries.put(pluginId, entriesPerPlugin);
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
}
- return entries;
- }
+ return entries;
+ }
private boolean isExtensionPoint(Class type) {
return ExtensionPoint.class.isAssignableFrom(type);
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
index 557bb77..cf02045 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
@@ -12,27 +12,14 @@
*/
package ro.fortsoft.pf4j;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ro.fortsoft.pf4j.util.*;
-import ro.fortsoft.pf4j.util.AndFileFilter;
-import ro.fortsoft.pf4j.util.CompoundClassLoader;
-import ro.fortsoft.pf4j.util.DirectoryFileFilter;
-import ro.fortsoft.pf4j.util.FileUtils;
-import ro.fortsoft.pf4j.util.HiddenFilter;
-import ro.fortsoft.pf4j.util.NotFileFilter;
-import ro.fortsoft.pf4j.util.Unzip;
-import ro.fortsoft.pf4j.util.ZipFileFilter;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.*;
/**
* Default implementation of the PluginManager interface.
@@ -91,11 +78,6 @@ public class DefaultPluginManager implements PluginManager {
private List<String> disabledPlugins;
/**
- * A compound class loader of resolved plugins.
- */
- protected CompoundClassLoader compoundClassLoader;
-
- /**
* Cache value for the runtime mode. No need to re-read it because it wont change at
* runtime.
*/
@@ -128,14 +110,22 @@ public class DefaultPluginManager implements PluginManager {
}
@Override
+ public List<PluginWrapper> getPlugins(PluginState pluginState) {
+ List<PluginWrapper> plugins= new ArrayList<PluginWrapper>();
+ for (PluginWrapper plugin : getPlugins()) {
+ if (pluginState.equals(plugin.getPluginState())) {
+ plugins.add(plugin);
+ }
+ }
+
+ return plugins;
+ }
+
+ @Override
public List<PluginWrapper> getResolvedPlugins() {
return resolvedPlugins;
}
- public PluginWrapper getPlugin(String pluginId) {
- return plugins.get(pluginId);
- }
-
@Override
public List<PluginWrapper> getUnresolvedPlugins() {
return unresolvedPlugins;
@@ -146,6 +136,11 @@ public class DefaultPluginManager implements PluginManager {
return startedPlugins;
}
+ @Override
+ public PluginWrapper getPlugin(String pluginId) {
+ return plugins.get(pluginId);
+ }
+
@Override
public String loadPlugin(File pluginArchiveFile) {
if (pluginArchiveFile == null || !pluginArchiveFile.exists()) {
@@ -167,12 +162,12 @@ public class DefaultPluginManager implements PluginManager {
// TODO uninstalled plugin dependencies?
unresolvedPlugins.remove(pluginWrapper);
resolvedPlugins.add(pluginWrapper);
- compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
extensionFinder.reset();
return pluginWrapper.getDescriptor().getPluginId();
} catch (PluginException e) {
log.error(e.getMessage(), e);
}
+
return null;
}
@@ -182,14 +177,18 @@ public class DefaultPluginManager implements PluginManager {
@Override
public void startPlugins() {
for (PluginWrapper pluginWrapper : resolvedPlugins) {
- try {
- 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);
- }
+ PluginState pluginState = pluginWrapper.getPluginState();
+ if ((PluginState.DISABLED != pluginState) && (PluginState.STARTED != pluginState)) {
+ try {
+ PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
+ log.info("Start plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
+ pluginWrapper.getPlugin().start();
+ pluginWrapper.setPluginState(PluginState.STARTED);
+ startedPlugins.add(pluginWrapper);
+ } catch (PluginException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
}
}
@@ -201,15 +200,25 @@ public class DefaultPluginManager implements PluginManager {
if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
}
+
PluginWrapper pluginWrapper = plugins.get(pluginId);
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
- if (pluginWrapper.getPluginState().equals(PluginState.STARTED)) {
+ if (PluginState.STARTED == pluginWrapper.getPluginState()) {
log.debug("Already started plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
return PluginState.STARTED;
}
- for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
+
+ if (PluginState.DISABLED == pluginWrapper.getPluginState()) {
+ // automatically enable plugin on manual plugin start
+ if (!enablePlugin(pluginId)) {
+ return pluginWrapper.getPluginState();
+ }
+ }
+
+ for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
startPlugin(dependency.getPluginId());
}
+
try {
log.info("Start plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
pluginWrapper.getPlugin().start();
@@ -218,6 +227,7 @@ public class DefaultPluginManager implements PluginManager {
} catch (PluginException e) {
log.error(e.getMessage(), e);
}
+
return pluginWrapper.getPluginState();
}
@@ -231,15 +241,17 @@ public class DefaultPluginManager implements PluginManager {
Iterator<PluginWrapper> itr = startedPlugins.iterator();
while (itr.hasNext()) {
PluginWrapper pluginWrapper = itr.next();
- PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
- try {
- log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
- pluginWrapper.getPlugin().stop();
- pluginWrapper.setPluginState(PluginState.STOPPED);
- itr.remove();
- } catch (PluginException e) {
- log.error(e.getMessage(), e);
- }
+ if (PluginState.STARTED == pluginWrapper.getPluginState()) {
+ try {
+ PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
+ log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
+ pluginWrapper.getPlugin().stop();
+ pluginWrapper.setPluginState(PluginState.STOPPED);
+ itr.remove();
+ } catch (PluginException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
}
}
@@ -251,15 +263,24 @@ public class DefaultPluginManager implements PluginManager {
if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
}
+
PluginWrapper pluginWrapper = plugins.get(pluginId);
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
- if (pluginWrapper.getPluginState().equals(PluginState.STOPPED)) {
+ if (PluginState.STOPPED == pluginWrapper.getPluginState()) {
log.debug("Already stopped plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
return PluginState.STOPPED;
}
+
+ // test for disabled plugin
+ if (PluginState.DISABLED == pluginWrapper.getPluginState()) {
+ // do nothing
+ return pluginWrapper.getPluginState();
+ }
+
for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
stopPlugin(dependency.getPluginId());
}
+
try {
log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
pluginWrapper.getPlugin().stop();
@@ -268,6 +289,7 @@ public class DefaultPluginManager implements PluginManager {
} catch (PluginException e) {
log.error(e.getMessage(), e);
}
+
return pluginWrapper.getPluginState();
}
@@ -332,7 +354,7 @@ public class DefaultPluginManager implements PluginManager {
public boolean unloadPlugin(String pluginId) {
try {
PluginState state = stopPlugin(pluginId);
- if (!PluginState.STOPPED.equals(state)) {
+ if (PluginState.STOPPED != state) {
return false;
}
@@ -354,21 +376,88 @@ public class DefaultPluginManager implements PluginManager {
// remove the classloader
if (pluginClassLoaders.containsKey(pluginId)) {
PluginClassLoader classLoader = pluginClassLoaders.remove(pluginId);
- compoundClassLoader.removeLoader(classLoader);
try {
classLoader.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
+
return true;
} catch (IllegalArgumentException e) {
// ignore not found exceptions because this method is recursive
}
+
return false;
}
@Override
+ public boolean disablePlugin(String pluginId) {
+ if (!plugins.containsKey(pluginId)) {
+ throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
+ }
+
+
+ PluginWrapper pluginWrapper = plugins.get(pluginId);
+ PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
+
+ if (PluginState.DISABLED == getPlugin(pluginId).getPluginState()) {
+ log.debug("Already disabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
+ return true;
+ }
+
+ if (PluginState.STOPPED == stopPlugin(pluginId)) {
+ getPlugin(pluginId).setPluginState(PluginState.DISABLED);
+ extensionFinder.reset();
+
+ if (disabledPlugins.add(pluginId)) {
+ try {
+ FileUtils.writeLines(disabledPlugins, new File(pluginsDirectory, "disabled.txt"));
+ } catch (IOException e) {
+ log.error("Failed to disable plugin {}", pluginId, e);
+ return false;
+ }
+ }
+ log.info("Disabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean enablePlugin(String pluginId) {
+ if (!plugins.containsKey(pluginId)) {
+ throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
+ }
+
+ PluginWrapper pluginWrapper = plugins.get(pluginId);
+ PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
+
+ if (PluginState.DISABLED != getPlugin(pluginId).getPluginState()) {
+ log.debug("Plugin plugin '{}:{}' is not disabled", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
+ return true;
+ }
+
+ try {
+ if (disabledPlugins.remove(pluginId)) {
+ FileUtils.writeLines(disabledPlugins, new File(pluginsDirectory, "disabled.txt"));
+ }
+ } catch (IOException e) {
+ log.error("Failed to enable plugin {}", pluginId, e);
+ return false;
+ }
+
+ getPlugin(pluginId).setPluginState(PluginState.CREATED);
+ extensionFinder.reset();
+
+ log.info("Enabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
+
+ return true;
+ }
+
+ @Override
public boolean deletePlugin(String pluginId) {
if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
@@ -433,6 +522,11 @@ public class DefaultPluginManager implements PluginManager {
}
@Override
+ public Set<String> getExtensionClassNames(String pluginId) {
+ return extensionFinder.findClassNames(pluginId);
+ }
+
+ @Override
public RuntimeMode getRuntimeMode() {
if (runtimeMode == null) {
// retrieves the runtime mode from system
@@ -478,7 +572,7 @@ public class DefaultPluginManager implements PluginManager {
* Add the possibility to override the ExtensionFinder.
*/
protected ExtensionFinder createExtensionFinder() {
- return new DefaultExtensionFinder(compoundClassLoader);
+ return new DefaultExtensionFinder(this);
}
/**
@@ -537,7 +631,6 @@ public class DefaultPluginManager implements PluginManager {
resolvedPlugins = new ArrayList<PluginWrapper>();
startedPlugins = new ArrayList<PluginWrapper>();
disabledPlugins = new ArrayList<String>();
- compoundClassLoader = new CompoundClassLoader();
pluginClasspath = createPluginClasspath();
pluginDescriptorFinder = createPluginDescriptorFinder();
@@ -575,12 +668,6 @@ public class DefaultPluginManager implements PluginManager {
String pluginClassName = pluginDescriptor.getPluginClass();
log.debug("Class '{}' for plugin '{}'", pluginClassName, pluginPath);
- // test for disabled plugin
- if (isPluginDisabled(pluginDescriptor.getPluginId())) {
- log.info("Plugin '{}' is disabled", pluginPath);
- return null;
- }
-
// load plugin
log.debug("Loading plugin '{}'", pluginPath);
PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory, pluginClasspath);
@@ -591,6 +678,13 @@ public class DefaultPluginManager implements PluginManager {
log.debug("Creating wrapper for plugin '{}'", pluginPath);
PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader());
pluginWrapper.setRuntimeMode(getRuntimeMode());
+
+ // test for disabled plugin
+ if (isPluginDisabled(pluginDescriptor.getPluginId())) {
+ log.info("Plugin '{}' is disabled", pluginPath);
+ pluginWrapper.setPluginState(PluginState.DISABLED);
+ }
+
log.debug("Created wrapper '{}' for plugin '{}'", pluginWrapper, pluginPath);
String pluginId = pluginDescriptor.getPluginId();
@@ -641,7 +735,6 @@ public class DefaultPluginManager implements PluginManager {
resolvedPlugins = dependencyResolver.getSortedPlugins();
for (PluginWrapper pluginWrapper : resolvedPlugins) {
unresolvedPlugins.remove(pluginWrapper);
- compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
log.info("Plugin '{}' resolved", pluginWrapper.getDescriptor().getPluginId());
}
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java
index 7e22a4a..c518566 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java
@@ -13,14 +13,23 @@
package ro.fortsoft.pf4j;
import java.util.List;
+import java.util.Set;
/**
* @author Decebal Suiu
*/
public interface ExtensionFinder {
- public <T> List<ExtensionWrapper<T>> find(Class<T> type);
+ /**
+ * Retrieves a list with all extensions found for an extension point.
+ */
+ public <T> List<ExtensionWrapper<T>> find(Class<T> type);
- public void reset();
+ /**
+ * Retrieves a list with all extension class names found for a plugin.
+ */
+ public Set<String> findClassNames(String pluginId);
+
+ public void reset();
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
index 60c79ca..3fd7572 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClassLoader.java
@@ -1,24 +1,27 @@
/*
* 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.IOException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.Enumeration;
import java.util.List;
/**
* One instance of this class should be created by plugin manager for every available plug-in.
- *
+ *
* @author Decebal Suiu
*/
public class PluginClassLoader extends URLClassLoader {
@@ -29,10 +32,10 @@ public class PluginClassLoader extends URLClassLoader {
private PluginManager pluginManager;
private PluginDescriptor pluginDescriptor;
-
+
public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) {
super(new URL[0], parent);
-
+
this.pluginManager = pluginManager;
this.pluginDescriptor = pluginDescriptor;
}
@@ -91,4 +94,26 @@ public class PluginClassLoader extends URLClassLoader {
return super.loadClass(className);
}
+ @Override
+ public URL getResource(String name) {
+ if (PluginState.DISABLED == getPlugin().getPluginState()) {
+ return null;
+ }
+
+ return super.getResource(name);
+ }
+
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ if (PluginState.DISABLED == getPlugin().getPluginState()) {
+ return Collections.emptyEnumeration();
+ }
+
+ return super.getResources(name);
+ }
+
+ private PluginWrapper getPlugin() {
+ return pluginManager.getPlugin(pluginDescriptor.getPluginId());
+ }
+
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java
index 5fbe975..541bb0a 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java
@@ -1,11 +1,11 @@
/*
* Copyright 2013 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.
@@ -16,25 +16,25 @@ import java.util.ArrayList;
import java.util.List;
/**
- * The classpath of the plugin after it was unpacked.
- * It contains classes directories and lib directories (directories that contains jars).
- * All directories are relativ to plugin repository.
- * The default values are "classes" and "lib".
- *
+ * The classpath of the plugin after it was unpacked.
+ * It contains classes directories and lib directories (directories that contains jars).
+ * All directories are relative to plugin repository.
+ * The default values are "classes" and "lib".
+ *
* @author Decebal Suiu
*/
public class PluginClasspath {
private static final String DEFAULT_CLASSES_DIRECTORY = "classes";
private static final String DEFAULT_LIB_DIRECTORY = "lib";
-
+
protected List<String> classesDirectories;
protected List<String> libDirectories;
-
+
public PluginClasspath() {
classesDirectories = new ArrayList<String>();
libDirectories = new ArrayList<String>();
-
+
addResources();
}
@@ -53,10 +53,10 @@ public class PluginClasspath {
public void setLibDirectories(List<String> libDirectories) {
this.libDirectories = libDirectories;
}
-
+
protected void addResources() {
classesDirectories.add(DEFAULT_CLASSES_DIRECTORY);
- libDirectories.add(DEFAULT_LIB_DIRECTORY);
+ libDirectories.add(DEFAULT_LIB_DIRECTORY);
}
-
+
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
index ec95c4e..f656313 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
@@ -14,6 +14,7 @@ package ro.fortsoft.pf4j;
import java.io.File;
import java.util.List;
+import java.util.Set;
/**
* Provides the functionality for plugin management such as load,
@@ -29,14 +30,19 @@ public interface PluginManager {
public List<PluginWrapper> getPlugins();
/**
+ * Retrieves all plugins with this state.
+ */
+ public List<PluginWrapper> getPlugins(PluginState pluginState);
+
+ /**
* Retrieves all resolved plugins (with resolved dependency).
*/
- public List<PluginWrapper> getResolvedPlugins();
+ public List<PluginWrapper> getResolvedPlugins();
/**
* Retrieves all unresolved plugins (with unresolved dependency).
*/
- public List<PluginWrapper> getUnresolvedPlugins();
+ public List<PluginWrapper> getUnresolvedPlugins();
/**
* Retrieves all started plugins.
@@ -44,6 +50,14 @@ public interface PluginManager {
public List<PluginWrapper> getStartedPlugins();
/**
+ * Retrieves the plugin with this id.
+ *
+ * @param pluginId
+ * @return the plugin
+ */
+ public PluginWrapper getPlugin(String pluginId);
+
+ /**
* Load plugins.
*/
public void loadPlugins();
@@ -89,6 +103,22 @@ public interface PluginManager {
public boolean unloadPlugin(String pluginId);
/**
+ * Disables a plugin from being loaded.
+ *
+ * @param pluginId
+ * @return true if plugin is disabled
+ */
+ public boolean disablePlugin(String pluginId);
+
+ /**
+ * Enables a plugin that has previously been disabled.
+ *
+ * @param pluginId
+ * @return true if plugin is enabled
+ */
+ public boolean enablePlugin(String pluginId);
+
+ /**
* Deletes a plugin.
*
* @param pluginId
@@ -100,7 +130,9 @@ public interface PluginManager {
public <T> List<T> getExtensions(Class<T> type);
- /**
+ public Set<String> getExtensionClassNames(String pluginId);
+
+ /**
* The runtime mode. Must currently be either DEVELOPMENT or DEPLOYMENT.
*/
public RuntimeMode getRuntimeMode();
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java
index 3727087..207e436 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java
@@ -1,11 +1,11 @@
/*
* 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.
@@ -18,19 +18,34 @@ package ro.fortsoft.pf4j;
public class PluginState {
public static final PluginState CREATED = new PluginState("CREATED");
- public static final PluginState INITIALIZED = new PluginState("INITIALIZED");
+ public static final PluginState DISABLED = new PluginState("DISABLED");
public static final PluginState STARTED = new PluginState("STARTED");
public static final PluginState STOPPED = new PluginState("STOPPED");
- public static final PluginState DESTROYED = new PluginState("DESTROYED");
- public static final PluginState FAILED = new PluginState("FAILED");
private String status;
-
+
private PluginState(String status) {
this.status = status;
}
- @Override
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PluginState that = (PluginState) o;
+
+ if (!status.equals(that.status)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return status.hashCode();
+ }
+
+ @Override
public String toString() {
return status;
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java
index d307cf0..b2ab37d 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java
@@ -1,11 +1,11 @@
/*
* 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.
@@ -28,22 +28,22 @@ public class PluginWrapper {
Plugin plugin;
PluginState pluginState;
RuntimeMode runtimeMode;
-
+
public PluginWrapper(PluginDescriptor descriptor, String pluginPath, PluginClassLoader pluginClassLoader) {
this.descriptor = descriptor;
this.pluginPath = pluginPath;
this.pluginClassLoader = pluginClassLoader;
-
+
// TODO
try {
plugin = createPluginInstance();
} catch (Exception e) {
e.printStackTrace();
}
-
+
pluginState = PluginState.CREATED;
}
-
+
/**
* Returns the plugin descriptor.
*/
@@ -79,12 +79,19 @@ public class PluginWrapper {
return runtimeMode;
}
+ /**
+ * Shortcut
+ */
+ public String getPluginId() {
+ return getDescriptor().getPluginId();
+ }
+
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + descriptor.getPluginId().hashCode();
-
+
return result;
}
@@ -93,20 +100,20 @@ public class PluginWrapper {
if (this == obj) {
return true;
}
-
+
if (obj == null) {
return false;
}
-
+
if (getClass() != obj.getClass()) {
return false;
}
-
+
PluginWrapper other = (PluginWrapper) obj;
if (!descriptor.getPluginId().equals(other.descriptor.getPluginId())) {
return false;
}
-
+
return true;
}
@@ -119,7 +126,7 @@ public class PluginWrapper {
void setPluginState(PluginState pluginState) {
this.pluginState = pluginState;
}
-
+
void setRuntimeMode(RuntimeMode runtimeMode) {
this.runtimeMode = runtimeMode;
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java
index 68cc2b3..2ac97db 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java
@@ -12,11 +12,9 @@
*/
package ro.fortsoft.pf4j.util;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
+import java.io.*;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -50,6 +48,21 @@ public class FileUtils {
return lines;
}
+ public static void writeLines(Collection<String> lines, File file) throws IOException {
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(file));
+ for (String line : lines) {
+ writer.write(line);
+ writer.write('\n');
+ }
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
/**
* Delete a file or recursively delete a folder.
*
@@ -71,6 +84,7 @@ public class FileUtils {
}
}
success |= fileOrFolder.delete();
+
return success;
}
}