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 - %-30.30c{1} - %m\n
/*
- * 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:
*/
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;
- }
-
}
/*
- * 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:
*/
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);
}
}
*/
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').
disabledPlugins = new ArrayList<String>();
compoundClassLoader = new CompoundClassLoader();
+ pluginClasspath = createPluginClasspath();
pluginDescriptorFinder = createPluginDescriptorFinder();
extensionFinder = createExtensionFinder();
* Add the possibility to override the PluginDescriptorFinder.
*/
protected PluginDescriptorFinder createPluginDescriptorFinder() {
- return new DefaultPluginDescriptorFinder();
+ return new DefaultPluginDescriptorFinder(pluginClasspath);
}
/**
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);
// load plugin
log.debug("Loading plugin '{}'", pluginPath);
- PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory);
+ PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory, pluginClasspath);
pluginLoader.load();
log.debug("Loaded plugin '{}'", pluginPath);
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
import java.io.File;
import java.io.FileFilter;
import java.net.MalformedURLException;
+import java.util.List;
import java.util.Vector;
import org.slf4j.Logger;
*/
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);
return loadClasses() && loadJars();
}
+ private boolean loadClasses() {
+ 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 directories to class loader.
+ */
+ private boolean loadJars() {
+ 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();
}
}
- private boolean loadClasses() {
- // make 'classesDirectory' absolute
- classesDirectory = classesDirectory.getAbsoluteFile();
-
- if (classesDirectory.exists() && classesDirectory.isDirectory()) {
- log.debug("Found '{}' directory", classesDirectory.getPath());
-
- try {
- pluginClassLoader.addURL(classesDirectory.toURI().toURL());
- log.debug("Added '{}' to the class loader path", classesDirectory);
- } catch (MalformedURLException e) {
- e.printStackTrace();
- log.error(e.getMessage(), e);
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Add all *.jar files from '/lib' directory.
- */
- private boolean loadJars() {
- // make 'jarDirectory' absolute
- libDirectory = libDirectory.getAbsoluteFile();
-
- Vector<File> jars = new Vector<File>();
- getJars(jars, libDirectory);
- 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;
- }
-
}
--- /dev/null
+/*
+ * 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;
+ }
+
+}