From 5b192003f42c99b85131387017292955278eb0a8 Mon Sep 17 00:00:00 2001 From: Josiah Haswell Date: Wed, 1 Nov 2017 13:16:01 -0600 Subject: [PATCH] Refactoring to make PluginDescriptor more usable (#180) --- .../org/pf4j/DefaultPluginDescriptor.java | 211 ++++++++++++++++++ .../pf4j/ManifestPluginDescriptorFinder.java | 6 +- .../main/java/org/pf4j/PluginDescriptor.java | 154 +------------ .../PropertiesPluginDescriptorFinder.java | 6 +- .../org/pf4j/DefaultPluginManagerTest.java | 4 +- .../java/org/pf4j/DependencyResolverTest.java | 20 +- .../ServiceProviderExtensionStorageTest.java | 82 +++++++ 7 files changed, 321 insertions(+), 162 deletions(-) create mode 100644 pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java create mode 100644 pf4j/src/test/java/org/pf4j/processor/ServiceProviderExtensionStorageTest.java diff --git a/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java b/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java new file mode 100644 index 0000000..5fa2935 --- /dev/null +++ b/pf4j/src/main/java/org/pf4j/DefaultPluginDescriptor.java @@ -0,0 +1,211 @@ +/* + * Copyright 2012 Decebal Suiu + * + * 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; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A plugin descriptor contains information about a plug-in obtained + * from the manifest (META-INF) file. + * + * @author Decebal Suiu + */ +public class DefaultPluginDescriptor implements PluginDescriptor { + + private String pluginId; + private String pluginDescription; + private String pluginClass; + private String version; + private String requires = "*"; // SemVer format + private String provider; + private List dependencies; + private String license; + + public DefaultPluginDescriptor() { + dependencies = new ArrayList<>(); + } + + /** + * @param pluginId + * @param pluginDescription + * @param pluginClass + * @param version + * @param requires + * @param provider + * @param license + */ + public DefaultPluginDescriptor(String pluginId, String pluginDescription, String pluginClass, String version, String requires, String provider, String license) { + this(); + this.pluginId = pluginId; + this.pluginDescription = pluginDescription; + this.pluginClass = pluginClass; + this.version = version; + this.requires = requires; + this.provider = provider; + this.license = license; + } + + public void addDependency(PluginDependency dependency) { + this.dependencies.add(dependency); + } + + /** + * Returns the unique identifier of this plugin. + */ + @Override + public String getPluginId() { + return pluginId; + } + + /** + * Returns the description of this plugin. + */ + @Override + public String getPluginDescription() { + return pluginDescription; + } + + /** + * Returns the name of the class that implements Plugin interface. + */ + @Override + public String getPluginClass() { + return pluginClass; + } + + /** + * Returns the version of this plugin. + */ + @Override + public String getVersion() { + return version; + } + + /** + * Returns string version of requires + * + * @return String with requires expression on SemVer format + */ + @Override + public String getRequires() { + return requires; + } + + /** + * Returns the provider name of this plugin. + */ + @Override + public String getProvider() { + return provider; + } + + /** + * Returns the legal license of this plugin, e.g. "Apache-2.0", "MIT" etc + */ + @Override + public String getLicense() { + return license; + } + + /** + * Returns all dependencies declared by this plugin. + * Returns an empty array if this plugin does not declare any require. + */ + @Override + public List getDependencies() { + return dependencies; + } + + @Override + public String toString() { + return "PluginDescriptor [pluginId=" + pluginId + ", pluginClass=" + + pluginClass + ", version=" + version + ", provider=" + + provider + ", dependencies=" + dependencies + ", description=" + + pluginDescription + ", requires=" + requires + ", license=" + + license + "]"; + } + + protected DefaultPluginDescriptor setPluginId(String pluginId) { + this.pluginId = pluginId; + + return this; + } + + protected PluginDescriptor setPluginDescription(String pluginDescription) { + this.pluginDescription = pluginDescription; + + return this; + } + + protected PluginDescriptor setPluginClass(String pluginClassName) { + this.pluginClass = pluginClassName; + + return this; + } + + + protected DefaultPluginDescriptor setPluginVersion(String version) { + this.version = version; + + return this; + } + + protected PluginDescriptor setProvider(String provider) { + this.provider = provider; + + return this; + } + + protected PluginDescriptor setRequires(String requires) { + this.requires = requires; + + return this; + } + + protected PluginDescriptor setDependencies(String dependencies) { + if (dependencies != null) { + dependencies = dependencies.trim(); + if (dependencies.isEmpty()) { + this.dependencies = Collections.emptyList(); + } else { + this.dependencies = new ArrayList<>(); + String[] tokens = dependencies.split(","); + for (String dependency : tokens) { + dependency = dependency.trim(); + if (!dependency.isEmpty()) { + this.dependencies.add(new PluginDependency(dependency)); + } + } + if (this.dependencies.isEmpty()) { + this.dependencies = Collections.emptyList(); + } + } + } else { + this.dependencies = Collections.emptyList(); + } + + return this; + } + + public PluginDescriptor setLicense(String license) { + this.license = license; + + return this; + } + +} diff --git a/pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java b/pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java index aa9a929..1e09067 100644 --- a/pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java +++ b/pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java @@ -88,7 +88,7 @@ public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder { } protected PluginDescriptor createPluginDescriptor(Manifest manifest) { - PluginDescriptor pluginDescriptor = createPluginDescriptorInstance(); + DefaultPluginDescriptor pluginDescriptor = createPluginDescriptorInstance(); // TODO validate !!! Attributes attributes = manifest.getMainAttributes(); @@ -125,8 +125,8 @@ public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder { return pluginDescriptor; } - protected PluginDescriptor createPluginDescriptorInstance() { - return new PluginDescriptor(); + protected DefaultPluginDescriptor createPluginDescriptorInstance() { + return new DefaultPluginDescriptor(); } } diff --git a/pf4j/src/main/java/org/pf4j/PluginDescriptor.java b/pf4j/src/main/java/org/pf4j/PluginDescriptor.java index 6dddbbf..ab08d68 100644 --- a/pf4j/src/main/java/org/pf4j/PluginDescriptor.java +++ b/pf4j/src/main/java/org/pf4j/PluginDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 Decebal Suiu + * Copyright 2015 Decebal Suiu * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,6 @@ */ package org.pf4j; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -25,153 +23,21 @@ import java.util.List; * * @author Decebal Suiu */ -public class PluginDescriptor { +public interface PluginDescriptor { - private String pluginId; - private String pluginDescription; - private String pluginClass; - private String version; - private String requires = "*"; // SemVer format - private String provider; - private List dependencies; - private String license; + String getPluginId(); - public PluginDescriptor() { - dependencies = new ArrayList<>(); - } + String getPluginDescription(); - /** - * Returns the unique identifier of this plugin. - */ - public String getPluginId() { - return pluginId; - } + String getPluginClass(); - /** - * Returns the description of this plugin. - */ - public String getPluginDescription() { - return pluginDescription; - } + String getVersion(); - /** - * Returns the name of the class that implements Plugin interface. - */ - public String getPluginClass() { - return pluginClass; - } + String getRequires(); - /** - * Returns the version of this plugin. - */ - public String getVersion() { - return version; - } + String getProvider(); - /** - * Returns string version of requires - * @return String with requires expression on SemVer format - */ - public String getRequires() { - return requires; - } - - /** - * Returns the provider name of this plugin. - */ - public String getProvider() { - return provider; - } - - /** - * Returns the legal license of this plugin, e.g. "Apache-2.0", "MIT" etc - */ - public String getLicense() { - return license; - } - - /** - * Returns all dependencies declared by this plugin. - * Returns an empty array if this plugin does not declare any require. - */ - public List getDependencies() { - return dependencies; - } - - @Override - public String toString() { - return "PluginDescriptor [pluginId=" + pluginId + ", pluginClass=" - + pluginClass + ", version=" + version + ", provider=" - + provider + ", dependencies=" + dependencies + ", description=" - + pluginDescription + ", requires=" + requires + ", license=" - + license + "]"; - } - - PluginDescriptor setPluginId(String pluginId) { - this.pluginId = pluginId; - - return this; - } - - PluginDescriptor setPluginDescription(String pluginDescription) { - this.pluginDescription = pluginDescription; - - return this; - } - - PluginDescriptor setPluginClass(String pluginClassName) { - this.pluginClass = pluginClassName; - - return this; - } - - PluginDescriptor setPluginVersion(String version) { - this.version = version; - - return this; - } - - PluginDescriptor setProvider(String provider) { - this.provider = provider; - - return this; - } - - PluginDescriptor setRequires(String requires) { - this.requires = requires; - - return this; - } - - PluginDescriptor setDependencies(String dependencies) { - if (dependencies != null) { - dependencies = dependencies.trim(); - if (dependencies.isEmpty()) { - this.dependencies = Collections.emptyList(); - } else { - this.dependencies = new ArrayList<>(); - String[] tokens = dependencies.split(","); - for (String dependency : tokens) { - dependency = dependency.trim(); - if (!dependency.isEmpty()) { - this.dependencies.add(new PluginDependency(dependency)); - } - } - if (this.dependencies.isEmpty()) { - this.dependencies = Collections.emptyList(); - } - } - } else { - this.dependencies = Collections.emptyList(); - } - - return this; - } - - public PluginDescriptor setLicense(String license) { - this.license = license; - - return this; - } + String getLicense(); + List getDependencies(); } diff --git a/pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java b/pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java index 4148287..9357bc3 100644 --- a/pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java +++ b/pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java @@ -95,7 +95,7 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder } protected PluginDescriptor createPluginDescriptor(Properties properties) { - PluginDescriptor pluginDescriptor = createPluginDescriptorInstance(); + DefaultPluginDescriptor pluginDescriptor = createPluginDescriptorInstance(); // TODO validate !!! String id = properties.getProperty("plugin.id"); @@ -132,8 +132,8 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder return pluginDescriptor; } - protected PluginDescriptor createPluginDescriptorInstance() { - return new PluginDescriptor(); + protected DefaultPluginDescriptor createPluginDescriptorInstance() { + return new DefaultPluginDescriptor(); } } diff --git a/pf4j/src/test/java/org/pf4j/DefaultPluginManagerTest.java b/pf4j/src/test/java/org/pf4j/DefaultPluginManagerTest.java index 03f8496..a474f57 100644 --- a/pf4j/src/test/java/org/pf4j/DefaultPluginManagerTest.java +++ b/pf4j/src/test/java/org/pf4j/DefaultPluginManagerTest.java @@ -27,13 +27,13 @@ import static org.junit.Assert.assertTrue; public class DefaultPluginManagerTest { - private PluginDescriptor pd1 = null; + private DefaultPluginDescriptor pd1 = null; private DefaultPluginManager pluginManager = new DefaultPluginManager(); private PluginWrapper pw1; @Before public void init() throws IOException { - pd1 = new PluginDescriptor(); + pd1 = new DefaultPluginDescriptor(); pd1.setPluginId("myPlugin"); pd1.setPluginVersion("1.2.3"); pd1.setPluginClass("foo"); diff --git a/pf4j/src/test/java/org/pf4j/DependencyResolverTest.java b/pf4j/src/test/java/org/pf4j/DependencyResolverTest.java index 44d2c93..dcd2515 100644 --- a/pf4j/src/test/java/org/pf4j/DependencyResolverTest.java +++ b/pf4j/src/test/java/org/pf4j/DependencyResolverTest.java @@ -40,11 +40,11 @@ public class DependencyResolverTest { @Test public void sortedPlugins() { // create incomplete plugin descriptor (ignore some attributes) - PluginDescriptor pd1 = new PluginDescriptor() + PluginDescriptor pd1 = new DefaultPluginDescriptor() .setPluginId("p1") .setDependencies("p2"); - PluginDescriptor pd2 = new PluginDescriptor() + PluginDescriptor pd2 = new DefaultPluginDescriptor() .setPluginId("p2") .setPluginVersion("0.0.0"); // needed in "checkDependencyVersion" method @@ -60,7 +60,7 @@ public class DependencyResolverTest { @Test public void notFoundDependencies() throws Exception { - PluginDescriptor pd1 = new PluginDescriptor() + PluginDescriptor pd1 = new DefaultPluginDescriptor() .setPluginId("p1") .setDependencies("p2, p3"); @@ -75,17 +75,17 @@ public class DependencyResolverTest { @Test public void cyclicDependencies() { - PluginDescriptor pd1 = new PluginDescriptor() + PluginDescriptor pd1 = new DefaultPluginDescriptor() .setPluginId("p1") .setPluginVersion("0.0.0") .setDependencies("p2"); - PluginDescriptor pd2 = new PluginDescriptor() + PluginDescriptor pd2 = new DefaultPluginDescriptor() .setPluginId("p2") .setPluginVersion("0.0.0") .setDependencies("p3"); - PluginDescriptor pd3 = new PluginDescriptor() + PluginDescriptor pd3 = new DefaultPluginDescriptor() .setPluginId("p3") .setPluginVersion("0.0.0") .setDependencies("p1"); @@ -102,12 +102,12 @@ public class DependencyResolverTest { @Test public void wrongDependencyVersion() { - PluginDescriptor pd1 = new PluginDescriptor() + PluginDescriptor pd1 = new DefaultPluginDescriptor() .setPluginId("p1") // .setDependencies("p2@2.0.0"); // simple version .setDependencies("p2@>=1.5.0 & <1.6.0"); // range version - PluginDescriptor pd2 = new PluginDescriptor() + PluginDescriptor pd2 = new DefaultPluginDescriptor() .setPluginId("p2") .setPluginVersion("1.4.0"); @@ -122,11 +122,11 @@ public class DependencyResolverTest { @Test public void goodDependencyVersion() { - PluginDescriptor pd1 = new PluginDescriptor() + PluginDescriptor pd1 = new DefaultPluginDescriptor() .setPluginId("p1") .setDependencies("p2@2.0.0"); - PluginDescriptor pd2 = new PluginDescriptor() + PluginDescriptor pd2 = new DefaultPluginDescriptor() .setPluginId("p2") .setPluginVersion("2.0.0"); diff --git a/pf4j/src/test/java/org/pf4j/processor/ServiceProviderExtensionStorageTest.java b/pf4j/src/test/java/org/pf4j/processor/ServiceProviderExtensionStorageTest.java new file mode 100644 index 0000000..a2ffc67 --- /dev/null +++ b/pf4j/src/test/java/org/pf4j/processor/ServiceProviderExtensionStorageTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Decebal Suiu + * + * 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.processor; + +import org.junit.Test; + +import javax.annotation.processing.Filer; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.io.StringReader; +import java.util.*; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; + +/** + * @author Josiah Haswell + */ +public class ServiceProviderExtensionStorageTest { + + @Test + public void ensureServiceProviderExtensionStorageReadWorks() throws IOException { + final StringReader file = new StringReader("#hello\n World"); + final Set entries = new HashSet<>(); + ServiceProviderExtensionStorage.read(file, entries); + + assertThat(entries.size(), is(1)); + assertThat(entries.contains("World"), is(true)); + } + + + @Test + public void ensureReadingExtensionsProducesCorrectListOfExtensions() { + final StringReader file = new StringReader("#hello\n World"); + final ExtensionAnnotationProcessor processor = mock(ExtensionAnnotationProcessor.class); + final Map> extensions = new HashMap<>(); + extensions.put("hello", Collections.singleton("world")); + + given(processor.getExtensions()).willReturn(extensions); + ServiceProviderExtensionStorage extensionStorage = new ServiceProviderExtensionStorage(processor) { + @Override + protected Filer getFiler() { + try { + Filer filer = mock(Filer.class); + FileObject fileObject = mock(FileObject.class); + given(fileObject.openReader(true)).willReturn(file); + given(filer.getResource( + any(StandardLocation.class), + any(String.class), + any(String.class) + )).willReturn(fileObject); + return filer; + } catch(IOException ex) { + throw new IllegalStateException("Shouldn't have gotten here"); + } + } + }; + + Map> read = extensionStorage.read(); + assertThat(read.containsKey("hello"), is(true)); + assertThat(read.get("hello"), is(Collections.singleton("World"))); + } + +}