--- /dev/null
+/*
+ * Copyright 2014 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default implementation for ExtensionFactory.
+ * It uses Class.newInstance() method.
+ *
+ * @author Decebal Suiu
+ */
+public class DefaultExtensionFactory implements ExtensionFactory {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFactory.class);
+
+ /**
+ * Creates an extension instance. If an error occurs than that error is logged and the method returns null.
+ * @param extensionClass
+ * @return
+ */
+ @Override
+ public Object create(Class<?> extensionClass) {
+ log.debug("Create instance for extension '{}'", extensionClass.getName());
+ try {
+ return extensionClass.newInstance();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+
+ return null;
+ }
+
+}
private ExtensionFactory extensionFactory;
private volatile Map<String, Set<String>> entries; // cache by pluginId
- public DefaultExtensionFinder(PluginManager pluginManager) {
+ public DefaultExtensionFinder(PluginManager pluginManager, ExtensionFactory extensionFactory) {
this.pluginManager = pluginManager;
- this.extensionFactory = createExtensionFactory();
+ this.extensionFactory = extensionFactory;
}
@Override
for (String className : extensionClassNames) {
try {
- Class<?> extensionType;
+ Class<?> extensionClass;
if (pluginId != null) {
- extensionType = pluginManager.getPluginClassLoader(pluginId).loadClass(className);
+ extensionClass = pluginManager.getPluginClassLoader(pluginId).loadClass(className);
} else {
- extensionType = getClass().getClassLoader().loadClass(className);
+ extensionClass = getClass().getClassLoader().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()));
- }
+ log.debug("Checking extension type '{}'", className);
+ if (type.isAssignableFrom(extensionClass) && extensionClass.isAnnotationPresent(Extension.class)) {
+ Extension extension = extensionClass.getAnnotation(Extension.class);
+ ExtensionDescriptor descriptor = new ExtensionDescriptor();
+ descriptor.setOrdinal(extension.ordinal());
+ descriptor.setExtensionClass(extensionClass);
+
+ ExtensionWrapper extensionWrapper = new ExtensionWrapper<T>(descriptor);
+ extensionWrapper.setExtensionFactory(extensionFactory);
+ result.add(extensionWrapper);
+ log.debug("Added extension '{}' with ordinal {}", className, extension.ordinal());
} else {
- log.debug("'{}' is not an extension for extension point '{}'", extensionType.getName(), type.getName());
+ log.debug("'{}' is not an extension for extension point '{}'", className, type.getName());
}
} catch (ClassNotFoundException e) {
log.error(e.getMessage(), e);
entries = null;
}
- /**
- * Add the possibility to override the ExtensionFactory.
- * The default implementation uses Class.newInstance() method.
- */
- protected ExtensionFactory createExtensionFactory() {
- return new ExtensionFactory() {
-
- @Override
- public Object create(Class<?> extensionType) {
- log.debug("Create instance for extension '{}'", extensionType.getName());
-
- try {
- return extensionType.newInstance();
- } catch (InstantiationException e) {
- log.error(e.getMessage(), e);
- } catch (IllegalAccessException e) {
- log.error(e.getMessage(), e);
- }
-
- return null;
- }
-
- };
- }
-
private Map<String, Set<String>> readIndexFiles() {
// checking cache
if (entries != null) {
return ExtensionPoint.class.isAssignableFrom(type);
}
- /**
- * Creates an extension instance.
- */
- public static interface ExtensionFactory {
-
- public Object create(Class<?> extensionType);
-
- }
-
}
--- /dev/null
+/*
+ * Copyright 2014 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+/**
+ * The default implementation for PluginFactory.
+ * It uses Class.newInstance() method.
+ *
+ * @author Decebal Suiu
+ */
+public class DefaultPluginFactory implements PluginFactory {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFactory.class);
+
+ /**
+ * Creates a plugin instance. If an error occurs than that error is logged and the method returns null.
+ * @param pluginWrapper
+ * @return
+ */
+ @Override
+ public Plugin create(final PluginWrapper pluginWrapper) {
+ String pluginClassName = pluginWrapper.getDescriptor().getPluginClass();
+ log.debug("Create instance for plugin '{}'", pluginClassName);
+
+ Class<?> pluginClass;
+ try {
+ pluginClass = pluginWrapper.getPluginClassLoader().loadClass(pluginClassName);
+ } catch (ClassNotFoundException e) {
+ log.error(e.getMessage(), e);
+ return null;
+ }
+
+ // once we have the class, we can do some checks on it to ensure
+ // that it is a valid implementation of a plugin.
+ int modifiers = pluginClass.getModifiers();
+ if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)
+ || (!Plugin.class.isAssignableFrom(pluginClass))) {
+ log.error("The plugin class '{}' is not valid", pluginClassName);
+ return null;
+ }
+
+ // create the plugin instance
+ try {
+ Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
+ return (Plugin) constructor.newInstance(new Object[] { pluginWrapper });
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+
+ return null;
+ }
+
+}
*/
private Version systemVersion = Version.ZERO;
+ private PluginFactory pluginFactory;
+ private ExtensionFactory extensionFactory;
+
/**
* The plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins").
*/
throw new IllegalArgumentException(String.format("Specified plugin %s does not exist!", pluginArchiveFile));
}
+ log.debug("Loading plugin from '{}'", pluginArchiveFile);
+
File pluginDirectory = null;
try {
pluginDirectory = expandPluginArchive(pluginArchiveFile);
if (directories == null) {
directories = new File[0];
}
- log.debug("Found possible {} plugins: {}", directories.length, directories);
+ log.debug("Found {} possible plugins: {}", directories.length, directories);
if (directories.length == 0) {
log.info("No plugins");
return;
List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
List<T> extensions = new ArrayList<T>(extensionsWrapper.size());
for (ExtensionWrapper<T> extensionWrapper : extensionsWrapper) {
- extensions.add(extensionWrapper.getInstance());
+ extensions.add(extensionWrapper.getExtension());
}
return extensions;
* Add the possibility to override the ExtensionFinder.
*/
protected ExtensionFinder createExtensionFinder() {
- DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this);
+ DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this, extensionFactory);
addPluginStateListener(extensionFinder);
return extensionFinder;
return new File(pluginsDir);
}
- private void initialize() {
+ /**
+ * Add the possibility to override the PluginFactory..
+ */
+ protected PluginFactory createPluginFactory() {
+ return new DefaultPluginFactory();
+ }
+
+ /**
+ * Add the possibility to override the ExtensionFactory.
+ */
+ protected ExtensionFactory createExtensionFactory() {
+ return new DefaultExtensionFactory();
+ }
+
+ private void initialize() {
plugins = new HashMap<String, PluginWrapper>();
pluginClassLoaders = new HashMap<String, PluginClassLoader>();
pathToIdMap = new HashMap<String, String>();
log.info("PF4J version {} in '{}' mode", getVersion(), getRuntimeMode());
pluginClasspath = createPluginClasspath();
+ pluginFactory = createPluginFactory();
+ extensionFactory = createExtensionFactory();
pluginDescriptorFinder = createPluginDescriptorFinder();
extensionFinder = createExtensionFinder();
// create the plugin wrapper
log.debug("Creating wrapper for plugin '{}'", pluginPath);
PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader());
+ pluginWrapper.setPluginFactory(pluginFactory);
pluginWrapper.setRuntimeMode(getRuntimeMode());
// test for disabled plugin
--- /dev/null
+/*
+ * Copyright 2014 Decebal Suiu
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with
+ * the License. You may obtain a copy of the License in the LICENSE file, or at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package ro.fortsoft.pf4j;
+
+/**
+ * @author Decebal Suiu
+ */
+public class ExtensionDescriptor {
+
+ private int ordinal;
+ private Class<?> extensionClass;
+
+ public Class<?> getExtensionClass() {
+ return extensionClass;
+ }
+
+ public int getOrdinal() {
+ return ordinal;
+ }
+
+ void setExtensionClass(Class<?> extensionClass) {
+ this.extensionClass = extensionClass;
+ }
+
+ void setOrdinal(int ordinal) {
+ this.ordinal = ordinal;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2014 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;
+
+/**
+ * Creates an extension instance.
+ */
+public interface ExtensionFactory {
+
+ public Object create(Class<?> extensionClass);
+
+}
/*
- * Copyright 2012 Decebal Suiu
- *
+ * Copyright 2014 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;
/**
+ * A wrapper over extension instance.
+ *
* @author Decebal Suiu
*/
public class ExtensionWrapper<T> implements Comparable<ExtensionWrapper<T>> {
- private final T instance;
- private final int ordinal;
-
- public ExtensionWrapper(T instance, int ordinal) {
- this.instance = instance;
- this.ordinal = ordinal;
+ ExtensionDescriptor descriptor;
+ ExtensionFactory extensionFactory;
+ T extension; // cache
+
+ public ExtensionWrapper(ExtensionDescriptor descriptor) {
+ this.descriptor = descriptor;
}
- public T getInstance() {
- return instance;
+ public T getExtension() {
+ if (extension == null) {
+ extension = (T) extensionFactory.create(descriptor.getExtensionClass());
+ }
+
+ return extension;
}
- public int getOrdinal() {
- return ordinal;
+ public ExtensionDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public int getOrdinal() {
+ return descriptor.getOrdinal();
}
@Override
public int compareTo(ExtensionWrapper<T> o) {
- return (ordinal - o.getOrdinal());
+ return (getOrdinal() - o.getOrdinal());
}
+ void setExtensionFactory(ExtensionFactory extensionFactory) {
+ this.extensionFactory = extensionFactory;
+ }
+
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2014 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;
+
+/**
+ * Creates a plugin instance.
+ */
+public interface PluginFactory {
+
+ public Plugin create(PluginWrapper pluginWrapper);
+
+}
*/
package ro.fortsoft.pf4j;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-
/**
* A wrapper over plugin instance.
*
PluginDescriptor descriptor;
String pluginPath;
PluginClassLoader pluginClassLoader;
- Plugin plugin;
+ PluginFactory pluginFactory;
PluginState pluginState;
RuntimeMode runtimeMode;
+ Plugin plugin; // cache
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;
}
}
public Plugin getPlugin() {
- return plugin;
+ if (plugin == null) {
+ plugin = pluginFactory.create(this);
+ }
+
+ return plugin;
}
public PluginState getPluginState() {
this.runtimeMode = runtimeMode;
}
- private Plugin createPluginInstance() throws Exception {
- String pluginClassName = descriptor.getPluginClass();
- Class<?> pluginClass = pluginClassLoader.loadClass(pluginClassName);
-
- // once we have the class, we can do some checks on it to ensure
- // that it is a valid implementation of a plugin.
- int modifiers = pluginClass.getModifiers();
- if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)
- || (!Plugin.class.isAssignableFrom(pluginClass))) {
- throw new PluginException("The plugin class '" + pluginClassName + "' is not valid.");
- }
-
- // create the plugin instance
- Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
- Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this });
-
- return plugin;
+ void setPluginFactory(PluginFactory pluginFactory) {
+ this.pluginFactory = pluginFactory;
}
}