Browse Source

Merge pull request #3 from gitblit/stop_plugin

Add support for starting, stopping, and unloading a plugin
pull/4/head
Decebal Suiu 11 years ago
parent
commit
eef2ee1cba
  1. 6
      pf4j/pom.xml
  2. 104
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
  3. 22
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
  4. 4
      pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java

6
pf4j/pom.xml

@ -31,6 +31,12 @@
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>1.6.4</version> <version>1.6.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

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

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -163,6 +164,34 @@ public class DefaultPluginManager implements PluginManager {
} }
} }
/**
* Start the specified plugin and it's dependencies.
*/
@Override
public PluginState startPlugin(String pluginId) {
if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
}
PluginWrapper pluginWrapper = plugins.get(pluginId);
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
if (pluginWrapper.getPluginState().equals(PluginState.STARTED)) {
log.debug("Already started plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
return PluginState.STARTED;
}
for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
startPlugin(dependency.getPluginId());
}
try {
log.info("Start plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
pluginWrapper.getPlugin().start();
pluginWrapper.setPluginState(PluginState.STARTED);
startedPlugins.add(pluginWrapper);
} catch (PluginException e) {
log.error(e.getMessage(), e);
}
return pluginWrapper.getPluginState();
}
/** /**
* Stop all active plugins. * Stop all active plugins.
*/ */
@ -170,17 +199,49 @@ public class DefaultPluginManager implements PluginManager {
public void stopPlugins() { public void stopPlugins() {
// stop started plugins in reverse order // stop started plugins in reverse order
Collections.reverse(startedPlugins); Collections.reverse(startedPlugins);
for (PluginWrapper pluginWrapper : startedPlugins) { Iterator<PluginWrapper> itr = startedPlugins.iterator();
while (itr.hasNext()) {
PluginWrapper pluginWrapper = itr.next();
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
try { try {
log.info("Stop plugin '{}'", pluginWrapper.getDescriptor().getPluginId()); log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
pluginWrapper.getPlugin().stop(); pluginWrapper.getPlugin().stop();
pluginWrapper.setPluginState(PluginState.STOPPED); pluginWrapper.setPluginState(PluginState.STOPPED);
itr.remove();
} catch (PluginException e) { } catch (PluginException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
} }
} }
/**
* Stop the specified plugin and it's dependencies.
*/
@Override
public PluginState stopPlugin(String pluginId) {
if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
}
PluginWrapper pluginWrapper = plugins.get(pluginId);
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
if (pluginWrapper.getPluginState().equals(PluginState.STOPPED)) {
log.debug("Already stopped plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
return PluginState.STOPPED;
}
for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
stopPlugin(dependency.getPluginId());
}
try {
log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
pluginWrapper.getPlugin().stop();
pluginWrapper.setPluginState(PluginState.STOPPED);
startedPlugins.remove(pluginWrapper);
} catch (PluginException e) {
log.error(e.getMessage(), e);
}
return pluginWrapper.getPluginState();
}
/** /**
* Load plugins. * Load plugins.
*/ */
@ -233,6 +294,45 @@ public class DefaultPluginManager implements PluginManager {
} }
} }
@Override
public boolean unloadPlugin(String pluginId) {
try {
PluginState state = stopPlugin(pluginId);
if (!PluginState.STOPPED.equals(state)) {
return false;
}
PluginWrapper pluginWrapper = plugins.get(pluginId);
PluginDescriptor descriptor = pluginWrapper.getDescriptor();
List<PluginDependency> dependencies = descriptor.getDependencies();
for (PluginDependency dependency : dependencies) {
if (!unloadPlugin(dependency.getPluginId())) {
return false;
}
}
// remove the plugin
plugins.remove(pluginId);
resolvedPlugins.remove(pluginWrapper);
pathToIdMap.remove(pluginWrapper.getPluginPath());
// remove the classloader
if (pluginClassLoaders.containsKey(pluginId)) {
PluginClassLoader classLoader = pluginClassLoaders.remove(pluginId);
compoundClassLoader.removeLoader(classLoader);
try {
classLoader.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
return true;
} catch (IllegalArgumentException e) {
// ignore not found exceptions because this method is recursive
}
return false;
}
/** /**
* Get plugin class loader for this path. * Get plugin class loader for this path.
*/ */

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

@ -52,11 +52,33 @@ public interface PluginManager {
*/ */
public void startPlugins(); public void startPlugins();
/**
* Start the specified plugin and it's dependencies.
*
* @return the plugin state
*/
public PluginState startPlugin(String pluginId);
/** /**
* Stop all active plugins. * Stop all active plugins.
*/ */
public void stopPlugins(); public void stopPlugins();
/**
* Stop the specified plugin and it's dependencies.
*
* @return the plugin state
*/
public PluginState stopPlugin(String pluginId);
/**
* Unload a plugin.
*
* @param pluginId
* @return true if the plugin was unloaded
*/
public boolean unloadPlugin(String pluginId);
public PluginClassLoader getPluginClassLoader(String pluginId); public PluginClassLoader getPluginClassLoader(String pluginId);
public <T> List<T> getExtensions(Class<T> type); public <T> List<T> getExtensions(Class<T> type);

4
pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java

@ -34,6 +34,10 @@ public class CompoundClassLoader extends ClassLoader {
loaders.add(loader); loaders.add(loader);
} }
public void removeLoader(ClassLoader loader) {
loaders.remove(loader);
}
@Override @Override
public Class<?> findClass(String name) throws ClassNotFoundException { public Class<?> findClass(String name) throws ClassNotFoundException {
for (ClassLoader loader : loaders) { for (ClassLoader loader : loaders) {

Loading…
Cancel
Save