diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java index c44787e..286b6ea 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java @@ -89,6 +89,11 @@ public class DefaultPluginManager implements PluginManager { */ private RuntimeMode runtimeMode; + /** + * The system version used for comparisons to the plugin requires attribute. + */ + private PluginVersion systemVersion = PluginVersion.ZERO; + /** * The plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins"). */ @@ -110,6 +115,16 @@ public class DefaultPluginManager implements PluginManager { initialize(); } + @Override + public void setSystemVersion(PluginVersion version) { + systemVersion = version; + } + + @Override + public PluginVersion getSystemVersion() { + return systemVersion; + } + @Override public List getPlugins() { return new ArrayList(plugins.values()); @@ -454,10 +469,17 @@ public class DefaultPluginManager implements PluginManager { } PluginWrapper pluginWrapper = getPlugin(pluginId); + if (!isPluginValid(pluginWrapper)) { + log.warn("Plugin '{}:{}' can not be enabled", + pluginWrapper.getPluginId(), + pluginWrapper.getDescriptor().getVersion()); + return false; + } + PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); PluginState pluginState = pluginWrapper.getPluginState(); if (PluginState.DISABLED != pluginState) { - log.debug("Plugin plugin '{}:{}' is not disabled", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); + log.debug("Plugin '{}:{}' is not disabled", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); return true; } @@ -634,6 +656,20 @@ public class DefaultPluginManager implements PluginManager { return !enabledPlugins.contains(pluginId); } + protected boolean isPluginValid(PluginWrapper pluginWrapper) { + PluginVersion requires = pluginWrapper.getDescriptor().getRequires(); + PluginVersion system = getSystemVersion(); + if (system.isZero() || system.atLeast(requires)) { + return true; + } + + log.warn(String.format("Plugin '%s:%s' requires a minimum system version of %s", + pluginWrapper.getPluginId(), + pluginWrapper.getDescriptor().getVersion(), + requires)); + return false; + } + protected FileFilter createHiddenPluginFilter() { return new HiddenFilter(); } @@ -724,6 +760,12 @@ public class DefaultPluginManager implements PluginManager { pluginWrapper.setPluginState(PluginState.DISABLED); } + // validate the plugin + if (!isPluginValid(pluginWrapper)) { + log.info("Plugin '{}' is disabled", pluginPath); + pluginWrapper.setPluginState(PluginState.DISABLED); + } + log.debug("Created wrapper '{}' for plugin '{}'", pluginWrapper, pluginPath); String pluginId = pluginDescriptor.getPluginId(); diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java index 2de42f5..7f802d1 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ManifestPluginDescriptorFinder.java @@ -103,6 +103,11 @@ public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder { String dependencies = attrs.getValue("Plugin-Dependencies"); pluginDescriptor.setDependencies(dependencies); + String requires = attrs.getValue("Plugin-Requires"); + if (StringUtils.isNotEmpty(requires)) { + pluginDescriptor.setRequires(PluginVersion.createVersion(requires)); + } + return pluginDescriptor; } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java index cb91f7d..ae07fbb 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java @@ -28,10 +28,12 @@ public class PluginDescriptor { private String pluginDescription; private String pluginClass; private PluginVersion version; + private PluginVersion requires; private String provider; private List dependencies; public PluginDescriptor() { + requires = PluginVersion.ZERO; dependencies = new ArrayList(); } @@ -63,6 +65,13 @@ public class PluginDescriptor { return version; } + /** + * Returns the requires of this plugin. + */ + public PluginVersion getRequires() { + return requires; + } + /** * Returns the provider name of this plugin. */ @@ -106,6 +115,10 @@ public class PluginDescriptor { this.provider = provider; } + void setRequires(PluginVersion requires) { + this.requires = requires; + } + void setDependencies(String dependencies) { if (dependencies != null) { dependencies = dependencies.trim(); diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java index daf6fbf..81abe7c 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java @@ -141,4 +141,20 @@ public interface PluginManager { public void removePluginStateListener(PluginStateListener listener); + /** + * Set the system version. This is used to compare against the plugin + * requires attribute. The default system version is 0.0.0 which + * disables all version checking. + * + * @default 0.0.0 + * @param version + */ + public void setSystemVersion(PluginVersion version); + + /** + * Returns the system version. + * + * * @return the system version + */ + public PluginVersion getSystemVersion(); } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginVersion.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginVersion.java index 6ffd284..c5d57fd 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginVersion.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginVersion.java @@ -1,22 +1,22 @@ /* * 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; -import ro.fortsoft.pf4j.util.StringUtils; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import ro.fortsoft.pf4j.util.StringUtils; + /** * Represents the version of a Plugin and allows versions to be compared. * Version following semantic defined by Semantic Versioning document. @@ -33,6 +33,8 @@ import java.util.regex.Pattern; */ public class PluginVersion implements Comparable { + public static final PluginVersion ZERO = new PluginVersion(0, 0, 0); + private static final String FORMAT = "(\\d+)\\.(\\d+)(?:\\.)?(\\d*)(\\.|-|\\+)?([0-9A-Za-z-.]*)?"; private static final Pattern PATTERN = Pattern.compile(FORMAT); @@ -95,6 +97,7 @@ public class PluginVersion implements Comparable { return qualifier; } + @Override public String toString() { StringBuffer sb = new StringBuffer(50); sb.append(major); @@ -135,6 +138,18 @@ public class PluginVersion implements Comparable { return 0; } + public boolean isZero() { + return compareTo(ZERO) == 0; + } + + public boolean atLeast(PluginVersion v) { + return compareTo(v) <= 0; + } + + public boolean exceeds(PluginVersion v) { + return compareTo(v) > 0; + } + // for test only public static void main(String[] args) { PluginVersion v = PluginVersion.createVersion("1.2.3-SNAPSHOT");