* This class implements the boilerplate plugin code that any {@link PluginManager}
* implementation would have to support.
* It helps cut the noise out of the subclass that handles plugin management.
- *
- * <p>This class is not thread-safe.
+ * <p>
+ * This class is not thread-safe.
*
* @author Decebal Suiu
*/
*/
@Override
public List<PluginWrapper> getPlugins(PluginState pluginState) {
- List<PluginWrapper> plugins = new ArrayList<>();
- for (PluginWrapper plugin : getPlugins()) {
- if (pluginState.equals(plugin.getPluginState())) {
- plugins.add(plugin);
- }
- }
-
- return plugins;
+ return getPlugins().stream()
+ .filter(plugin -> pluginState.equals(plugin.getPluginState()))
+ .collect(Collectors.toList());
}
@Override
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
public String loadPlugin(Path pluginPath) {
if ((pluginPath == null) || Files.notExists(pluginPath)) {
@Override
public void loadPlugins() {
log.debug("Lookup plugins in '{}'", pluginsRoots);
+
// check for plugins roots
if (pluginsRoots.isEmpty()) {
log.warn("No plugins roots configured");
/**
* 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
public boolean unloadPlugin(String pluginId) {
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) {
try {
if (unloadDependents) {
// notify the plugin as it's deleted
plugin.delete();
- Path pluginPath = pluginWrapper.getPluginPath();
-
- return pluginRepository.deletePluginPath(pluginPath);
+ return pluginRepository.deletePluginPath(pluginWrapper.getPluginPath());
}
/**
}
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())) {
startPlugin(dependency.getPluginId());
}
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) {
checkPluginId(pluginId);
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) {
if (!plugins.containsKey(pluginId)) {
throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
}
pluginsDir = isDevelopment() ? DEVELOPMENT_PLUGINS_DIR : DEFAULT_PLUGINS_DIR;
+
return Collections.singletonList(Paths.get(pluginsDir));
}
return true;
}
- PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
log.warn("Plugin '{}' requires a minimum system version of {}, and you have {}",
- getPluginLabel(pluginDescriptor),
+ getPluginLabel(pluginWrapper.getDescriptor()),
requires,
getSystemVersion());
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) {
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() {
// retrieves the plugins descriptors
List<PluginDescriptor> descriptors = new ArrayList<>();
}
}
+ /**
+ * 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) {
for (PluginStateListener listener : pluginStateListeners) {
log.trace("Fire '{}' to '{}'", event, listener);
}
}
+ /**
+ * 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) {
// Test for plugin path duplication
String pluginId = idForPath(pluginPath);
}
/**
- * 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) {
// create the plugin wrapper
log.debug("Creating wrapper for plugin '{}'", pluginPath);
PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
pluginWrapper.setPluginFactory(getPluginFactory());
+
return pluginWrapper;
}
* Override this to change the validation criteria.
*
* @param descriptor the plugin descriptor to validate
- * @throws PluginRuntimeException if validation fails
+ * @throws InvalidPluginDescriptorException if validation fails
*/
protected void validatePluginDescriptor(PluginDescriptor descriptor) {
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) {
- 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
*/
public boolean isExactVersionAllowed() {
}
/**
- * 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) {
return pluginDescriptor.getPluginId() + "@" + pluginDescriptor.getVersion();