Browse Source

Add InvalidPluginDescriptorException

Add more javadoc in AbstractPluginManager
pull/565/head
Decebal Suiu 10 months ago
parent
commit
a33c7b084a
  1. 106
      pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
  2. 30
      pf4j/src/main/java/org/pf4j/InvalidPluginDescriptorException.java

106
pf4j/src/main/java/org/pf4j/AbstractPluginManager.java

@ -38,8 +38,8 @@ import java.util.stream.Collectors;
* This class implements the boilerplate plugin code that any {@link PluginManager} * This class implements the boilerplate plugin code that any {@link PluginManager}
* implementation would have to support. * implementation would have to support.
* It helps cut the noise out of the subclass that handles plugin management. * It helps cut the noise out of the subclass that handles plugin management.
* * <p>
* <p>This class is not thread-safe. * This class is not thread-safe.
* *
* @author Decebal Suiu * @author Decebal Suiu
*/ */
@ -160,14 +160,9 @@ public abstract class AbstractPluginManager implements PluginManager {
*/ */
@Override @Override
public List<PluginWrapper> getPlugins(PluginState pluginState) { public List<PluginWrapper> getPlugins(PluginState pluginState) {
List<PluginWrapper> plugins = new ArrayList<>(); return getPlugins().stream()
for (PluginWrapper plugin : getPlugins()) { .filter(plugin -> pluginState.equals(plugin.getPluginState()))
if (pluginState.equals(plugin.getPluginState())) { .collect(Collectors.toList());
plugins.add(plugin);
}
}
return plugins;
} }
@Override @Override
@ -190,6 +185,14 @@ public abstract class AbstractPluginManager implements PluginManager {
return plugins.get(pluginId); return plugins.get(pluginId);
} }
/**
* Load a plugin.
*
* @param pluginPath the plugin location
* @return the pluginId of the loaded plugin as specified in its {@linkplain PluginDescriptor metadata}
* @throws IllegalArgumentException if the plugin location does not exist
* @throws PluginRuntimeException if something goes wrong
*/
@Override @Override
public String loadPlugin(Path pluginPath) { public String loadPlugin(Path pluginPath) {
if ((pluginPath == null) || Files.notExists(pluginPath)) { if ((pluginPath == null) || Files.notExists(pluginPath)) {
@ -212,6 +215,7 @@ public abstract class AbstractPluginManager implements PluginManager {
@Override @Override
public void loadPlugins() { public void loadPlugins() {
log.debug("Lookup plugins in '{}'", pluginsRoots); log.debug("Lookup plugins in '{}'", pluginsRoots);
// check for plugins roots // check for plugins roots
if (pluginsRoots.isEmpty()) { if (pluginsRoots.isEmpty()) {
log.warn("No plugins roots configured"); log.warn("No plugins roots configured");
@ -264,12 +268,22 @@ public abstract class AbstractPluginManager implements PluginManager {
/** /**
* Unload the specified plugin and it's dependents. * Unload the specified plugin and it's dependents.
*
* @param pluginId the pluginId of the plugin to unload
* @return true if the plugin was unloaded, otherwise false
*/ */
@Override @Override
public boolean unloadPlugin(String pluginId) { public boolean unloadPlugin(String pluginId) {
return unloadPlugin(pluginId, true); return unloadPlugin(pluginId, true);
} }
/**
* Unload the specified plugin and it's dependents.
*
* @param pluginId the pluginId of the plugin to unload
* @param unloadDependents if true, unload dependents
* @return true if the plugin was unloaded, otherwise false
*/
protected boolean unloadPlugin(String pluginId, boolean unloadDependents) { protected boolean unloadPlugin(String pluginId, boolean unloadDependents) {
try { try {
if (unloadDependents) { if (unloadDependents) {
@ -347,9 +361,7 @@ public abstract class AbstractPluginManager implements PluginManager {
// notify the plugin as it's deleted // notify the plugin as it's deleted
plugin.delete(); plugin.delete();
Path pluginPath = pluginWrapper.getPluginPath(); return pluginRepository.deletePluginPath(pluginWrapper.getPluginPath());
return pluginRepository.deletePluginPath(pluginPath);
} }
/** /**
@ -405,7 +417,7 @@ public abstract class AbstractPluginManager implements PluginManager {
} }
for (PluginDependency dependency : pluginDescriptor.getDependencies()) { for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
// start dependency only if it marked as required (non optional) or if it optional and loaded // start dependency only if it marked as required (non-optional) or if it optional and loaded
if (!dependency.isOptional() || plugins.containsKey(dependency.getPluginId())) { if (!dependency.isOptional() || plugins.containsKey(dependency.getPluginId())) {
startPlugin(dependency.getPluginId()); startPlugin(dependency.getPluginId());
} }
@ -455,6 +467,13 @@ public abstract class AbstractPluginManager implements PluginManager {
return stopPlugin(pluginId, true); return stopPlugin(pluginId, true);
} }
/**
* Stop the specified plugin and it's dependents.
*
* @param pluginId the pluginId of the plugin to stop
* @param stopDependents if true, stop dependents
* @return the plugin state after stopping
*/
protected PluginState stopPlugin(String pluginId, boolean stopDependents) { protected PluginState stopPlugin(String pluginId, boolean stopDependents) {
checkPluginId(pluginId); checkPluginId(pluginId);
@ -491,6 +510,12 @@ public abstract class AbstractPluginManager implements PluginManager {
return pluginWrapper.getPluginState(); return pluginWrapper.getPluginState();
} }
/**
* Check if the plugin exists in the list of plugins.
*
* @param pluginId the pluginId to check
* @throws IllegalArgumentException if the plugin does not exist
*/
protected void checkPluginId(String pluginId) { protected void checkPluginId(String pluginId) {
if (!plugins.containsKey(pluginId)) { if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId)); throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
@ -741,6 +766,7 @@ public abstract class AbstractPluginManager implements PluginManager {
} }
pluginsDir = isDevelopment() ? DEVELOPMENT_PLUGINS_DIR : DEFAULT_PLUGINS_DIR; pluginsDir = isDevelopment() ? DEVELOPMENT_PLUGINS_DIR : DEFAULT_PLUGINS_DIR;
return Collections.singletonList(Paths.get(pluginsDir)); return Collections.singletonList(Paths.get(pluginsDir));
} }
@ -760,19 +786,30 @@ public abstract class AbstractPluginManager implements PluginManager {
return true; return true;
} }
PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
log.warn("Plugin '{}' requires a minimum system version of {}, and you have {}", log.warn("Plugin '{}' requires a minimum system version of {}, and you have {}",
getPluginLabel(pluginDescriptor), getPluginLabel(pluginWrapper.getDescriptor()),
requires, requires,
getSystemVersion()); getSystemVersion());
return false; return false;
} }
/**
* Check if the plugin is disabled.
*
* @param pluginId the pluginId to check
* @return true if the plugin is disabled, otherwise false
*/
protected boolean isPluginDisabled(String pluginId) { protected boolean isPluginDisabled(String pluginId) {
return pluginStatusProvider.isPluginDisabled(pluginId); return pluginStatusProvider.isPluginDisabled(pluginId);
} }
/**
* It resolves the plugins by checking the dependencies.
* It also checks for cyclic dependencies, missing dependencies and wrong versions of the dependencies.
*
* @throws PluginRuntimeException if something goes wrong
*/
protected void resolvePlugins() { protected void resolvePlugins() {
// retrieves the plugins descriptors // retrieves the plugins descriptors
List<PluginDescriptor> descriptors = new ArrayList<>(); List<PluginDescriptor> descriptors = new ArrayList<>();
@ -815,6 +852,12 @@ public abstract class AbstractPluginManager implements PluginManager {
} }
} }
/**
* Fire a plugin state event.
* This method is called when a plugin is loaded, started, stopped, etc.
*
* @param event the plugin state event
*/
protected synchronized void firePluginStateEvent(PluginStateEvent event) { protected synchronized void firePluginStateEvent(PluginStateEvent event) {
for (PluginStateListener listener : pluginStateListeners) { for (PluginStateListener listener : pluginStateListeners) {
log.trace("Fire '{}' to '{}'", event, listener); log.trace("Fire '{}' to '{}'", event, listener);
@ -822,6 +865,14 @@ public abstract class AbstractPluginManager implements PluginManager {
} }
} }
/**
* Load the plugin from the specified path.
*
* @param pluginPath the path to the plugin
* @return the loaded plugin
* @throws PluginAlreadyLoadedException if the plugin is already loaded
* @throws InvalidPluginDescriptorException if the plugin is invalid
*/
protected PluginWrapper loadPluginFromPath(Path pluginPath) { protected PluginWrapper loadPluginFromPath(Path pluginPath) {
// Test for plugin path duplication // Test for plugin path duplication
String pluginId = idForPath(pluginPath); String pluginId = idForPath(pluginPath);
@ -886,15 +937,21 @@ public abstract class AbstractPluginManager implements PluginManager {
} }
/** /**
* creates the plugin wrapper. override this if you want to prevent plugins having full access to the plugin manager * Creates the plugin wrapper.
* <p>
* Override this if you want to prevent plugins having full access to the plugin manager.
* *
* @return * @param pluginDescriptor the plugin descriptor
* @param pluginPath the path to the plugin
* @param pluginClassLoader the class loader for the plugin
* @return the plugin wrapper
*/ */
protected PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor, Path pluginPath, ClassLoader pluginClassLoader) { protected PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor, Path pluginPath, ClassLoader pluginClassLoader) {
// create the plugin wrapper // create the plugin wrapper
log.debug("Creating wrapper for plugin '{}'", pluginPath); log.debug("Creating wrapper for plugin '{}'", pluginPath);
PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader); PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
pluginWrapper.setPluginFactory(getPluginFactory()); pluginWrapper.setPluginFactory(getPluginFactory());
return pluginWrapper; return pluginWrapper;
} }
@ -918,19 +975,21 @@ public abstract class AbstractPluginManager implements PluginManager {
* Override this to change the validation criteria. * Override this to change the validation criteria.
* *
* @param descriptor the plugin descriptor to validate * @param descriptor the plugin descriptor to validate
* @throws PluginRuntimeException if validation fails * @throws InvalidPluginDescriptorException if validation fails
*/ */
protected void validatePluginDescriptor(PluginDescriptor descriptor) { protected void validatePluginDescriptor(PluginDescriptor descriptor) {
if (StringUtils.isNullOrEmpty(descriptor.getPluginId())) { if (StringUtils.isNullOrEmpty(descriptor.getPluginId())) {
throw new PluginRuntimeException("Field 'id' cannot be empty"); throw new InvalidPluginDescriptorException("Field 'id' cannot be empty");
} }
if (descriptor.getVersion() == null) { if (descriptor.getVersion() == null) {
throw new PluginRuntimeException("Field 'version' cannot be empty"); throw new InvalidPluginDescriptorException("Field 'version' cannot be empty");
} }
} }
/** /**
* Check if the exact version in requires is allowed.
*
* @return true if exact versions in requires is allowed * @return true if exact versions in requires is allowed
*/ */
public boolean isExactVersionAllowed() { public boolean isExactVersionAllowed() {
@ -954,7 +1013,10 @@ public abstract class AbstractPluginManager implements PluginManager {
} }
/** /**
* The plugin label is used in logging and it's a string in format {@code pluginId@pluginVersion}. * The plugin label is used in logging, and it's a string in format {@code pluginId@pluginVersion}.
*
* @param pluginDescriptor the plugin descriptor
* @return the plugin label
*/ */
protected String getPluginLabel(PluginDescriptor pluginDescriptor) { protected String getPluginLabel(PluginDescriptor pluginDescriptor) {
return pluginDescriptor.getPluginId() + "@" + pluginDescriptor.getVersion(); return pluginDescriptor.getPluginId() + "@" + pluginDescriptor.getVersion();

30
pf4j/src/main/java/org/pf4j/InvalidPluginDescriptorException.java

@ -0,0 +1,30 @@
/*
* Copyright (C) 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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 org.pf4j;
/**
* This exception signals incomplete or wrong information in the descriptor for a plugin.
*
* @see PluginDescriptor
* @author Decebal Suiu
*/
public class InvalidPluginDescriptorException extends PluginRuntimeException {
public InvalidPluginDescriptorException(String message) {
super(message);
}
}
Loading…
Cancel
Save