Browse Source

added PluginState

pull/3/head
Decebal Suiu 12 years ago
parent
commit
82319fe101
  1. 3
      README.md
  2. 47
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
  3. 16
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java
  4. 38
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java
  5. 48
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java
  6. 2
      pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java

3
README.md

@ -6,6 +6,7 @@ declared by application or other plugins. Also a plugin can define extension poi
Components
-------------------
- **Plugin** is the base class for all plugins types. Each plugin is loaded into a separate class loader to avoid conflicts.
- **PluginManager** is used for all aspects of plugins management (loading, starting, stopping).
- **ExtensionPoint** is a point in the application where custom code can be invoked. It's a java interface marker.
@ -14,6 +15,7 @@ Any java interface or abstract class can be marked as an extension point (implem
Artifacts
-------------------
- PF4J `pf4j` (jar)
- PF4J Demo `pf4j-demo` (executable jar)
@ -34,6 +36,7 @@ where ${pf4j.version} is the last pf4j version.
How to use
-------------------
It's very simple to add pf4j in your application:
public static void main(String[] args) {

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

@ -24,8 +24,8 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ro.fortsoft.pf4j.util.CompoundClassLoader;
import ro.fortsoft.pf4j.util.DirectoryFilter;
import ro.fortsoft.pf4j.util.UberClassLoader;
import ro.fortsoft.pf4j.util.Unzip;
import ro.fortsoft.pf4j.util.ZipFilter;
@ -82,8 +82,11 @@ public class DefaultPluginManager implements PluginManager {
*/
private List<PluginWrapper> startedPlugins;
private UberClassLoader uberClassLoader;
/**
* A compound class loader of resolved plugins.
*/
private CompoundClassLoader compoundClassLoader;
/**
* Th plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins").
*/
@ -108,16 +111,18 @@ public class DefaultPluginManager implements PluginManager {
disabledPlugins = new ArrayList<PluginWrapper>();
startedPlugins = new ArrayList<PluginWrapper>();
pluginDescriptorFinder = new DefaultPluginDescriptorFinder();
uberClassLoader = new UberClassLoader();
extensionFinder = new DefaultExtensionFinder(uberClassLoader);
compoundClassLoader = new CompoundClassLoader();
extensionFinder = new DefaultExtensionFinder(compoundClassLoader);
System.setProperty("pf4j.pluginsDir", pluginsDirectory.getAbsolutePath());
}
@Override
public List<PluginWrapper> getPlugins() {
return new ArrayList<PluginWrapper>(plugins.values());
}
@Override
public List<PluginWrapper> getResolvedPlugins() {
return resolvedPlugins;
}
@ -126,6 +131,7 @@ public class DefaultPluginManager implements PluginManager {
return plugins.get(pluginId);
}
@Override
public List<PluginWrapper> getUnresolvedPlugins() {
return unresolvedPlugins;
}
@ -134,6 +140,7 @@ public class DefaultPluginManager implements PluginManager {
return disabledPlugins;
}
@Override
public List<PluginWrapper> getStartedPlugins() {
return startedPlugins;
}
@ -141,11 +148,13 @@ public class DefaultPluginManager implements PluginManager {
/**
* Start all active plugins.
*/
@Override
public void startPlugins() {
for (PluginWrapper pluginWrapper : resolvedPlugins) {
try {
LOG.info("Start plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
pluginWrapper.getPlugin().start();
pluginWrapper.setPluginState(PluginState.STARTED);
startedPlugins.add(pluginWrapper);
} catch (PluginException e) {
LOG.error(e.getMessage(), e);
@ -156,6 +165,7 @@ public class DefaultPluginManager implements PluginManager {
/**
* Stop all active plugins.
*/
@Override
public void stopPlugins() {
// stop started plugins in reverse order
Collections.reverse(startedPlugins);
@ -163,6 +173,7 @@ public class DefaultPluginManager implements PluginManager {
try {
LOG.info("Stop plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
pluginWrapper.getPlugin().stop();
pluginWrapper.setPluginState(PluginState.STOPPED);
} catch (PluginException e) {
LOG.error(e.getMessage(), e);
}
@ -172,6 +183,7 @@ public class DefaultPluginManager implements PluginManager {
/**
* Load plugins.
*/
@Override
public void loadPlugins() {
// check for plugins directory
if (!pluginsDirectory.exists() || !pluginsDirectory.isDirectory()) {
@ -218,10 +230,12 @@ public class DefaultPluginManager implements PluginManager {
/**
* Get plugin class loader for this path.
*/
@Override
public PluginClassLoader getPluginClassLoader(String pluginId) {
return pluginClassLoaders.get(pluginId);
}
@Override
public <T> List<T> getExtensions(Class<T> type) {
List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
List<T> extensions = new ArrayList<T>(extensionsWrapper.size());
@ -232,13 +246,27 @@ public class DefaultPluginManager implements PluginManager {
return extensions;
}
/**
* Retrieves the {@link PluginWrapper} that loaded the given class 'clazz'.
*/
public PluginWrapper whichPlugin(Class<?> clazz) {
ClassLoader classLoader = clazz.getClassLoader();
for (PluginWrapper plugin : resolvedPlugins) {
if (plugin.getPluginClassLoader() == classLoader) {
return plugin;
}
}
return null;
}
private void loadPlugin(String fileName) throws PluginException {
// test for plugin directory
File pluginDirectory = new File(pluginsDirectory, fileName);
if (!pluginDirectory.isDirectory()) {
return;
}
// try to load the plugin
String pluginPath = "/".concat(fileName);
@ -247,7 +275,7 @@ public class DefaultPluginManager implements PluginManager {
return;
}
// it's a new plugin
// test for plugin duplication
if (plugins.get(pathToIdMap.get(pluginPath)) != null) {
return;
}
@ -278,7 +306,6 @@ public class DefaultPluginManager implements PluginManager {
// add plugin class loader to the list with class loaders
PluginClassLoader pluginClassLoader = pluginLoader.getPluginClassLoader();
pluginDescriptor.setPluginClassLoader(pluginClassLoader);
pluginClassLoaders.put(pluginId, pluginClassLoader);
}
@ -288,7 +315,7 @@ public class DefaultPluginManager implements PluginManager {
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()) {
if (!pluginDirectory.exists() || (pluginArchiveDate > pluginDirectory.lastModified())) {
LOG.debug("Expand plugin archive '" + pluginArchiveFile + "' in '" + pluginDirectory + "'");
// create directorie for plugin
pluginDirectory.mkdirs();
@ -310,7 +337,7 @@ public class DefaultPluginManager implements PluginManager {
resolvedPlugins = dependencyResolver.getSortedPlugins();
for (PluginWrapper pluginWrapper : resolvedPlugins) {
unresolvedPlugins.remove(pluginWrapper);
uberClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
LOG.info("Plugin '" + pluginWrapper.getDescriptor().getPluginId() + "' resolved");
}
}

16
pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java

@ -29,7 +29,6 @@ public class PluginDescriptor {
private PluginVersion version;
private String provider;
private List<PluginDependency> dependencies;
private PluginClassLoader pluginClassLoader;
public PluginDescriptor() {
dependencies = new ArrayList<PluginDependency>();
@ -71,21 +70,12 @@ public class PluginDescriptor {
return dependencies;
}
/**
* Returns the plugin class loader used to load classes and resources
* for this plug-in. The class loader can be used to directly access
* plug-in resources and classes.
*/
public PluginClassLoader getPluginClassLoader() {
return pluginClassLoader;
}
@Override
public String toString() {
return "PluginDescriptor [pluginId=" + pluginId + ", pluginClass="
+ pluginClass + ", version=" + version + ", provider="
+ provider + ", dependencies=" + dependencies
+ ", pluginClassLoader=" + pluginClassLoader + "]";
+ "]";
}
void setPluginId(String pluginId) {
@ -127,8 +117,4 @@ public class PluginDescriptor {
}
}
void setPluginClassLoader(PluginClassLoader pluginClassLoader) {
this.pluginClassLoader = pluginClassLoader;
}
}

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

@ -0,0 +1,38 @@
/*
* 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;
/**
* @author Decebal Suiu
*/
public class PluginState {
public static final PluginState CREATED = new PluginState("CREATED");
public static final PluginState INITIALIZED = new PluginState("INITIALIZED");
public static final PluginState STARTED = new PluginState("STARTED");
public static final PluginState STOPPED = new PluginState("STOPPED");
public static final PluginState DESTROYED = new PluginState("DESTROYED");
public static final PluginState FAILED = new PluginState("FAILED");
private String status;
private PluginState(String status) {
this.status = status;
}
@Override
public String toString() {
return status;
}
}

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

@ -26,6 +26,7 @@ public class PluginWrapper {
String pluginPath;
PluginClassLoader pluginClassLoader;
Plugin plugin;
PluginState pluginState;
public PluginWrapper(PluginDescriptor descriptor, String pluginPath, PluginClassLoader pluginClassLoader) {
this.descriptor = descriptor;
@ -38,6 +39,8 @@ public class PluginWrapper {
} catch (Exception e) {
e.printStackTrace();
}
pluginState = PluginState.CREATED;
}
/**
@ -67,25 +70,9 @@ public class PluginWrapper {
return plugin;
}
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 compatible.");
}
// create the plugin instance
Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this });
return plugin;
}
public PluginState getPluginState() {
return pluginState;
}
@Override
public int hashCode() {
@ -124,4 +111,27 @@ public class PluginWrapper {
+ pluginPath + "]";
}
void setPluginState(PluginState pluginState) {
this.pluginState = pluginState;
}
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 compatible.");
}
// create the plugin instance
Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this });
return plugin;
}
}

2
pf4j/src/main/java/ro/fortsoft/pf4j/util/UberClassLoader.java → pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java

@ -26,7 +26,7 @@ import java.util.Set;
*
* @author Decebal Suiu
*/
public class UberClassLoader extends ClassLoader {
public class CompoundClassLoader extends ClassLoader {
private Set<ClassLoader> loaders = new HashSet<ClassLoader>();
Loading…
Cancel
Save