summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDecebal Suiu <decebal.suiu@gmail.com>2013-10-01 09:23:48 +0300
committerDecebal Suiu <decebal.suiu@gmail.com>2013-10-01 09:23:48 +0300
commitc18773b3ed9735f475844e2abf2a253412c46fc0 (patch)
tree5f3e6617b20f31948c657e1c1e2adb8b060361eb
parent60fb88af769ad4f43ca35bc5527d57c982dcaaa2 (diff)
parentaab4e0129a722f98a70ca1b9ed1917befd31c9f0 (diff)
downloadpf4j-c18773b3ed9735f475844e2abf2a253412c46fc0.tar.gz
pf4j-c18773b3ed9735f475844e2abf2a253412c46fc0.zip
Merge branch 'master' of https://github.com/decebals/pf4j
-rw-r--r--.gitignore5
-rw-r--r--demo/api/pom.xml4
-rw-r--r--demo/app/pom.xml4
-rw-r--r--demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java88
-rw-r--r--demo/app/src/main/resources/log4j.properties2
-rw-r--r--demo/plugins/plugin1/plugin.properties (renamed from demo/plugin1/plugin.properties)0
-rw-r--r--demo/plugins/plugin1/pom.xml (renamed from demo/plugin1/pom.xml)6
-rw-r--r--demo/plugins/plugin1/src/main/assembly/assembly.xml (renamed from demo/plugin1/src/main/assembly/assembly.xml)0
-rw-r--r--demo/plugins/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java (renamed from demo/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java)0
-rw-r--r--demo/plugins/plugin2/plugin.properties (renamed from demo/plugin2/plugin.properties)0
-rw-r--r--demo/plugins/plugin2/pom.xml (renamed from demo/plugin2/pom.xml)6
-rw-r--r--demo/plugins/plugin2/src/main/assembly/assembly.xml (renamed from demo/plugin2/src/main/assembly/assembly.xml)0
-rw-r--r--demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java (renamed from demo/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java)0
-rw-r--r--demo/plugins/pom.xml37
-rw-r--r--demo/pom.xml7
-rw-r--r--pf4j/pom.xml4
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java63
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java76
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java134
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java4
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java102
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java59
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java135
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java10
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java80
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/AndFileFilter.java76
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/DirectoryFileFilter.java (renamed from pf4j/src/main/java/ro/fortsoft/pf4j/util/DirectoryFilter.java)13
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/ExtensionFileFilter.java (renamed from pf4j/src/main/java/ro/fortsoft/pf4j/util/ExtensionFilter.java)16
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/HiddenFilter.java30
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/JarFileFilter.java (renamed from pf4j/src/main/java/ro/fortsoft/pf4j/util/JarFilter.java)4
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/NotFileFilter.java36
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java4
-rw-r--r--pf4j/src/main/java/ro/fortsoft/pf4j/util/ZipFileFilter.java (renamed from pf4j/src/main/java/ro/fortsoft/pf4j/util/ZipFilter.java)4
-rw-r--r--pom.xml2
-rw-r--r--run-demo.bat4
-rwxr-xr-xrun-demo.sh4
36 files changed, 713 insertions, 306 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..00a7233
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+target/
+.classpath
+.project
+.settings
+
diff --git a/demo/api/pom.xml b/demo/api/pom.xml
index 2a2a04b..1818ec5 100644
--- a/demo/api/pom.xml
+++ b/demo/api/pom.xml
@@ -4,12 +4,12 @@
<parent>
<groupId>ro.fortsoft.pf4j.demo</groupId>
<artifactId>pf4j-demo-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pf4j-demo-api</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Demo Api</name>
diff --git a/demo/app/pom.xml b/demo/app/pom.xml
index cef9586..bf07815 100644
--- a/demo/app/pom.xml
+++ b/demo/app/pom.xml
@@ -4,12 +4,12 @@
<parent>
<groupId>ro.fortsoft.pf4j.demo</groupId>
<artifactId>pf4j-demo-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pf4j-demo-app</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Demo App</name>
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 9f218cf..7681a75 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
@@ -12,12 +12,19 @@
*/
package ro.fortsoft.pf4j.demo;
+import java.io.File;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
import org.apache.commons.lang.StringUtils;
import ro.fortsoft.pf4j.DefaultPluginManager;
+import ro.fortsoft.pf4j.PluginClasspath;
+import ro.fortsoft.pf4j.PluginDescriptorFinder;
import ro.fortsoft.pf4j.PluginManager;
+import ro.fortsoft.pf4j.PropertiesPluginDescriptorFinder;
import ro.fortsoft.pf4j.demo.api.Greeting;
/**
@@ -26,21 +33,25 @@ import ro.fortsoft.pf4j.demo.api.Greeting;
* @author Decebal Suiu
*/
public class Boot {
-
+
public static void main(String[] args) {
// print logo
printLogo();
- // load and start (active/resolved) plugins
- final PluginManager pluginManager = new DefaultPluginManager();
+ // create the plugin manager
+ final PluginManager pluginManager = createPluginManager();
+
+ // load and start (active/resolved) the plugins
pluginManager.loadPlugins();
pluginManager.startPlugins();
+ // retrieves the extensions for Greeting extension point
List<Greeting> greetings = pluginManager.getExtensions(Greeting.class);
for (Greeting greeting : greetings) {
System.out.println(">>> " + greeting.getGreeting());
}
+ // stop the plugins
pluginManager.stopPlugins();
/*
Runtime.getRuntime().addShutdownHook(new Thread() {
@@ -53,11 +64,82 @@ public class Boot {
});
*/
}
+
+ private static PluginManager createPluginManager() {
+ // retrieves the pf4j runtime mode
+ String modeAsString = System.getProperty("pf4j.mode", RuntimeMode.PROD.toString());
+ RuntimeMode mode = RuntimeMode.byName(modeAsString);
+
+ System.out.println("PF4J runtime mode: '" + mode + "'");
+
+ // create the plugin manager depending on runtime mode
+ PluginManager pluginManager = null;
+ if (mode == RuntimeMode.PROD) {
+ pluginManager = new DefaultPluginManager();
+ } else if (mode == RuntimeMode.DEV) {
+ // run from eclipse IDE (for example)
+ pluginManager = new DefaultPluginManager(new File("../plugins")) {
+
+ @Override
+ protected PluginClasspath createPluginClasspath() {
+ PluginClasspath pluginClasspath = super.createPluginClasspath();
+ // modify plugin classes
+ List<String> pluginClasses = pluginClasspath.getClassesDirectories();
+ pluginClasses.clear();
+ pluginClasses.add("target/classes");
+
+ return pluginClasspath;
+ }
+
+ @Override
+ protected PluginDescriptorFinder createPluginDescriptorFinder() {
+ return new PropertiesPluginDescriptorFinder();
+ }
+
+ };
+ }
+
+ return pluginManager;
+ }
private static void printLogo() {
System.out.println(StringUtils.repeat("#", 40));
System.out.println(StringUtils.center("PF4J-DEMO", 40));
System.out.println(StringUtils.repeat("#", 40));
}
+
+ public enum RuntimeMode {
+
+ DEV("dev"), // development
+ PROD("prod"); // production
+
+ private final String name;
+
+ private static final Map<String, RuntimeMode> map = new HashMap<String, RuntimeMode>();
+
+ static {
+ for (RuntimeMode mode : RuntimeMode.values()) {
+ map.put(mode.name, mode);
+ }
+ }
+
+ private RuntimeMode(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public static RuntimeMode byName(String name) {
+ if (map.containsKey(name)) {
+ return map.get(name);
+ }
+
+ throw new NoSuchElementException("Cannot found PF4J runtime mode with name '" + name + "'");
+ }
+
+ }
}
diff --git a/demo/app/src/main/resources/log4j.properties b/demo/app/src/main/resources/log4j.properties
index f2160e8..3ac64fd 100644
--- a/demo/app/src/main/resources/log4j.properties
+++ b/demo/app/src/main/resources/log4j.properties
@@ -2,5 +2,5 @@ log4j.rootLogger=DEBUG,Console
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.appender.Console.layout.conversionPattern=%-5p - %-32.32c{1} - %m\n
diff --git a/demo/plugin1/plugin.properties b/demo/plugins/plugin1/plugin.properties
index 4f95d99..4f95d99 100644
--- a/demo/plugin1/plugin.properties
+++ b/demo/plugins/plugin1/plugin.properties
diff --git a/demo/plugin1/pom.xml b/demo/plugins/plugin1/pom.xml
index 49cf1df..8fe5f7b 100644
--- a/demo/plugin1/pom.xml
+++ b/demo/plugins/plugin1/pom.xml
@@ -3,13 +3,13 @@
<parent>
<groupId>ro.fortsoft.pf4j.demo</groupId>
- <artifactId>pf4j-demo-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <artifactId>pf4j-demo-plugins</artifactId>
+ <version>0.6-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pf4j-demo-plugin1</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Demo Plugin #1</name>
diff --git a/demo/plugin1/src/main/assembly/assembly.xml b/demo/plugins/plugin1/src/main/assembly/assembly.xml
index 3fdc464..3fdc464 100644
--- a/demo/plugin1/src/main/assembly/assembly.xml
+++ b/demo/plugins/plugin1/src/main/assembly/assembly.xml
diff --git a/demo/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java b/demo/plugins/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java
index d10d3dd..d10d3dd 100644
--- a/demo/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java
+++ b/demo/plugins/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java
diff --git a/demo/plugin2/plugin.properties b/demo/plugins/plugin2/plugin.properties
index 0de45e6..0de45e6 100644
--- a/demo/plugin2/plugin.properties
+++ b/demo/plugins/plugin2/plugin.properties
diff --git a/demo/plugin2/pom.xml b/demo/plugins/plugin2/pom.xml
index b69f767..2bf0dd8 100644
--- a/demo/plugin2/pom.xml
+++ b/demo/plugins/plugin2/pom.xml
@@ -3,13 +3,13 @@
<parent>
<groupId>ro.fortsoft.pf4j.demo</groupId>
- <artifactId>pf4j-demo-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <artifactId>pf4j-demo-plugins</artifactId>
+ <version>0.6-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pf4j-demo-plugin2</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Demo Plugin #2</name>
diff --git a/demo/plugin2/src/main/assembly/assembly.xml b/demo/plugins/plugin2/src/main/assembly/assembly.xml
index 5cefe0d..5cefe0d 100644
--- a/demo/plugin2/src/main/assembly/assembly.xml
+++ b/demo/plugins/plugin2/src/main/assembly/assembly.xml
diff --git a/demo/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java b/demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java
index 8f12e23..8f12e23 100644
--- a/demo/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java
+++ b/demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java
diff --git a/demo/plugins/pom.xml b/demo/plugins/pom.xml
new file mode 100644
index 0000000..d451b31
--- /dev/null
+++ b/demo/plugins/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>ro.fortsoft.pf4j.demo</groupId>
+ <artifactId>pf4j-demo-parent</artifactId>
+ <version>0.6-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>ro.fortsoft.pf4j.demo</groupId>
+ <artifactId>pf4j-demo-plugins</artifactId>
+ <version>0.6-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>Demo Plugins Parent</name>
+
+ <build>
+ <resources>
+ <resource>
+ <filtering>false</filtering>
+ <directory>src/main/java</directory>
+ <excludes>
+ <exclude>**/*.java</exclude>
+ </excludes>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+ </build>
+
+ <modules>
+ <module>plugin1</module>
+ <module>plugin2</module>
+ </modules>
+
+</project>
diff --git a/demo/pom.xml b/demo/pom.xml
index 76bd4d7..7d00cd7 100644
--- a/demo/pom.xml
+++ b/demo/pom.xml
@@ -4,13 +4,13 @@
<parent>
<groupId>ro.fortsoft.pf4j</groupId>
<artifactId>pf4j-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ro.fortsoft.pf4j.demo</groupId>
<artifactId>pf4j-demo-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Demo Parent</name>
@@ -32,8 +32,7 @@
<modules>
<module>app</module>
<module>api</module>
- <module>plugin1</module>
- <module>plugin2</module>
+ <module>plugins</module>
</modules>
</project>
diff --git a/pf4j/pom.xml b/pf4j/pom.xml
index 68b0710..0859a55 100644
--- a/pf4j/pom.xml
+++ b/pf4j/pom.xml
@@ -4,12 +4,12 @@
<parent>
<groupId>ro.fortsoft.pf4j</groupId>
<artifactId>pf4j-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pf4j</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>PF4J</name>
<description>Plugin Framework for Java</description>
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
index 492a701..66c1936 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Decebal Suiu
+ * 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:
@@ -12,69 +12,16 @@
*/
package ro.fortsoft.pf4j;
-import java.lang.reflect.AnnotatedElement;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.java.sezpoz.Index;
-import net.java.sezpoz.IndexItem;
-
/**
- * Using Sezpoz(http://sezpoz.java.net/) for extensions discovery.
+ * The default implementation for ExtensionFinder.
+ * Now, this class it's a "link" to {@link ro.fortsoft.pf4j.SezpozExtensionFinder}.
*
* @author Decebal Suiu
*/
-public class DefaultExtensionFinder implements ExtensionFinder {
+public class DefaultExtensionFinder extends SezpozExtensionFinder {
- private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFinder.class);
-
- private volatile List<IndexItem<Extension, Object>> indices;
- private ClassLoader classLoader;
-
public DefaultExtensionFinder(ClassLoader classLoader) {
- this.classLoader = classLoader;
+ super(classLoader);
}
- @Override
- public <T> List<ExtensionWrapper<T>> find(Class<T> type) {
- log.debug("Find extensions for " + type);
- List<ExtensionWrapper<T>> result = new ArrayList<ExtensionWrapper<T>>();
- getIndices();
-// System.out.println("indices = "+ indices);
- for (IndexItem<Extension, Object> item : indices) {
- try {
- AnnotatedElement element = item.element();
- Class<?> extensionType = (Class<?>) element;
- log.debug("Checking extension type " + extensionType);
- if (type.isAssignableFrom(extensionType)) {
- Object instance = item.instance();
- if (instance != null) {
- log.debug("Added extension " + extensionType);
- result.add(new ExtensionWrapper<T>(type.cast(instance), item.annotation().ordinal()));
- }
- }
- } catch (InstantiationException e) {
- log.error(e.getMessage(), e);
- }
- }
-
- return result;
- }
-
- private List<IndexItem<Extension, Object>> getIndices() {
- if (indices == null) {
- indices = new ArrayList<IndexItem<Extension, Object>>();
- Iterator<IndexItem<Extension, Object>> it = Index.load(Extension.class, Object.class, classLoader).iterator();
- while (it.hasNext()) {
- indices.add(it.next());
- }
- }
-
- return indices;
- }
-
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java
index 3e23ff1..144fc6e 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginDescriptorFinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Decebal Suiu
+ * 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:
@@ -12,78 +12,16 @@
*/
package ro.fortsoft.pf4j;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-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.
- *
+ * The default implementation for PluginDescriptorFinder.
+ * Now, this class it's a "link" to {@link ro.fortsoft.pf4j.ManifestPluginDescriptorFinder}.
+ *
* @author Decebal Suiu
*/
-public class DefaultPluginDescriptorFinder implements PluginDescriptorFinder {
-
- @Override
- public PluginDescriptor find(File pluginRepository) throws PluginException {
- // TODO it's ok with classes/ ?
- File manifestFile = new File(pluginRepository, "classes/META-INF/MANIFEST.MF");
- if (!manifestFile.exists()) {
- throw new PluginException("Cannot find '" + manifestFile + "' file");
- }
-
- FileInputStream input = null;
- try {
- input = new FileInputStream(manifestFile);
- } catch (FileNotFoundException e) {
- // not happening
- }
-
- Manifest manifest = null;
- try {
- manifest = new Manifest(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 !!!
- Attributes attrs = manifest.getMainAttributes();
- String id = attrs.getValue("Plugin-Id");
- if (StringUtils.isEmpty(id)) {
- throw new PluginException("Plugin-Id cannot be empty");
- }
- pluginDescriptor.setPluginId(id);
-
- String clazz = attrs.getValue("Plugin-Class");
- if (StringUtils.isEmpty(clazz)) {
- throw new PluginException("Plugin-Class cannot be empty");
- }
- pluginDescriptor.setPluginClass(clazz);
-
- String version = attrs.getValue("Plugin-Version");
- if (StringUtils.isEmpty(version)) {
- throw new PluginException("Plugin-Version cannot be empty");
- }
- pluginDescriptor.setPluginVersion(PluginVersion.createVersion(version));
-
- String provider = attrs.getValue("Plugin-Provider");
- pluginDescriptor.setProvider(provider);
- String dependencies = attrs.getValue("Plugin-Dependencies");
- pluginDescriptor.setDependencies(dependencies);
+public class DefaultPluginDescriptorFinder extends ManifestPluginDescriptorFinder {
- return pluginDescriptor;
+ public DefaultPluginDescriptorFinder(PluginClasspath pluginClasspath) {
+ super(pluginClasspath);
}
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
index 20aba2d..0c2628d 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
@@ -13,7 +13,7 @@
package ro.fortsoft.pf4j;
import java.io.File;
-import java.io.FilenameFilter;
+import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -24,11 +24,14 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ro.fortsoft.pf4j.util.AndFileFilter;
import ro.fortsoft.pf4j.util.CompoundClassLoader;
-import ro.fortsoft.pf4j.util.DirectoryFilter;
+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.ZipFilter;
+import ro.fortsoft.pf4j.util.ZipFileFilter;
/**
* Default implementation of the PluginManager interface.
@@ -44,9 +47,11 @@ public class DefaultPluginManager implements PluginManager {
*/
private File pluginsDirectory;
- private ExtensionFinder extensionFinder;
+ private final ExtensionFinder extensionFinder;
- private PluginDescriptorFinder pluginDescriptorFinder;
+ private final PluginDescriptorFinder pluginDescriptorFinder;
+
+ private final PluginClasspath pluginClasspath;
/**
* A map of plugins this manager is responsible for (the key is the 'pluginId').
@@ -111,17 +116,18 @@ public class DefaultPluginManager implements PluginManager {
disabledPlugins = new ArrayList<String>();
compoundClassLoader = new CompoundClassLoader();
+ pluginClasspath = createPluginClasspath();
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);
+ 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);
+ log.info("Disabled plugins: {}", disabledPlugins);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
@@ -160,7 +166,7 @@ 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);
@@ -179,7 +185,7 @@ 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) {
@@ -193,16 +199,17 @@ public class DefaultPluginManager implements PluginManager {
*/
@Override
public void loadPlugins() {
+ log.debug("Lookup plugins in '{}'", pluginsDirectory.getAbsolutePath());
// check for plugins directory
if (!pluginsDirectory.exists() || !pluginsDirectory.isDirectory()) {
- log.error("No '" + pluginsDirectory + "' directory");
+ log.error("No '{}' directory", pluginsDirectory.getAbsolutePath());
return;
}
// expand all plugin archives
- FilenameFilter zipFilter = new ZipFilter();
- String[] zipFiles = pluginsDirectory.list(zipFilter);
- for (String zipFile : zipFiles) {
+ FileFilter zipFilter = new ZipFileFilter();
+ File[] zipFiles = pluginsDirectory.listFiles(zipFilter);
+ for (File zipFile : zipFiles) {
try {
expandPluginArchive(zipFile);
} catch (IOException e) {
@@ -211,15 +218,18 @@ public class DefaultPluginManager implements PluginManager {
}
// check for no plugins
- FilenameFilter directoryFilter = new DirectoryFilter();
- String[] directories = pluginsDirectory.list(directoryFilter);
+ List<FileFilter> filterList = new ArrayList<FileFilter>();
+ filterList.add(new DirectoryFileFilter());
+ filterList.add(new NotFileFilter(createHiddenPluginFilter()));
+ FileFilter pluginsFilter = new AndFileFilter(filterList);
+ File[] directories = pluginsDirectory.listFiles(pluginsFilter);
if (directories.length == 0) {
log.info("No plugins");
return;
}
// load any plugin from plugins directory
- for (String directory : directories) {
+ for (File directory : directories) {
try {
loadPlugin(directory);
} catch (PluginException e) {
@@ -268,15 +278,43 @@ public class DefaultPluginManager implements PluginManager {
return null;
}
- private void loadPlugin(String fileName) throws PluginException {
- // test for plugin directory
- File pluginDirectory = new File(pluginsDirectory, fileName);
- if (!pluginDirectory.isDirectory()) {
- return;
- }
-
+ /**
+ * Add the possibility to override the PluginDescriptorFinder.
+ */
+ protected PluginDescriptorFinder createPluginDescriptorFinder() {
+ return new DefaultPluginDescriptorFinder(pluginClasspath);
+ }
+
+ /**
+ * Add the possibility to override the ExtensionFinder.
+ */
+ protected ExtensionFinder createExtensionFinder() {
+ return new DefaultExtensionFinder(compoundClassLoader);
+ }
+
+ /**
+ * Add the possibility to override the PluginClassPath.
+ */
+ protected PluginClasspath createPluginClasspath() {
+ return new PluginClasspath();
+ }
+
+ protected boolean isPluginDisabled(String pluginId) {
+ if (enabledPlugins.isEmpty()) {
+ return disabledPlugins.contains(pluginId);
+ }
+
+ return !enabledPlugins.contains(pluginId);
+ }
+
+ protected FileFilter createHiddenPluginFilter() {
+ return new HiddenFilter();
+ }
+
+ private void loadPlugin(File pluginDirectory) throws PluginException {
// try to load the plugin
- String pluginPath = "/".concat(fileName);
+ String pluginName = pluginDirectory.getName();
+ String pluginPath = "/".concat(pluginName);
// test for plugin duplication
if (plugins.get(pathToIdMap.get(pluginPath)) != null) {
@@ -284,28 +322,28 @@ public class DefaultPluginManager implements PluginManager {
}
// 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);
String pluginClassName = pluginDescriptor.getPluginClass();
- log.debug("Class '" + pluginClassName + "'" + " for plugin '" + pluginPath + "'");
+ log.debug("Class '{}' for plugin '{}'", pluginClassName, pluginPath);
// test for disabled plugin
if (isPluginDisabled(pluginDescriptor.getPluginId())) {
- log.info("Plugin '" + pluginPath + "' is disabled");
+ log.info("Plugin '{}' is disabled", pluginPath);
return;
}
// load plugin
- log.debug("Loading plugin '" + pluginPath + "'");
- PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory);
+ log.debug("Loading plugin '{}'", pluginPath);
+ PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory, pluginClasspath);
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 '{}' for plugin '{}'", pluginWrapper, pluginPath);
String pluginId = pluginDescriptor.getPluginId();
@@ -318,37 +356,15 @@ 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);
+ private void expandPluginArchive(File pluginArchiveFile) throws IOException {
+ String fileName = pluginArchiveFile.getName();
long pluginArchiveDate = pluginArchiveFile.lastModified();
String pluginName = fileName.substring(0, fileName.length() - 4);
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 + "'");
- // create directorie for plugin
+ log.debug("Expand plugin archive '{}' in '{}'", pluginArchiveFile, pluginDirectory);
+ // create directory for plugin
pluginDirectory.mkdirs();
// expand '.zip' file
@@ -369,7 +385,7 @@ 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 '{}' resolved", pluginWrapper.getDescriptor().getPluginId());
}
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java
index 8611fef..a64aef5 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DependencyResolver.java
@@ -51,14 +51,14 @@ class DependencyResolver {
}
}
- log.debug("Graph: " + graph);
+ log.debug("Graph: {}", graph);
List<String> pluginsId = graph.reverseTopologicalSort();
if (pluginsId == null) {
throw new CyclicDependencyException("Cyclic dependences !!!" + graph.toString());
}
- log.debug("Plugins order: " + pluginsId);
+ log.debug("Plugins order: {}", pluginsId);
List<PluginWrapper> sortedPlugins = new ArrayList<PluginWrapper>();
for (String pluginId : pluginsId) {
sortedPlugins.add(getPlugin(pluginId));
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java
new file mode 100644
index 0000000..fd82793
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java
@@ -0,0 +1,102 @@
+/*
+ * 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.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ro.fortsoft.pf4j.util.StringUtils;
+
+/**
+ * Read the plugin descriptor from the manifest file.
+ *
+ * @author Decebal Suiu
+ */
+public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder {
+
+ private static final Logger log = LoggerFactory.getLogger(ManifestPluginDescriptorFinder.class);
+
+ private PluginClasspath pluginClasspath;
+
+ public ManifestPluginDescriptorFinder(PluginClasspath pluginClasspath) {
+ this.pluginClasspath = pluginClasspath;
+ }
+
+ @Override
+ public PluginDescriptor find(File pluginRepository) throws PluginException {
+ // TODO it's ok with first classes directory? Another idea is to specify in PluginClasspath the folder.
+ String classes = pluginClasspath.getClassesDirectories().get(0);
+ File manifestFile = new File(pluginRepository, classes + "/META-INF/MANIFEST.MF");
+ log.debug("Lookup plugin descriptor in '{}'", manifestFile);
+ if (!manifestFile.exists()) {
+ throw new PluginException("Cannot find '" + manifestFile + "' file");
+ }
+
+ FileInputStream input = null;
+ try {
+ input = new FileInputStream(manifestFile);
+ } catch (FileNotFoundException e) {
+ // not happening
+ }
+
+ Manifest manifest = null;
+ try {
+ manifest = new Manifest(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 !!!
+ Attributes attrs = manifest.getMainAttributes();
+ String id = attrs.getValue("Plugin-Id");
+ if (StringUtils.isEmpty(id)) {
+ throw new PluginException("Plugin-Id cannot be empty");
+ }
+ pluginDescriptor.setPluginId(id);
+
+ String clazz = attrs.getValue("Plugin-Class");
+ if (StringUtils.isEmpty(clazz)) {
+ throw new PluginException("Plugin-Class cannot be empty");
+ }
+ pluginDescriptor.setPluginClass(clazz);
+
+ String version = attrs.getValue("Plugin-Version");
+ if (StringUtils.isEmpty(version)) {
+ throw new PluginException("Plugin-Version cannot be empty");
+ }
+ pluginDescriptor.setPluginVersion(PluginVersion.createVersion(version));
+
+ String provider = attrs.getValue("Plugin-Provider");
+ pluginDescriptor.setProvider(provider);
+ String dependencies = attrs.getValue("Plugin-Dependencies");
+ pluginDescriptor.setDependencies(dependencies);
+
+ return pluginDescriptor;
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java
new file mode 100644
index 0000000..23cd8f6
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginClasspath.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package ro.fortsoft.pf4j;
+
+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".
+ *
+ * @author Decebal Suiu
+ */
+public class PluginClasspath {
+
+ private static final String DEFAULT_CLASSES_DIRECTORY = "classes";
+ private static final String DEFAULT_LIB_DIRECTORY = "lib";
+
+ private List<String> classesDirectories;
+ private List<String> libDirectories;
+
+ public PluginClasspath() {
+ classesDirectories = new ArrayList<String>();
+ libDirectories = new ArrayList<String>();
+
+ // add defaults
+ classesDirectories.add(DEFAULT_CLASSES_DIRECTORY);
+ libDirectories.add(DEFAULT_LIB_DIRECTORY);
+ }
+
+ public List<String> getClassesDirectories() {
+ return classesDirectories;
+ }
+
+ public void setClassesDirectories(List<String> classesDirectories) {
+ this.classesDirectories = classesDirectories;
+ }
+
+ public List<String> getLibDirectories() {
+ return libDirectories;
+ }
+
+ public void setLibDirectories(List<String> libDirectories) {
+ this.libDirectories = libDirectories;
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
index 78603f4..8bd2daa 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
@@ -13,15 +13,16 @@
package ro.fortsoft.pf4j;
import java.io.File;
-import java.io.FilenameFilter;
+import java.io.FileFilter;
import java.net.MalformedURLException;
+import java.util.List;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import ro.fortsoft.pf4j.util.DirectoryFilter;
-import ro.fortsoft.pf4j.util.JarFilter;
+import ro.fortsoft.pf4j.util.DirectoryFileFilter;
+import ro.fortsoft.pf4j.util.JarFileFilter;
/**
* Load all informations needed by a plugin.
@@ -40,25 +41,15 @@ class PluginLoader {
*/
private File pluginRepository;
- /*
- * The directory with '.class' files.
- */
- private File classesDirectory;
-
- /*
- * The directory with '.jar' files.
- */
- private File libDirectory;
-
+ private PluginClasspath pluginClasspath;
private PluginClassLoader pluginClassLoader;
- public PluginLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, File pluginRepository) {
+ public PluginLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, File pluginRepository, PluginClasspath pluginClasspath) {
this.pluginRepository = pluginRepository;
- classesDirectory = new File(pluginRepository, "classes");
- libDirectory = new File(pluginRepository, "lib");
+ this.pluginClasspath = pluginClasspath;
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() {
@@ -77,66 +68,76 @@ class PluginLoader {
return loadClasses() && loadJars();
}
- private void getJars(Vector<String> v, File file) {
- FilenameFilter jarFilter = new JarFilter();
- FilenameFilter directoryFilter = new DirectoryFilter();
-
- if (file.exists() && file.isDirectory() && file.isAbsolute()) {
- String[] jars = file.list(jarFilter);
- for (int i = 0; (jars != null) && (i < jars.length); ++i) {
- v.addElement(jars[i]);
- }
-
- String[] directoryList = file.list(directoryFilter);
- for (int i = 0; (directoryList != null) && (i < directoryList.length); ++i) {
- File directory = new File(file, directoryList[i]);
- getJars(v, directory);
- }
- }
- }
-
private boolean loadClasses() {
- // make 'classesDirectory' absolute
- classesDirectory = classesDirectory.getAbsoluteFile();
-
- if (classesDirectory.exists() && classesDirectory.isDirectory()) {
- log.debug("Found '" + classesDirectory.getPath() + "' directory");
-
- try {
- pluginClassLoader.addURL(classesDirectory.toURI().toURL());
- log.debug("Added '" + classesDirectory + "' to the class loader path");
- } catch (MalformedURLException e) {
- e.printStackTrace();
- log.error(e.getMessage(), e);
- return false;
- }
- }
+ List<String> classesDirectories = pluginClasspath.getClassesDirectories();
+
+ // add each classes directory to plugin class loader
+ for (String classesDirectory : classesDirectories) {
+ // make 'classesDirectory' absolute
+ File file = new File(pluginRepository, classesDirectory).getAbsoluteFile();
+
+ if (file.exists() && file.isDirectory()) {
+ log.debug("Found '{}' directory", file.getPath());
+
+ try {
+ pluginClassLoader.addURL(file.toURI().toURL());
+ log.debug("Added '{}' to the class loader path", file);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+ }
return true;
}
/**
- * Add all *.jar files from '/lib' directory.
+ * Add all *.jar files from lib directories to class loader.
*/
private boolean loadJars() {
- // make 'jarDirectory' absolute
- libDirectory = libDirectory.getAbsoluteFile();
-
- Vector<String> jars = new Vector<String>();
- getJars(jars, libDirectory);
- for (String jar : jars) {
- File jarFile = new File(libDirectory, jar);
- try {
- pluginClassLoader.addURL(jarFile.toURI().toURL());
- log.debug("Added '" + jarFile + "' to the class loader path");
- } catch (MalformedURLException e) {
- e.printStackTrace();
- log.error(e.getMessage(), e);
- return false;
- }
- }
+ List<String> libDirectories = pluginClasspath.getLibDirectories();
+
+ // add each jars directory to plugin class loader
+ for (String libDirectory : libDirectories) {
+ // make 'libDirectory' absolute
+ File file = new File(pluginRepository, libDirectory).getAbsoluteFile();
+
+ // collect all jars from current lib directory in jars variable
+ Vector<File> jars = new Vector<File>();
+ getJars(jars, file);
+ for (File jar : jars) {
+ try {
+ pluginClassLoader.addURL(jar.toURI().toURL());
+ log.debug("Added '{}' to the class loader path", jar);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+ }
return true;
}
+ private void getJars(Vector<File> bucket, File file) {
+ FileFilter jarFilter = new JarFileFilter();
+ FileFilter directoryFilter = new DirectoryFileFilter();
+
+ if (file.exists() && file.isDirectory() && file.isAbsolute()) {
+ File[] jars = file.listFiles(jarFilter);
+ for (int i = 0; (jars != null) && (i < jars.length); ++i) {
+ bucket.addElement(jars[i]);
+ }
+
+ File[] directories = file.listFiles(directoryFilter);
+ for (int i = 0; (directories != null) && (i < directories.length); ++i) {
+ File directory = directories[i];
+ getJars(bucket, directory);
+ }
+ }
+ }
+
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java
index 4f0e753..2c7c707 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PropertiesPluginDescriptorFinder.java
@@ -19,6 +19,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import ro.fortsoft.pf4j.util.StringUtils;
/**
@@ -28,10 +31,14 @@ import ro.fortsoft.pf4j.util.StringUtils;
*/
public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder {
+ private static final Logger log = LoggerFactory.getLogger(PropertiesPluginDescriptorFinder.class);
+
+ private static final String DEFAULT_PROPERTIES_FILE_NAME = "plugin.properties";
+
private String propertiesFileName;
public PropertiesPluginDescriptorFinder() {
- this("plugin.properties");
+ this(DEFAULT_PROPERTIES_FILE_NAME);
}
public PropertiesPluginDescriptorFinder(String propertiesFileName) {
@@ -41,6 +48,7 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder
@Override
public PluginDescriptor find(File pluginRepository) throws PluginException {
File propertiesFile = new File(pluginRepository, propertiesFileName);
+ log.debug("Lookup plugin descriptor in '{}'", propertiesFile);
if (!propertiesFile.exists()) {
throw new PluginException("Cannot find '" + propertiesFile + "' file");
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java
new file mode 100644
index 0000000..3f5014c
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java
@@ -0,0 +1,80 @@
+/*
+ * 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.lang.reflect.AnnotatedElement;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.java.sezpoz.Index;
+import net.java.sezpoz.IndexItem;
+
+/**
+ * Using Sezpoz(http://sezpoz.java.net/) for extensions discovery.
+ *
+ * @author Decebal Suiu
+ */
+public class SezpozExtensionFinder implements ExtensionFinder {
+
+ private static final Logger log = LoggerFactory.getLogger(SezpozExtensionFinder.class);
+
+ private volatile List<IndexItem<Extension, Object>> indices;
+ private ClassLoader classLoader;
+
+ public SezpozExtensionFinder(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public <T> List<ExtensionWrapper<T>> find(Class<T> type) {
+ log.debug("Find extensions for {}", type);
+ List<ExtensionWrapper<T>> result = new ArrayList<ExtensionWrapper<T>>();
+ getIndices();
+// System.out.println("indices = "+ indices);
+ for (IndexItem<Extension, Object> item : indices) {
+ try {
+ AnnotatedElement element = item.element();
+ Class<?> extensionType = (Class<?>) element;
+ log.debug("Checking extension type {}", extensionType);
+ if (type.isAssignableFrom(extensionType)) {
+ Object instance = item.instance();
+ if (instance != null) {
+ log.debug("Added extension {}", extensionType);
+ result.add(new ExtensionWrapper<T>(type.cast(instance), item.annotation().ordinal()));
+ }
+ }
+ } catch (InstantiationException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ return result;
+ }
+
+ private List<IndexItem<Extension, Object>> getIndices() {
+ if (indices == null) {
+ indices = new ArrayList<IndexItem<Extension, Object>>();
+ Iterator<IndexItem<Extension, Object>> it = Index.load(Extension.class, Object.class, classLoader).iterator();
+ while (it.hasNext()) {
+ indices.add(it.next());
+ }
+ }
+
+ return indices;
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/AndFileFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/AndFileFilter.java
new file mode 100644
index 0000000..b50e852
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/AndFileFilter.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+package ro.fortsoft.pf4j.util;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This filter providing conditional AND logic across a list of
+ * file filters. This filter returns <code>true</code> if all filters in the
+ * list return <code>true</code>. Otherwise, it returns <code>false</code>.
+ * Checking of the file filter list stops when the first filter returns
+ * <code>false</code>.
+ *
+ * @author Decebal Suiu
+ */
+public class AndFileFilter implements FileFilter {
+
+ /** The list of file filters. */
+ private List<FileFilter> fileFilters;
+
+ public AndFileFilter() {
+ this.fileFilters = new ArrayList<FileFilter>();
+ }
+
+ public AndFileFilter(List<FileFilter> fileFilters) {
+ this.fileFilters = new ArrayList<FileFilter>(fileFilters);
+ }
+
+ public void addFileFilter(FileFilter fileFilter) {
+ fileFilters.add(fileFilter);
+ }
+
+ public List<FileFilter> getFileFilters() {
+ return Collections.unmodifiableList(fileFilters);
+ }
+
+ public boolean removeFileFilter(FileFilter fileFilter) {
+ return fileFilters.remove(fileFilter);
+ }
+
+ public void setFileFilters(List<FileFilter> fileFilters) {
+ this.fileFilters = new ArrayList<FileFilter>(fileFilters);
+ }
+
+ @Override
+ public boolean accept(File file) {
+ if (this.fileFilters.size() == 0) {
+ return false;
+ }
+
+ for (Iterator<FileFilter> iter = this.fileFilters.iterator(); iter.hasNext();) {
+ FileFilter fileFilter = (FileFilter) iter.next();
+ if (!fileFilter.accept(file)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/DirectoryFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/DirectoryFileFilter.java
index 54e1a95..3877222 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/DirectoryFilter.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/DirectoryFileFilter.java
@@ -14,22 +14,17 @@ package ro.fortsoft.pf4j.util;
import java.io.File;
import java.io.FileFilter;
-import java.io.FilenameFilter;
/**
+ * Filter accepts files that are directories.
+ *
* @author Decebal Suiu
*/
-public class DirectoryFilter implements FileFilter, FilenameFilter {
+public class DirectoryFileFilter implements FileFilter {
- /**
- * Accepts any file ending in .jar. The case of the filename is ignored.
- */
+ @Override
public boolean accept(File file) {
return file.isDirectory();
}
- public boolean accept(File dir, String name) {
- return accept(new File(dir, name));
- }
-
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/ExtensionFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/ExtensionFileFilter.java
index 22b999f..03ed0b7 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/ExtensionFilter.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/ExtensionFileFilter.java
@@ -13,29 +13,25 @@
package ro.fortsoft.pf4j.util;
import java.io.File;
-import java.io.FilenameFilter;
+import java.io.FileFilter;
/**
+ * Filter accepts any file ending in extension. The case of the filename is ignored.
+ *
* @author Decebal Suiu
*/
-public class ExtensionFilter implements FilenameFilter {
+public class ExtensionFileFilter implements FileFilter {
private String extension;
- public ExtensionFilter(String extension) {
+ public ExtensionFileFilter(String extension) {
this.extension = extension;
}
- /**
- * Accepts any file ending in extension. The case of the filename is ignored.
- */
+ @Override
public boolean accept(File file) {
// perform a case insensitive check.
return file.getName().toUpperCase().endsWith(extension.toUpperCase());
}
- public boolean accept(File dir, String name) {
- return accept(new File(dir, name));
- }
-
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/HiddenFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/HiddenFilter.java
new file mode 100644
index 0000000..eed53f1
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/HiddenFilter.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+package ro.fortsoft.pf4j.util;
+
+import java.io.File;
+import java.io.FileFilter;
+
+/**
+ * Filter that only accepts hidden files.
+ *
+ * @author decebal.suiu
+ */
+public class HiddenFilter implements FileFilter {
+
+ @Override
+ public boolean accept(File file) {
+ return file.isHidden();
+ }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/JarFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/JarFileFilter.java
index 60c8859..5c1f0ca 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/JarFilter.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/JarFileFilter.java
@@ -18,14 +18,14 @@ package ro.fortsoft.pf4j.util;
*
* @author Decebal Suiu
*/
-public class JarFilter extends ExtensionFilter {
+public class JarFileFilter extends ExtensionFileFilter {
/**
* The extension that this filter will search for.
*/
private static final String JAR_EXTENSION = ".JAR";
- public JarFilter() {
+ public JarFileFilter() {
super(JAR_EXTENSION);
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/NotFileFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/NotFileFilter.java
new file mode 100644
index 0000000..68ff3e0
--- /dev/null
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/NotFileFilter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+package ro.fortsoft.pf4j.util;
+
+import java.io.File;
+import java.io.FileFilter;
+
+/**
+ * This filter produces a logical NOT of the filters specified.
+ *
+ * @author Decebal Suiu
+ */
+public class NotFileFilter implements FileFilter {
+
+ private FileFilter filter;
+
+ public NotFileFilter(FileFilter filter) {
+ this.filter = filter;
+ }
+
+ @Override
+ public boolean accept(File file) {
+ return !filter.accept(file);
+ }
+
+}
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 e3f3ed3..74d60d5 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/Unzip.java
@@ -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 '{}' to '{}'", source, 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 '{}' not found", zipEntry.getName());
}
}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/ZipFilter.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/ZipFileFilter.java
index 4b10de3..9743fb6 100644
--- a/pf4j/src/main/java/ro/fortsoft/pf4j/util/ZipFilter.java
+++ b/pf4j/src/main/java/ro/fortsoft/pf4j/util/ZipFileFilter.java
@@ -18,14 +18,14 @@ package ro.fortsoft.pf4j.util;
*
* @author Decebal Suiu
*/
-public class ZipFilter extends ExtensionFilter {
+public class ZipFileFilter extends ExtensionFileFilter {
/**
* The extension that this filter will search for.
*/
private static final String ZIP_EXTENSION = ".ZIP";
- public ZipFilter() {
+ public ZipFileFilter() {
super(ZIP_EXTENSION);
}
diff --git a/pom.xml b/pom.xml
index 3c9bb2e..c54a45b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ro.fortsoft.pf4j</groupId>
<artifactId>pf4j-parent</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
<packaging>pom</packaging>
<name>PF4J Parent</name>
<description>Plugin Framework for Java</description>
diff --git a/run-demo.bat b/run-demo.bat
index 05c53df..0edca59 100644
--- a/run-demo.bat
+++ b/run-demo.bat
@@ -12,8 +12,8 @@ mkdir demo-dist\plugins
REM copy artifacts to demo-dist folder
xcopy demo\app\target\pf4j-demo-app-*.zip demo-dist /s /i
-xcopy demo\plugin1\target\pf4j-demo-plugin1-*.zip demo-dist\plugins /s
-xcopy demo\plugin2\target\pf4j-demo-plugin2-*.zip demo-dist\plugins /s
+xcopy demo\plugins\plugin1\target\pf4j-demo-plugin1-*.zip demo-dist\plugins /s
+xcopy demo\plugins\plugin2\target\pf4j-demo-plugin2-*.zip demo-dist\plugins /s
cd demo-dist
diff --git a/run-demo.sh b/run-demo.sh
index ce68e5b..724d68b 100755
--- a/run-demo.sh
+++ b/run-demo.sh
@@ -14,8 +14,8 @@ mkdir demo-dist/plugins
# copy artifacts to demo-dist folder
cp -r demo/app/target/pf4j-demo-*/* demo-dist/
-cp demo/plugin1/target/pf4j-demo-plugin1-*.zip demo-dist/plugins/
-cp demo/plugin2/target/pf4j-demo-plugin2-*.zip demo-dist/plugins/
+cp demo/plugins/plugin1/target/pf4j-demo-plugin1-*.zip demo-dist/plugins/
+cp demo/plugins/plugin2/target/pf4j-demo-plugin2-*.zip demo-dist/plugins/
# run demo
cd demo-dist