Browse Source

try to resolve issue #20

pull/22/head
Decebal Suiu 11 years ago
parent
commit
808a36a3ae
  1. 45
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFactory.java
  2. 65
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
  3. 69
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginFactory.java
  4. 30
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
  5. 39
      pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionDescriptor.java
  6. 22
      pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFactory.java
  7. 44
      pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java
  8. 22
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginFactory.java
  9. 38
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java

45
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFactory.java

@ -0,0 +1,45 @@
/*
* 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;
}
}

65
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java

@ -36,9 +36,9 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
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
@ -68,23 +68,26 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
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);
@ -117,31 +120,6 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
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) {
@ -219,13 +197,4 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
return ExtensionPoint.class.isAssignableFrom(type);
}
/**
* Creates an extension instance.
*/
public static interface ExtensionFactory {
public Object create(Class<?> extensionType);
}
}

69
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginFactory.java

@ -0,0 +1,69 @@
/*
* 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;
}
}

30
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java

@ -94,6 +94,9 @@ public class DefaultPluginManager implements PluginManager {
*/
private Version systemVersion = Version.ZERO;
private PluginFactory pluginFactory;
private ExtensionFactory extensionFactory;
/**
* The plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins").
*/
@ -168,6 +171,8 @@ public class DefaultPluginManager implements PluginManager {
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);
@ -361,7 +366,7 @@ public class DefaultPluginManager implements PluginManager {
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;
@ -554,7 +559,7 @@ public class DefaultPluginManager implements PluginManager {
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;
@ -633,7 +638,7 @@ public class DefaultPluginManager implements PluginManager {
* 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;
@ -702,7 +707,21 @@ public class DefaultPluginManager implements PluginManager {
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>();
@ -716,6 +735,8 @@ public class DefaultPluginManager implements PluginManager {
log.info("PF4J version {} in '{}' mode", getVersion(), getRuntimeMode());
pluginClasspath = createPluginClasspath();
pluginFactory = createPluginFactory();
extensionFactory = createExtensionFactory();
pluginDescriptorFinder = createPluginDescriptorFinder();
extensionFinder = createExtensionFinder();
@ -760,6 +781,7 @@ public class DefaultPluginManager implements PluginManager {
// 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

39
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionDescriptor.java

@ -0,0 +1,39 @@
/*
* 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;
}
}

22
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFactory.java

@ -0,0 +1,22 @@
/*
* 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);
}

44
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java

@ -1,11 +1,11 @@
/*
* 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.
@ -13,29 +13,43 @@
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;
}
}

22
pf4j/src/main/java/ro/fortsoft/pf4j/PluginFactory.java

@ -0,0 +1,22 @@
/*
* 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);
}

38
pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java

@ -12,9 +12,6 @@
*/
package ro.fortsoft.pf4j;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
/**
* A wrapper over plugin instance.
*
@ -25,22 +22,16 @@ public class PluginWrapper {
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;
}
@ -68,7 +59,11 @@ public class PluginWrapper {
}
public Plugin getPlugin() {
return plugin;
if (plugin == null) {
plugin = pluginFactory.create(this);
}
return plugin;
}
public PluginState getPluginState() {
@ -130,23 +125,8 @@ public class PluginWrapper {
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;
}
}

Loading…
Cancel
Save