|
|
|
@ -12,27 +12,14 @@
|
|
|
|
|
*/ |
|
|
|
|
package ro.fortsoft.pf4j; |
|
|
|
|
|
|
|
|
|
import java.io.File; |
|
|
|
|
import java.io.FileFilter; |
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.Collections; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.Iterator; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
import org.slf4j.Logger; |
|
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
|
import ro.fortsoft.pf4j.util.*; |
|
|
|
|
|
|
|
|
|
import ro.fortsoft.pf4j.util.AndFileFilter; |
|
|
|
|
import ro.fortsoft.pf4j.util.CompoundClassLoader; |
|
|
|
|
import ro.fortsoft.pf4j.util.DirectoryFileFilter; |
|
|
|
|
import ro.fortsoft.pf4j.util.FileUtils; |
|
|
|
|
import ro.fortsoft.pf4j.util.HiddenFilter; |
|
|
|
|
import ro.fortsoft.pf4j.util.NotFileFilter; |
|
|
|
|
import ro.fortsoft.pf4j.util.Unzip; |
|
|
|
|
import ro.fortsoft.pf4j.util.ZipFileFilter; |
|
|
|
|
import java.io.File; |
|
|
|
|
import java.io.FileFilter; |
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Default implementation of the PluginManager interface. |
|
|
|
@ -90,11 +77,6 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
private List<String> enabledPlugins; |
|
|
|
|
private List<String> disabledPlugins; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A compound class loader of resolved plugins. |
|
|
|
|
*/ |
|
|
|
|
protected CompoundClassLoader compoundClassLoader; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Cache value for the runtime mode. No need to re-read it because it wont change at |
|
|
|
|
* runtime. |
|
|
|
@ -127,15 +109,23 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
return new ArrayList<PluginWrapper>(plugins.values()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public List<PluginWrapper> getPlugins(PluginState pluginState) { |
|
|
|
|
List<PluginWrapper> plugins= new ArrayList<PluginWrapper>(); |
|
|
|
|
for (PluginWrapper plugin : getPlugins()) { |
|
|
|
|
if (pluginState.equals(plugin.getPluginState())) { |
|
|
|
|
plugins.add(plugin); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return plugins; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public List<PluginWrapper> getResolvedPlugins() { |
|
|
|
|
return resolvedPlugins; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public PluginWrapper getPlugin(String pluginId) { |
|
|
|
|
return plugins.get(pluginId); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public List<PluginWrapper> getUnresolvedPlugins() { |
|
|
|
|
return unresolvedPlugins; |
|
|
|
@ -146,6 +136,11 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
return startedPlugins; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public PluginWrapper getPlugin(String pluginId) { |
|
|
|
|
return plugins.get(pluginId); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public String loadPlugin(File pluginArchiveFile) { |
|
|
|
|
if (pluginArchiveFile == null || !pluginArchiveFile.exists()) { |
|
|
|
@ -167,12 +162,12 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
// TODO uninstalled plugin dependencies?
|
|
|
|
|
unresolvedPlugins.remove(pluginWrapper); |
|
|
|
|
resolvedPlugins.add(pluginWrapper); |
|
|
|
|
compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader()); |
|
|
|
|
extensionFinder.reset(); |
|
|
|
|
return pluginWrapper.getDescriptor().getPluginId(); |
|
|
|
|
} catch (PluginException e) { |
|
|
|
|
log.error(e.getMessage(), e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -182,14 +177,18 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
@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); |
|
|
|
|
} |
|
|
|
|
PluginState pluginState = pluginWrapper.getPluginState(); |
|
|
|
|
if ((PluginState.DISABLED != pluginState) && (PluginState.STARTED != pluginState)) { |
|
|
|
|
try { |
|
|
|
|
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -201,15 +200,25 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
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)) { |
|
|
|
|
if (PluginState.STARTED == pluginWrapper.getPluginState()) { |
|
|
|
|
log.debug("Already started plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
return PluginState.STARTED; |
|
|
|
|
} |
|
|
|
|
for (PluginDependency dependency : pluginDescriptor.getDependencies()) { |
|
|
|
|
|
|
|
|
|
if (PluginState.DISABLED == pluginWrapper.getPluginState()) { |
|
|
|
|
// automatically enable plugin on manual plugin start
|
|
|
|
|
if (!enablePlugin(pluginId)) { |
|
|
|
|
return pluginWrapper.getPluginState(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (PluginDependency dependency : pluginDescriptor.getDependencies()) { |
|
|
|
|
startPlugin(dependency.getPluginId()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
log.info("Start plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
pluginWrapper.getPlugin().start(); |
|
|
|
@ -218,6 +227,7 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
} catch (PluginException e) { |
|
|
|
|
log.error(e.getMessage(), e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return pluginWrapper.getPluginState(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -231,15 +241,17 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
Iterator<PluginWrapper> itr = startedPlugins.iterator(); |
|
|
|
|
while (itr.hasNext()) { |
|
|
|
|
PluginWrapper pluginWrapper = itr.next(); |
|
|
|
|
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); |
|
|
|
|
try { |
|
|
|
|
log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
pluginWrapper.getPlugin().stop(); |
|
|
|
|
pluginWrapper.setPluginState(PluginState.STOPPED); |
|
|
|
|
itr.remove(); |
|
|
|
|
} catch (PluginException e) { |
|
|
|
|
log.error(e.getMessage(), e); |
|
|
|
|
} |
|
|
|
|
if (PluginState.STARTED == pluginWrapper.getPluginState()) { |
|
|
|
|
try { |
|
|
|
|
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); |
|
|
|
|
log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
pluginWrapper.getPlugin().stop(); |
|
|
|
|
pluginWrapper.setPluginState(PluginState.STOPPED); |
|
|
|
|
itr.remove(); |
|
|
|
|
} catch (PluginException e) { |
|
|
|
|
log.error(e.getMessage(), e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -251,15 +263,24 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
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)) { |
|
|
|
|
if (PluginState.STOPPED == pluginWrapper.getPluginState()) { |
|
|
|
|
log.debug("Already stopped plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
return PluginState.STOPPED; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// test for disabled plugin
|
|
|
|
|
if (PluginState.DISABLED == pluginWrapper.getPluginState()) { |
|
|
|
|
// do nothing
|
|
|
|
|
return pluginWrapper.getPluginState(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (PluginDependency dependency : pluginDescriptor.getDependencies()) { |
|
|
|
|
stopPlugin(dependency.getPluginId()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
pluginWrapper.getPlugin().stop(); |
|
|
|
@ -268,6 +289,7 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
} catch (PluginException e) { |
|
|
|
|
log.error(e.getMessage(), e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return pluginWrapper.getPluginState(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -332,7 +354,7 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
public boolean unloadPlugin(String pluginId) { |
|
|
|
|
try { |
|
|
|
|
PluginState state = stopPlugin(pluginId); |
|
|
|
|
if (!PluginState.STOPPED.equals(state)) { |
|
|
|
|
if (PluginState.STOPPED != state) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -354,20 +376,87 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
// 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public boolean disablePlugin(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 (PluginState.DISABLED == getPlugin(pluginId).getPluginState()) { |
|
|
|
|
log.debug("Already disabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (PluginState.STOPPED == stopPlugin(pluginId)) { |
|
|
|
|
getPlugin(pluginId).setPluginState(PluginState.DISABLED); |
|
|
|
|
extensionFinder.reset(); |
|
|
|
|
|
|
|
|
|
if (disabledPlugins.add(pluginId)) { |
|
|
|
|
try { |
|
|
|
|
FileUtils.writeLines(disabledPlugins, new File(pluginsDirectory, "disabled.txt")); |
|
|
|
|
} catch (IOException e) { |
|
|
|
|
log.error("Failed to disable plugin {}", pluginId, e); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
log.info("Disabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public boolean enablePlugin(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 (PluginState.DISABLED != getPlugin(pluginId).getPluginState()) { |
|
|
|
|
log.debug("Plugin plugin '{}:{}' is not disabled", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
if (disabledPlugins.remove(pluginId)) { |
|
|
|
|
FileUtils.writeLines(disabledPlugins, new File(pluginsDirectory, "disabled.txt")); |
|
|
|
|
} |
|
|
|
|
} catch (IOException e) { |
|
|
|
|
log.error("Failed to enable plugin {}", pluginId, e); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getPlugin(pluginId).setPluginState(PluginState.CREATED); |
|
|
|
|
extensionFinder.reset(); |
|
|
|
|
|
|
|
|
|
log.info("Enabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public boolean deletePlugin(String pluginId) { |
|
|
|
|
if (!plugins.containsKey(pluginId)) { |
|
|
|
@ -432,6 +521,11 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
return extensions; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Set<String> getExtensionClassNames(String pluginId) { |
|
|
|
|
return extensionFinder.findClassNames(pluginId); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public RuntimeMode getRuntimeMode() { |
|
|
|
|
if (runtimeMode == null) { |
|
|
|
@ -478,7 +572,7 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
* Add the possibility to override the ExtensionFinder. |
|
|
|
|
*/ |
|
|
|
|
protected ExtensionFinder createExtensionFinder() { |
|
|
|
|
return new DefaultExtensionFinder(compoundClassLoader); |
|
|
|
|
return new DefaultExtensionFinder(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -537,7 +631,6 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
resolvedPlugins = new ArrayList<PluginWrapper>(); |
|
|
|
|
startedPlugins = new ArrayList<PluginWrapper>(); |
|
|
|
|
disabledPlugins = new ArrayList<String>(); |
|
|
|
|
compoundClassLoader = new CompoundClassLoader(); |
|
|
|
|
|
|
|
|
|
pluginClasspath = createPluginClasspath(); |
|
|
|
|
pluginDescriptorFinder = createPluginDescriptorFinder(); |
|
|
|
@ -575,12 +668,6 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
String pluginClassName = pluginDescriptor.getPluginClass(); |
|
|
|
|
log.debug("Class '{}' for plugin '{}'", pluginClassName, pluginPath); |
|
|
|
|
|
|
|
|
|
// test for disabled plugin
|
|
|
|
|
if (isPluginDisabled(pluginDescriptor.getPluginId())) { |
|
|
|
|
log.info("Plugin '{}' is disabled", pluginPath); |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// load plugin
|
|
|
|
|
log.debug("Loading plugin '{}'", pluginPath); |
|
|
|
|
PluginLoader pluginLoader = new PluginLoader(this, pluginDescriptor, pluginDirectory, pluginClasspath); |
|
|
|
@ -591,6 +678,13 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
log.debug("Creating wrapper for plugin '{}'", pluginPath); |
|
|
|
|
PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader()); |
|
|
|
|
pluginWrapper.setRuntimeMode(getRuntimeMode()); |
|
|
|
|
|
|
|
|
|
// test for disabled plugin
|
|
|
|
|
if (isPluginDisabled(pluginDescriptor.getPluginId())) { |
|
|
|
|
log.info("Plugin '{}' is disabled", pluginPath); |
|
|
|
|
pluginWrapper.setPluginState(PluginState.DISABLED); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log.debug("Created wrapper '{}' for plugin '{}'", pluginWrapper, pluginPath); |
|
|
|
|
|
|
|
|
|
String pluginId = pluginDescriptor.getPluginId(); |
|
|
|
@ -641,7 +735,6 @@ public class DefaultPluginManager implements PluginManager {
|
|
|
|
|
resolvedPlugins = dependencyResolver.getSortedPlugins(); |
|
|
|
|
for (PluginWrapper pluginWrapper : resolvedPlugins) { |
|
|
|
|
unresolvedPlugins.remove(pluginWrapper); |
|
|
|
|
compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader()); |
|
|
|
|
log.info("Plugin '{}' resolved", pluginWrapper.getDescriptor().getPluginId()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|