diff --git a/demo_gradle/README.md b/demo_gradle/README.md new file mode 100644 index 0000000..6851fc0 --- /dev/null +++ b/demo_gradle/README.md @@ -0,0 +1,62 @@ +# PF4J Gradle Demo + +This demo assumes that you know the basics of Gradle (Please look at [gradle](https://gradle.org/) for more info) + +### Setup/Build + +1. Clone the repo +2. Go to demo_gradle `cd demo_gradle` +3. run `gradle build` + +* This will produce one jar, named app-plugin-demo-uberjar.jar, located in the `app/build/libs/` directory and three plugins zips located in `build/plugins` directory. +* The plugins are `plugin-hello-plugin-0.0.1.zip`, `plugin-KotlinPlugin-1.0.0.zip` and `plugin-welcome-plugin-0.0.1.zip` + +### Run the demo + +1. Run + +``` + java -jar -Dpf4j.pluginsDir=build/plugins app/build/libs/app-plugin-demo-uberjar.jar +``` + +* pf4j.pluginsDir: is where the plugins are located + +2. The demo's output should look similar to: (Please see `Boot#main()` for more details) +``` +demo_gradle $ java -jar -Dpf4j.pluginsDir=build/plugins app/build/libs/app-plugin-demo-uberjar.jar +[main] INFO org.pf4j.demo.Boot - ######################################## +[main] INFO org.pf4j.demo.Boot - PF4J-DEMO +[main] INFO org.pf4j.demo.Boot - ######################################## +[main] INFO org.pf4j.DefaultPluginStatusProvider - Enabled plugins: [] +[main] INFO org.pf4j.DefaultPluginStatusProvider - Disabled plugins: [] +[main] INFO org.pf4j.DefaultPluginManager - PF4J version 0.0.0 in 'deployment' mode +[main] INFO org.pf4j.AbstractPluginManager - Plugin 'welcome-plugin@0.0.1' resolved +[main] INFO org.pf4j.AbstractPluginManager - Plugin 'KotlinPlugin@1.0.0' resolved +[main] INFO org.pf4j.AbstractPluginManager - Plugin 'hello-plugin@0.0.1' resolved +[main] INFO org.pf4j.AbstractPluginManager - Start plugin 'welcome-plugin@0.0.1' +[main] INFO org.pf4j.demo.welcome.WelcomePlugin - WelcomePlugin.start() +[main] INFO org.pf4j.demo.welcome.WelcomePlugin - WELCOMEPLUGIN +[main] INFO org.pf4j.AbstractPluginManager - Start plugin 'KotlinPlugin@1.0.0' +[main] INFO org.pf4j.demo.kotlin.KotlinPlugin - KotlinPlugin.start() +[main] INFO org.pf4j.demo.kotlin.KotlinPlugin - KOTLINPLUGIN +[main] INFO org.pf4j.AbstractPluginManager - Start plugin 'hello-plugin@0.0.1' +[main] INFO org.pf4j.demo.hello.HelloPlugin - HelloPlugin.start() +[main] INFO org.pf4j.demo.Boot - Plugindirectory: +[main] INFO org.pf4j.demo.Boot - build/plugins + +[main] INFO org.pf4j.demo.Boot - Found 3 extensions for extension point 'org.pf4j.demo.api.Greeting' +[main] INFO org.pf4j.demo.Boot - >>> Whazzup +[main] INFO org.pf4j.demo.Boot - >>> Welcome +[main] INFO org.pf4j.demo.Boot - >>> Hello +[main] INFO org.pf4j.demo.Boot - Extensions added by plugin 'welcome-plugin': +[main] INFO org.pf4j.demo.Boot - Extensions added by plugin 'KotlinPlugin': +[main] INFO org.pf4j.demo.Boot - Extensions added by plugin 'hello-plugin': +[main] INFO org.pf4j.AbstractPluginManager - Stop plugin 'hello-plugin@0.0.1' +[main] INFO org.pf4j.demo.hello.HelloPlugin - HelloPlugin.stop() +[main] INFO org.pf4j.AbstractPluginManager - Stop plugin 'KotlinPlugin@1.0.0' +[main] INFO org.pf4j.demo.kotlin.KotlinPlugin - KotlinPlugin.stop() +[main] INFO org.pf4j.AbstractPluginManager - Stop plugin 'welcome-plugin@0.0.1' +[main] INFO org.pf4j.demo.welcome.WelcomePlugin - WelcomePlugin.stop() + +``` + diff --git a/demo_gradle/api/build.gradle b/demo_gradle/api/build.gradle index 12a46bf..0d3ca62 100644 --- a/demo_gradle/api/build.gradle +++ b/demo_gradle/api/build.gradle @@ -1,5 +1,6 @@ dependencies { - compile 'org.pf4j:pf4j:2.0.0-SNAPSHOT' - compile 'org.apache.commons:commons-lang3:3.0' + compile group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}" + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + testCompile group: 'junit', name: 'junit', version: '4.+' } diff --git a/demo_gradle/app/build.gradle b/demo_gradle/app/build.gradle index 9f3d5a4..4761092 100644 --- a/demo_gradle/app/build.gradle +++ b/demo_gradle/app/build.gradle @@ -3,14 +3,29 @@ apply plugin: 'application' mainClassName = 'org.pf4j.demo.Boot' dependencies { - compile project(':api') - compile 'org.pf4j:pf4j:2.0.0-SNAPSHOT' - compile 'org.apache.commons:commons-lang3:3.5' - testCompile group: 'junit', name: 'junit', version: '4.+' - compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25' + compile project(':api') + compile group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}" + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25' + + testCompile group: 'junit', name: 'junit', version: '4.+' } -jar { - baseName = 'Plugin Demo' - version = '0.1.0' +task uberjar(type: Jar, dependsOn: ['compileJava']) { + zip64 true + from configurations.runtime.asFileTree.files.collect { + exclude "META-INF/*.SF" + exclude "META-INF/*.DSA" + exclude "META-INF/*.RSA" + zipTree(it) + } + from files(sourceSets.main.output.classesDir) + from files(sourceSets.main.resources) + manifest { + attributes 'Main-Class': mainClassName + } + + baseName = "${project.name}-plugin-demo" + classifier = "uberjar" } + diff --git a/demo_gradle/app/src/main/java/org/pf4j/demo/Boot.java b/demo_gradle/app/src/main/java/org/pf4j/demo/Boot.java index 46261d6..9343f4a 100644 --- a/demo_gradle/app/src/main/java/org/pf4j/demo/Boot.java +++ b/demo_gradle/app/src/main/java/org/pf4j/demo/Boot.java @@ -16,6 +16,9 @@ package org.pf4j.demo; import org.apache.commons.lang3.StringUtils; +import org.pf4j.CompoundPluginDescriptorFinder; +import org.pf4j.ManifestPluginDescriptorFinder; +import org.pf4j.PropertiesPluginDescriptorFinder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.pf4j.DefaultPluginManager; @@ -38,7 +41,16 @@ public class Boot { printLogo(); // create the plugin manager - final PluginManager pluginManager = new DefaultPluginManager(); + final PluginManager pluginManager = new DefaultPluginManager() { + @Override + protected CompoundPluginDescriptorFinder createPluginDescriptorFinder() { + return new CompoundPluginDescriptorFinder() + // Demo is using the Manifest file + // PropertiesPluginDescriptorFinder is commented out just to avoid error log + //.add(new PropertiesPluginDescriptorFinder()) + .add(new ManifestPluginDescriptorFinder()); + } + }; // load the plugins pluginManager.loadPlugins(); diff --git a/demo_gradle/build.gradle b/demo_gradle/build.gradle index d86746d..9968360 100644 --- a/demo_gradle/build.gradle +++ b/demo_gradle/build.gradle @@ -1,26 +1,14 @@ subprojects { - apply plugin: 'java' + apply plugin: 'java' - repositories { - mavenLocal() - mavenCentral() - } + repositories { + mavenLocal() + mavenCentral() + } } +// plugin location +ext.pluginsDir = rootProject.buildDir.path + '/plugins' + +task build(dependsOn: [':app:uberjar']) -task copyPlugins() { - doLast { - delete 'app/plugins' - mkdir 'app/plugins' - subprojects.each { p -> - if (p.path.contains(":plugins/")) { - System.out.println("Copying plugin from " + p.path); - copy { - from p.projectDir.toString() + '/build/libs' - into 'app/plugins' - include '*.zip' - } - } - } - } -} diff --git a/demo_gradle/gradle.properties b/demo_gradle/gradle.properties new file mode 100644 index 0000000..177f36b --- /dev/null +++ b/demo_gradle/gradle.properties @@ -0,0 +1,2 @@ +# PF4J +pf4jVersion=2.0.0 diff --git a/demo_gradle/plugins/build.gradle b/demo_gradle/plugins/build.gradle new file mode 100644 index 0000000..104b17d --- /dev/null +++ b/demo_gradle/plugins/build.gradle @@ -0,0 +1,32 @@ +subprojects { + jar { + manifest { + attributes 'Plugin-Class': "${pluginClass}", + 'Plugin-Id': "${pluginId}", + 'Plugin-Version': "${version}", + 'Plugin-Provider': "${pluginProvider}" + } + } + + task plugin(type: Jar) { + baseName = "plugin-${pluginId}" + into('classes') { + with jar + } + into('lib') { + from configurations.compile + } + extension('zip') + } + + task assemblePlugin(type: Copy) { + from plugin + into pluginsDir + } +} + +task assemblePlugins(type: Copy) { + dependsOn subprojects.assemblePlugin +} + +build.dependsOn project.tasks.assemblePlugins diff --git a/demo_gradle/plugins/plugin1/build.gradle b/demo_gradle/plugins/plugin1/build.gradle index 6a9d507..69791a7 100644 --- a/demo_gradle/plugins/plugin1/build.gradle +++ b/demo_gradle/plugins/plugin1/build.gradle @@ -1,33 +1,9 @@ -jar { - baseName = 'WelcomePlugin' - version = '0.1.0' - manifest { - attributes 'Plugin-Class': 'org.pf4j.demo.welcome.WelcomePlugin', - 'Plugin-Id': 'WelcomePlugin', - 'Plugin-Version': '1.0.0', - 'Plugin-Provider': 'Decebal Suiu' - } -} - -task plugin(type: Jar) { - baseName = 'WelcomePlugin' - version = '0.1.0' - into('classes') { - with jar - } - into('lib') { - from configurations.compile - } - extension('zip') -} -assemble.dependsOn plugin - dependencies { - compileOnly project(':api') - // compileOnly important!!! We do not want to put the api into the zip file since the main program has it already! - compile('org.pf4j:pf4j:2.0.0-SNAPSHOT') { - exclude group: "org.slf4j" - } - compile 'org.apache.commons:commons-lang3:3.5' - testCompile group: 'junit', name: 'junit', version: '4.+' + // compileOnly important!!! We do not want to put the api into the zip file since the main program has it already! + compileOnly project(':api') + compileOnly(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") { + exclude group: "org.slf4j" + } + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + testCompile group: 'junit', name: 'junit', version: '4.+' } diff --git a/demo_gradle/plugins/plugin1/gradle.properties b/demo_gradle/plugins/plugin1/gradle.properties new file mode 100644 index 0000000..2edd800 --- /dev/null +++ b/demo_gradle/plugins/plugin1/gradle.properties @@ -0,0 +1,6 @@ +version=0.0.1 + +pluginId=welcome-plugin +pluginClass=org.pf4j.demo.welcome.WelcomePlugin +pluginProvider=Decebal Suiu +pluginDependencies= diff --git a/demo_gradle/plugins/plugin1/plugin.properties b/demo_gradle/plugins/plugin1/plugin.properties deleted file mode 100644 index 9da9bcc..0000000 --- a/demo_gradle/plugins/plugin1/plugin.properties +++ /dev/null @@ -1,5 +0,0 @@ -plugin.id=welcome-plugin -plugin.class=org.pf4j.demo.welcome.WelcomePlugin -plugin.version=0.0.1 -plugin.provider=Decebal Suiu -plugin.dependencies= diff --git a/demo_gradle/plugins/plugin2/build.gradle b/demo_gradle/plugins/plugin2/build.gradle index da75a55..69791a7 100644 --- a/demo_gradle/plugins/plugin2/build.gradle +++ b/demo_gradle/plugins/plugin2/build.gradle @@ -1,33 +1,9 @@ -jar { - baseName = 'HelloPlugin' - version = '0.1.0' - manifest { - attributes 'Plugin-Class': 'org.pf4j.demo.hello.HelloPlugin', - 'Plugin-Id': 'HelloPlugin', - 'Plugin-Version': '1.0.0', - 'Plugin-Provider': 'Decebal Suiu' - } -} - -task plugin(type: Jar) { - baseName = 'HelloPlugin' - version = '0.1.0' - into('classes') { - with jar - } - into('lib') { - from configurations.compile - } - extension('zip') -} -assemble.dependsOn plugin - dependencies { - compileOnly project(':api') - // compileOnly important!!! We do not want to put the api into the zip file since the main program has it already! - compile('org.pf4j:pf4j:2.0.0-SNAPSHOT') { - exclude group: "org.slf4j" - } - compile 'org.apache.commons:commons-lang3:3.5' - testCompile group: 'junit', name: 'junit', version: '4.+' + // compileOnly important!!! We do not want to put the api into the zip file since the main program has it already! + compileOnly project(':api') + compileOnly(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") { + exclude group: "org.slf4j" + } + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + testCompile group: 'junit', name: 'junit', version: '4.+' } diff --git a/demo_gradle/plugins/plugin2/gradle.properties b/demo_gradle/plugins/plugin2/gradle.properties new file mode 100644 index 0000000..ef70127 --- /dev/null +++ b/demo_gradle/plugins/plugin2/gradle.properties @@ -0,0 +1,6 @@ +version=0.0.1 + +pluginId=hello-plugin +pluginClass=org.pf4j.demo.hello.HelloPlugin +pluginProvider=Decebal Suiu +pluginDependencies= diff --git a/demo_gradle/plugins/plugin2/plugin.properties b/demo_gradle/plugins/plugin2/plugin.properties deleted file mode 100644 index 60b6f33..0000000 --- a/demo_gradle/plugins/plugin2/plugin.properties +++ /dev/null @@ -1,5 +0,0 @@ -plugin.id=hello-plugin -plugin.class=org.pf4j.demo.hello.HelloPlugin -plugin.version=0.0.1 -plugin.provider=Decebal Suiu -plugin.dependencies= diff --git a/demo_gradle/plugins/plugin3/build.gradle b/demo_gradle/plugins/plugin3/build.gradle index 69afeab..c360e23 100644 --- a/demo_gradle/plugins/plugin3/build.gradle +++ b/demo_gradle/plugins/plugin3/build.gradle @@ -1,51 +1,28 @@ buildscript { - ext.kotlin_version = '1.1.2-2' + ext.kotlin_version = '1.1.2-2' - repositories { - mavenCentral() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -jar { - baseName = 'KotlinPlugin' - version = '0.1.0' - manifest { - attributes 'Plugin-Class': 'org.pf4j.demo.kotlin.KotlinPlugin', - 'Plugin-Id': 'KotlinPlugin', - 'Plugin-Version': '1.0.0', - 'Plugin-Provider': 'Anindya Chatterjee' - } -} - -task plugin(type: Jar) { - baseName = 'KotlinPlugin' - version = '0.1.0' - into('classes') { - with jar - } - into('lib') { - from configurations.compile - } - extension('zip') + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } } -assemble.dependsOn plugin apply plugin: 'kotlin' apply plugin: 'kotlin-kapt' repositories { - mavenCentral() + mavenCentral() } dependencies { - compileOnly project(':api') - kapt('org.pf4j:pf4j:2.0.0-SNAPSHOT') { - exclude group: "org.slf4j" - } - compile 'org.apache.commons:commons-lang3:3.5' - testCompile group: 'junit', name: 'junit', version: '4.+' - compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" + compileOnly project(':api') + compileOnly(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") { + exclude group: "org.slf4j" + } + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" + + testCompile group: 'junit', name: 'junit', version: '4.+' } diff --git a/demo_gradle/plugins/plugin3/gradle.properties b/demo_gradle/plugins/plugin3/gradle.properties new file mode 100644 index 0000000..a04b609 --- /dev/null +++ b/demo_gradle/plugins/plugin3/gradle.properties @@ -0,0 +1,6 @@ +version=1.0.0 + +pluginId=KotlinPlugin +pluginClass=org.pf4j.demo.kotlin.KotlinPlugin +pluginProvider=Anindya Chatterjee +pluginDependencies= diff --git a/demo_gradle/settings.gradle b/demo_gradle/settings.gradle index 7ee71ba..828e80a 100644 --- a/demo_gradle/settings.gradle +++ b/demo_gradle/settings.gradle @@ -1,5 +1,8 @@ include 'api' include 'app' -include 'plugins/plugin1' -include 'plugins/plugin2' -include 'plugins/plugin3' + +include 'plugins' + +include 'plugins:plugin1' +include 'plugins:plugin2' +include 'plugins:plugin3' 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/DefaultPluginManager.java b/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java index 660950f..0e08984 100644 --- a/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java +++ b/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java @@ -52,7 +52,7 @@ public class DefaultPluginManager extends AbstractPluginManager { } @Override - protected CompoundPluginDescriptorFinder createPluginDescriptorFinder() { + protected PluginDescriptorFinder createPluginDescriptorFinder() { return new CompoundPluginDescriptorFinder() .add(new PropertiesPluginDescriptorFinder()) .add(new ManifestPluginDescriptorFinder()); 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"))); + } + +}