├── .gitignore
├── LICENSE
├── README.md
├── _config.yml
├── shared-interfaces
├── README.md
├── pom.xml
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── curisprofound
│ │ └── plugins
│ │ └── PluginInterface.java
└── target
│ ├── classes
│ └── com
│ │ └── curisprofound
│ │ └── plugins
│ │ └── PluginInterface.class
│ ├── maven-archiver
│ └── pom.properties
│ ├── maven-status
│ └── maven-compiler-plugin
│ │ ├── compile
│ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile
│ │ └── default-testCompile
│ │ └── inputFiles.lst
│ └── shared-plugin-interfaces-1.1.0.jar
├── simple-plugin-container
├── README.md
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── curisprofound
│ │ │ │ └── plugins
│ │ │ │ └── simple
│ │ │ │ └── Container.java
│ │ └── resources
│ │ │ └── assembly.xml
│ └── test
│ │ ├── lib
│ │ ├── java-semver-0.9.0.jar
│ │ ├── pf4j-2.3.0.jar
│ │ ├── shared-plugin-interface-1.0-SNAPSHOT.jar
│ │ ├── slf4j-api-1.7.5.jar
│ │ └── slf4j-simple-1.7.5.jar
│ │ ├── plugins
│ │ ├── test-plugin-simple-1.0-SNAPSHOT.zip
│ │ └── test-plugin-simple-1.0-SNAPSHOT
│ │ │ ├── classes
│ │ │ ├── META-INF
│ │ │ │ ├── MANIFEST.MF
│ │ │ │ ├── extensions.idx
│ │ │ │ └── maven
│ │ │ │ │ └── com.curisprofound
│ │ │ │ │ └── test-plugin-simple
│ │ │ │ │ ├── pom.properties
│ │ │ │ │ └── pom.xml
│ │ │ ├── assembly.xml
│ │ │ ├── com
│ │ │ │ └── curisprofound
│ │ │ │ │ └── plugins
│ │ │ │ │ └── simple
│ │ │ │ │ ├── HelloPlugin$HelloGreeting.class
│ │ │ │ │ └── HelloPlugin.class
│ │ │ └── plugin.properties
│ │ │ ├── lib
│ │ │ ├── java-semver-0.9.0.jar
│ │ │ └── pf4j-2.3.0.jar
│ │ │ └── plugin.properties
│ │ ├── simple-plugin-container-1.0-SNAPSHOT.jar
│ │ └── simple-plugin-container-1.0-SNAPSHOT.zip
└── target
│ ├── classes
│ ├── assembly.xml
│ └── com
│ │ └── curisprofound
│ │ └── plugins
│ │ └── simple
│ │ └── Container.class
│ ├── lib
│ ├── java-semver-0.9.0.jar
│ ├── pf4j-2.3.0.jar
│ ├── shared-plugin-interfaces-1.1.0.jar
│ ├── slf4j-api-1.7.5.jar
│ └── slf4j-simple-1.7.5.jar
│ ├── maven-archiver
│ └── pom.properties
│ ├── maven-status
│ └── maven-compiler-plugin
│ │ ├── compile
│ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile
│ │ └── default-testCompile
│ │ └── inputFiles.lst
│ ├── plugins
│ ├── test-plugin-simple-1.0-SNAPSHOT.zip
│ └── test-plugin-simple-1.0-SNAPSHOT
│ │ ├── classes
│ │ ├── META-INF
│ │ │ └── extensions.idx
│ │ ├── assembly.xml
│ │ ├── com
│ │ │ └── curisprofound
│ │ │ │ └── plugins
│ │ │ │ └── simple
│ │ │ │ ├── SimplePlugin$SimpleIdentityPlugin.class
│ │ │ │ └── SimplePlugin.class
│ │ └── plugin.properties
│ │ ├── lib
│ │ ├── java-semver-0.9.0.jar
│ │ └── pf4j-2.3.0.jar
│ │ └── plugin.properties
│ ├── simple-plugin-container-1.0-SNAPSHOT.jar
│ ├── simple-plugin-container-1.0-SNAPSHOT.zip
│ └── simple-plugin-container-1.0-SNAPSHOT
│ ├── lib
│ ├── java-semver-0.9.0.jar
│ ├── pf4j-2.3.0.jar
│ ├── shared-plugin-interfaces-1.1.0.jar
│ ├── slf4j-api-1.7.5.jar
│ └── slf4j-simple-1.7.5.jar
│ ├── plugins
│ ├── test-plugin-simple-1.0-SNAPSHOT.zip
│ └── test-plugin-simple-1.0-SNAPSHOT
│ │ ├── classes
│ │ ├── META-INF
│ │ │ └── extensions.idx
│ │ ├── assembly.xml
│ │ ├── com
│ │ │ └── curisprofound
│ │ │ │ └── plugins
│ │ │ │ └── simple
│ │ │ │ ├── SimplePlugin$SimpleIdentityPlugin.class
│ │ │ │ └── SimplePlugin.class
│ │ └── plugin.properties
│ │ ├── lib
│ │ ├── java-semver-0.9.0.jar
│ │ └── pf4j-2.3.0.jar
│ │ └── plugin.properties
│ └── simple-plugin-container-1.0-SNAPSHOT.jar
├── simple-test-plugin
├── README.md
├── pom.xml
├── src
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── curisprofound
│ │ │ └── plugins
│ │ │ └── simple
│ │ │ └── SimplePlugin.java
│ │ └── resources
│ │ ├── assembly.xml
│ │ └── plugin.properties
└── target
│ ├── classes
│ ├── META-INF
│ │ └── extensions.idx
│ ├── assembly.xml
│ ├── com
│ │ └── curisprofound
│ │ │ └── plugins
│ │ │ └── simple
│ │ │ ├── SimplePlugin$SimpleIdentityPlugin.class
│ │ │ └── SimplePlugin.class
│ └── plugin.properties
│ ├── maven-archiver
│ └── pom.properties
│ ├── maven-status
│ └── maven-compiler-plugin
│ │ ├── compile
│ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile
│ │ └── default-testCompile
│ │ └── inputFiles.lst
│ ├── test-plugin-simple-1.0-SNAPSHOT.jar
│ ├── test-plugin-simple-1.0-SNAPSHOT.zip
│ └── test-plugin-simple-1.0-SNAPSHOT
│ ├── classes
│ ├── META-INF
│ │ └── extensions.idx
│ ├── assembly.xml
│ ├── com
│ │ └── curisprofound
│ │ │ └── plugins
│ │ │ └── simple
│ │ │ ├── SimplePlugin$SimpleIdentityPlugin.class
│ │ │ └── SimplePlugin.class
│ └── plugin.properties
│ ├── lib
│ ├── java-semver-0.9.0.jar
│ └── pf4j-2.3.0.jar
│ └── plugin.properties
├── spring-plugin-container
├── .gitignore
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── curisprofound
│ │ │ └── springplugincontainer
│ │ │ ├── AppConfig.java
│ │ │ ├── PluginConfig.java
│ │ │ └── SpringPluginContainerApplication.java
│ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── com
│ └── curisprofound
│ └── springplugincontainer
│ └── SpringPluginContainerApplicationTests.java
└── spring-test-plugin
├── .gitignore
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── curisprofound
│ │ └── springtestplugin
│ │ ├── ApplicationConfiguration.java
│ │ ├── GreetProvider.java
│ │ ├── PluginController.java
│ │ ├── SpringSamplePlugin.java
│ │ └── SpringTestPluginApplication.java
└── resources
│ ├── application.properties
│ ├── assembly.xml
│ └── plugin.properties
└── test
└── java
└── com
└── curisprofound
└── springtestplugin
└── SpringTestPluginApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 | .sts4-cache
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 | /plugins/
19 | .mvn
20 |
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /build/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 |
29 | /docs/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 ralemy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Extending applications with PF4J plugins
2 |
3 | This repository provides a tutorial and an example on how to use PF4J to
4 | develop an application that supports extension through the development of third-party plugins.
5 |
6 | # User Stories:
7 |
8 | Initially, we focus on the minimum amount of code to create a java applicaiton with plugin support.
9 |
10 | |Story 01 |Should be able to add functionality via plugin|
11 | |---------|-----------------------|
12 | |As an | Application Developer|
13 | |I need to| support plugins in my applications|
14 | |So that| they can be extended by third-party collaborators|
15 |
16 | Then, we extend the functionality to include container and plugins built with
17 | Spring boot
18 |
19 | |Story 02 |Should be able to use Spring boot in container and plugins|
20 | |---------|-----------------------|
21 | |As an | Spring boot Developer|
22 | |I need to| support plugins written based on Spring|
23 | |So that| I can use Spring functionality such as dependency injection in my plugins|
24 |
25 | Next, we add a new Restful endpoint using an annotated class
26 |
27 | |Story 03 |Should be able to add to Restful endpoints from plugin |
28 | |---------|-----------------------|
29 | |As an | Spring boot Developer|
30 | |I need to| be able to add new endpoints via the plugin|
31 | |So that| provide access to the extended functionality via RESTful interfaces|
32 |
33 | Finally, we add a reactive Restful endpoint using a Router Function
34 |
35 | |Story 04 |Should be able to add reactive endpoints from plugin |
36 | |---------|-----------------------|
37 | |As an | Spring boot Developer|
38 | |I need to| be able to add reactive endpoints via the plugin|
39 | |So that| provide the benefits of reactive programing with my plugins|
40 |
41 |
42 | ## Contents
43 |
44 | [Overview](#overview) ....................... Explains the reasons behind creation of this repository
45 |
46 | [Shared Interface](./shared-interfaces)............. Allows plugins to interact with the container and eachother
47 |
48 | [Baremetal Plugin](./simple-test-plugin)............. Minimal java code that creates a functioning plugin
49 |
50 | [Baremetal Container](./simple-plugin-container)....... Minimal java code that creates standalone plugin container
51 |
52 | [Spring boot Plugin](./spring-test-plugin)............ A plugin that uses Spring boot for DI and adds endpoints created with annotated classes or router functions.
53 |
54 | [Spring boot Container](./spring-plugin-container)...... A Spring boot app with plugin support and reactive Restful service
55 |
56 | # Overview
57 |
58 | Plugins are pieces of software, developed by a third-party, that extend the functionality of a given application. There are many benefits to an application that supports plugins, such as flexibility to accommodate new requirements, extensibility to integrate in new environments, and suitability in being able to create tailored solutions by including only the functionality required for a specific use case.
59 |
60 | There are multiple ways of adding plugin support to a Java application. The powerful, age-old and very complex OSGI network to the use of simple and limited-functionality mechanisms inherent in Java 8. One good mid-way compromise which is neither too simplistic nor too complicated is Pf4J, although by no means this is to claim that it is the only or even the best solution for the problem.
61 |
62 | [PF4J][] is a plugin framework for Java, that allows third party developers to extend the functionality of an application by adding a zip file to the plugins folder that will be loaded at
63 | runtime. Extensions can also be added to the application jar file if needed. the [PF4J][] Github repository has an example of how to develop such an application, along with comprehensive documentation on the framework. While these should certainly be studied, in our experience understanding the examples was not easy for the average developers and we decided to contribure by creating this tutorial.
64 |
65 | This project demonstrates the same concepts in a more practical way. Three separate maven projects are created, and a scenario is presented on how the solution will be created and deployed.
66 |
67 | ## Actors
68 |
69 | In the plugin management system, two main actors are at play. the **application owner**, who creates the application which accepts the plugin, and published the interfaces that the second actor, the **plugin developer**, implements to develop extended functionality.
70 |
71 | ## Artifacts
72 |
73 | The solution involves three components. the first component is in the form of a java interface, which is developed by the application owner and consists of a series of mehtods that plugin developer implements to extend the application. This component should be typically published in maven repository or some similar place and is added to the other two components as a dependency.
74 |
75 | the second component is the container, which is also developed by the application owner. Once started, the plugin container scans the plugins folder and reads and unzips the plugins in that folder, loading the classes and starting and stopping the plugins.
76 |
77 |
78 | the third component is the plugin itself. it is developed by the plugin developer and implements some of the shared interfaces defined in the first component and together with its own dependencies resides as a zip file in the plugins directory where the container will be looking for it.
79 |
80 |
81 | The following table summarizes the above concepts
82 |
83 | |Artifact| Actor| Description|
84 | |--------|------|------------|
85 | |Container| Application Owner| the main application, scans a directory that contains plugins as zip files, decompresses and imports them into the application|
86 | |Shared Interfaces|Application Owner| the collection of interfaces that plugins implement. published by the application owner and included as a dependency by both the plugin-container and the plugin|
87 | |Plugin| Plugin Developer| the implementation of one or more interfaces defined in Shared-Plugin-Interfaces. deployed as a zip file of classes and their dependencies inside the plugins directory of the Plugin-Container|
88 |
89 | [Back to Contents](#contents)
90 |
91 | [PF4J]: https://github.com/pf4j/pf4j
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/shared-interfaces/README.md:
--------------------------------------------------------------------------------
1 | # The Shared Interfaces component
2 |
3 | This component will only contain the interfaces that the plugins are supposed to implement. What is important to keep in mind is that it should try not to force dependencies on plugins. For example, if it is defining an interface that will
4 | be implemented by Spring-based and non-Spring-based plugins, it should not use Spring specific classes and types as parameters or return values.
5 |
6 | It is noteworthy that more than one shared interface component can exist, and while the container will reference all of them, the plugins need only reference
7 | the ones they are implementing.
8 |
9 | For the purposes of our tutorial, we have a very small pom file.
10 |
11 |
12 | ```xml
13 |
14 |
17 | 4.0.0
18 |
19 | com.curis-profound
20 | shared-plugin-interfaces
21 | 1.1.0
22 |
23 |
24 |
25 |
26 |
27 | org.pf4j
28 | pf4j
29 | 2.3.0
30 |
31 |
32 |
33 |
34 | ```
35 |
36 | the ```org.pf4j``` dependency is the only one necessay, and will provide the superclass for interface to define:
37 |
38 | ```java
39 | package com.curisprofound.plugins;
40 |
41 | import org.pf4j.ExtensionPoint;
42 | import java.util.List;
43 |
44 | public interface PluginInterface extends ExtensionPoint {
45 | String identify();
46 | List> reactiveRoutes();
47 | List mvcControllers();
48 | }
49 | ```
50 |
51 | Three methods are defined. the first one is used by plugins to introduce themselves to the application with a human-readable phrase. The second one is for Spring-based plugins to add new reactive endpoints using ```RouterFunction``` objects, and the third endpoint is again for Spring-based plugins to add Restful endpoints using annotated classes.
52 |
53 |
54 | and we use a simple command to generate the jar file:
55 |
56 | ```bash
57 | mvn clean package
58 | ```
59 |
60 | The jar is then published to a repository and can be included in dependent projects in a standard way
61 |
62 | ```xml
63 |
64 |
65 | com.curisprofound
66 | shared-plugin-interfaces
67 | 1.1.0
68 |
69 |
70 | ```
71 |
72 | If you have the jar locally, you can add it to the local maven repo so the other projects could include it as if it was received from upstream.
73 |
74 | ```bash
75 | mvn install:install-file \
76 | -Dfile=target/shared-plugin-interfaces-1.1.0.jar \
77 | -DgroupId=com.curisprofound \
78 | -DartifactId=shared-plugin-interfaces \
79 | -Dversion=1.1.0 \
80 | -Dpackaging=jar
81 | ```
82 |
83 | [Back to Contents](../#contents)
84 |
85 | [PF4J]: https://github.com/pf4j/pf4j
86 |
87 |
--------------------------------------------------------------------------------
/shared-interfaces/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.curis-profound
8 | shared-plugin-interfaces
9 | 1.1.0
10 |
11 |
12 |
13 | org.pf4j
14 | pf4j
15 | 2.3.0
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/shared-interfaces/src/main/java/com/curisprofound/plugins/PluginInterface.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.plugins;
2 |
3 | import org.pf4j.ExtensionPoint;
4 |
5 | import java.util.List;
6 |
7 | public interface PluginInterface extends ExtensionPoint {
8 | String identify();
9 | List> reactiveRoutes();
10 | List mvcControllers();
11 | }
12 |
--------------------------------------------------------------------------------
/shared-interfaces/target/classes/com/curisprofound/plugins/PluginInterface.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/shared-interfaces/target/classes/com/curisprofound/plugins/PluginInterface.class
--------------------------------------------------------------------------------
/shared-interfaces/target/maven-archiver/pom.properties:
--------------------------------------------------------------------------------
1 | #Created by Apache Maven 3.5.3
2 | version=1.1.0
3 | groupId=com.curis-profound
4 | artifactId=shared-plugin-interfaces
5 |
--------------------------------------------------------------------------------
/shared-interfaces/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst:
--------------------------------------------------------------------------------
1 | com/curisprofound/plugins/PluginInterface.class
2 |
--------------------------------------------------------------------------------
/shared-interfaces/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst:
--------------------------------------------------------------------------------
1 | /Users/rezaalemy/Projects/Spring/pf4j-sample/sharedplugininterfaces/src/main/java/com/curisprofound/plugins/PluginInterface.java
2 |
--------------------------------------------------------------------------------
/shared-interfaces/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/shared-interfaces/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
--------------------------------------------------------------------------------
/shared-interfaces/target/shared-plugin-interfaces-1.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/shared-interfaces/target/shared-plugin-interfaces-1.1.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/README.md:
--------------------------------------------------------------------------------
1 | # The plugin-container application
2 |
3 | For the application to support the plugins, we need the pom file to depend at least on PF4J and the shared plugin interfaces. if you are planning to use the slf4j logger, include the slf4j-simple package
4 | as well.
5 |
6 |
7 | ```xml
8 |
9 |
12 | 4.0.0
13 |
14 | com.curisprofound
15 | simple-plugin-container
16 | 1.0-SNAPSHOT
17 |
18 |
19 |
20 |
21 | org.pf4j
22 | pf4j
23 | 2.3.0
24 |
25 |
26 |
27 |
28 | org.slf4j
29 | slf4j-simple
30 | 1.7.5
31 |
32 |
33 |
34 | com.curisprofound
35 | shared-plugin-interfaces
36 | 1.0-SNAPSHOT
37 |
38 |
39 |
40 |
41 | ```
42 | in the build section, the following plugins are included:
43 |
44 | * To compile the classes (using class level 8 to be able to use lambda and other extensions):
45 |
46 | ```xml
47 |
48 | org.apache.maven.plugins
49 | maven-compiler-plugin
50 |
51 | 8
52 | 8
53 |
54 |
55 | ```
56 | * to create an executable jar which looks in lib/ for its dependencies
57 |
58 | ```xml
59 |
60 | org.apache.maven.plugins
61 | maven-jar-plugin
62 | 2.3.1
63 |
64 |
65 |
66 | true
67 | lib/
68 | com.curisprofound.plugins.simple.Container
69 |
70 |
71 |
72 |
73 |
74 | ```
75 |
76 | * to create a zip file that would layout the application correctly, we use the maven assembly plugin:
77 |
78 | ```xml
79 |
80 | maven-assembly-plugin
81 | 2.3
82 |
83 |
84 |
85 | src/main/resources/assembly.xml
86 |
87 |
88 | false
89 |
90 |
91 |
92 | make-assembly
93 | package
94 |
95 | attached
96 |
97 |
98 |
99 |
100 | ```
101 |
102 | The assembly plugin will look in ```src/main/resources/assembly.xml``` to see how to create the zip file for the main application.
103 |
104 | here, we create a lib/ subdirectory and put all the dependencies in it:
105 |
106 | ```xml
107 |
108 |
109 | false
110 | lib
111 |
112 | *:jar:*
113 |
114 |
115 |
116 | ```
117 | we put the executable jar in the root of the unzipped directory and create an empty plugins directory where third party plugins will reside
118 |
119 | ```xml
120 |
121 |
122 | ${project.build.directory}
123 |
124 |
125 | *.jar
126 |
127 |
128 | *-javadoc.jar
129 | *-sources.jar
130 |
131 |
132 |
133 | .
134 | plugins
135 |
136 | */**
137 |
138 |
139 |
140 | ```
141 |
142 | So, our plugin container code requires to create a new PluginManager object,
143 | tell it to load and start plugins and then use it to access the plugins. here
144 | is the minimal code for that:
145 |
146 | ```java
147 | package com.curisprofound.plugins.simple;
148 |
149 |
150 | public class Container {
151 |
152 | private static final Logger log = LoggerFactory.getLogger(Container.class);
153 |
154 | public static void main(String[] args){
155 |
156 | final PluginManager pm = new DefaultPluginManager();
157 | pm.loadPlugins();
158 | pm.startPlugins();
159 |
160 | final List plugins = pm.getExtensions(PluginInterface.class);
161 |
162 | log.info(MessageFormat.format(" {0} Plugin(s) found ", String.valueOf(plugins.size())));
163 |
164 | plugins.forEach(g ->
165 | log.info(MessageFormat.format(" {0}: {1}",
166 | g.getClass().getCanonicalName(),
167 | g.identify())));
168 |
169 | pm.stopPlugins();
170 |
171 | }
172 | }
173 |
174 | ```
175 |
176 | build the project with
177 | ```bash
178 | mvn clean package
179 | ```
180 |
181 | this will create, among other things, a zip file in the target directory.
182 |
183 | ```bash
184 | unzip target/simple-plugin-container-1.0-SNAPSHOT.zip
185 | cd target/simple-plugin-container-1.0-SNAPSHOT
186 | java -jar simple-plugin-container-1.0-SNAPSHOT.jar
187 | ```
188 | The output is as expected for an empty plugins directory
189 |
190 | ```bash
191 | [main] INFO org.pf4j.DefaultPluginStatusProvider - Enabled plugins: []
192 | [main] INFO org.pf4j.DefaultPluginStatusProvider - Disabled plugins: []
193 | [main] INFO org.pf4j.DefaultPluginManager - PF4J version 2.3.0 in 'deployment' mode
194 | [main] INFO org.pf4j.AbstractPluginManager - No plugins
195 | [main] INFO com.curisprofound.plugins.simple.Container - 0 Plugin(s) found
196 | ```
197 |
198 | Once a plugin is created, copy it to the plugin directory. for example, the ```simple-test-plugin``` project will create a ```target/test-plugin-simple-1.0-SNAPSHOT.zip``` when built with ```mvn clean package```. Copy this file to the plugins directory and run the container again to see the plugin discovered and working
199 |
200 | ```bash
201 | $ cd target/simple-plugin-container-1.0-SNAPSHOT
202 | $ cp ../../../simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT.zip ./plugins/
203 | $ java -jar simple-plugin-container-1.0-SNAPSHOT.jar
204 | [main] INFO org.pf4j.DefaultPluginStatusProvider - Enabled plugins: []
205 | [main] INFO org.pf4j.DefaultPluginStatusProvider - Disabled plugins: []
206 | [main] INFO org.pf4j.DefaultPluginManager - PF4J version 2.3.0 in 'deployment' mode
207 | [main] INFO org.pf4j.util.FileUtils - Expanded plugin zip 'test-plugin-simple-1.0-SNAPSHOT.zip' in 'test-plugin-simple-1.0-SNAPSHOT'
208 | [main] INFO org.pf4j.AbstractPluginManager - Plugin 'simple-identity-plugin@0.0.1' resolved
209 | [main] INFO org.pf4j.AbstractPluginManager - Start plugin 'simple-identity-plugin@0.0.1'
210 | [main] INFO com.curisprofound.plugins.simple.SimplePlugin - Simple Plugin Started
211 | [main] INFO com.curisprofound.plugins.simple.Container - 1 Plugin(s) found
212 | [main] INFO com.curisprofound.plugins.simple.Container - com.curisprofound.plugins.simple.SimplePlugin.SimpleIdentityPlugin: A simple plugin with no dependency on Spring
213 | [main] INFO org.pf4j.AbstractPluginManager - Stop plugin 'simple-identity-plugin@0.0.1'
214 | [main] INFO com.curisprofound.plugins.simple.SimplePlugin - Simple Plugin Stopped
215 |
216 | ```
217 |
218 | [Back to Contents](../#contents)
219 |
220 |
221 | [PF4J]: https://github.com/pf4j/pf4j
222 |
223 |
--------------------------------------------------------------------------------
/simple-plugin-container/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.curisprofound
8 | simple-plugin-container
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 | org.pf4j
15 | pf4j
16 | 2.3.0
17 |
18 |
19 |
20 |
21 | org.slf4j
22 | slf4j-simple
23 | 1.7.5
24 |
25 |
26 |
27 | com.curisprofound
28 | shared-plugin-interfaces
29 | 1.1.0
30 |
31 |
32 |
33 |
34 |
35 |
36 | maven-assembly-plugin
37 | 2.3
38 |
39 |
40 |
41 | src/main/resources/assembly.xml
42 |
43 |
44 | false
45 |
46 |
47 |
48 | make-assembly
49 | package
50 |
51 | attached
52 |
53 |
54 |
55 |
56 |
57 |
58 | org.apache.maven.plugins
59 | maven-jar-plugin
60 | 2.3.1
61 |
62 |
63 |
64 | true
65 | lib/
66 | com.curisprofound.plugins.simple.Container
67 |
68 |
69 |
70 |
71 |
72 |
73 | maven-deploy-plugin
74 |
75 | true
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-compiler-plugin
81 |
82 | 8
83 | 8
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/main/java/com/curisprofound/plugins/simple/Container.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.plugins.simple;
2 |
3 | import com.curisprofound.plugins.PluginInterface;
4 | import org.pf4j.DefaultPluginManager;
5 | import org.pf4j.PluginManager;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.text.MessageFormat;
10 | import java.util.List;
11 |
12 | public class Container {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(Container.class);
15 |
16 | public static void main(String[] args){
17 | final PluginManager pm = new DefaultPluginManager();
18 |
19 | pm.loadPlugins();
20 |
21 | pm.startPlugins();
22 |
23 | final List plugins = pm.getExtensions(PluginInterface.class);
24 |
25 | log.info(MessageFormat.format(" {0} Plugin(s) found ", String.valueOf(plugins.size())));
26 |
27 | plugins.forEach(g ->
28 | log.info(MessageFormat.format(" {0}: {1}",
29 | g.getClass().getCanonicalName(),
30 | g.identify())));
31 |
32 | pm.stopPlugins();
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/main/resources/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | app
9 |
10 | dir
11 | zip
12 |
13 | false
14 |
15 |
16 | false
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 |
23 |
24 |
25 | ${project.build.directory}
26 |
27 |
28 | *.jar
29 |
30 |
31 | *-javadoc.jar
32 | *-sources.jar
33 |
34 |
35 |
36 | .
37 | plugins
38 |
39 | */**
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/lib/shared-plugin-interface-1.0-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/lib/shared-plugin-interface-1.0-SNAPSHOT.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/lib/slf4j-api-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/lib/slf4j-api-1.7.5.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/lib/slf4j-simple-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/lib/slf4j-simple-1.7.5.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT.zip
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Plugin-Dependencies:
3 | Plugin-Id: simple-hello-plugin
4 | Archiver-Version: Plexus Archiver
5 | Built-By: rezaalemy
6 | Plugin-Provider: Curis Profound
7 | Plugin-Version: 0.0.1
8 | Plugin-Class: com.curisprofound.plugins.simple.HelloPlugin
9 | Created-By: Apache Maven 3.5.3
10 | Build-Jdk: 1.8.0_161
11 |
12 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/extensions.idx:
--------------------------------------------------------------------------------
1 | # Generated by PF4J
2 | com.curisprofound.plugins.simple.HelloPlugin$HelloGreeting
3 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/maven/com.curisprofound/test-plugin-simple/pom.properties:
--------------------------------------------------------------------------------
1 | #Generated by Maven
2 | #Wed Jul 25 15:02:13 PDT 2018
3 | version=1.0-SNAPSHOT
4 | groupId=com.curisprofound
5 | artifactId=test-plugin-simple
6 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/maven/com.curisprofound/test-plugin-simple/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.curisprofound
8 | test-plugin-simple
9 | 1.0-SNAPSHOT
10 | Simple Test Plugin
11 | jar
12 |
13 |
14 | simple-hello-plugin
15 | com.curisprofound.plugins.simple.HelloPlugin
16 | 0.0.1
17 | Curis Profound
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.pf4j
25 | pf4j
26 | 2.3.0
27 |
28 |
29 | com.curisprofound
30 | shared-plugin-interface
31 | 1.0-SNAPSHOT
32 |
33 |
34 |
35 |
36 |
37 |
38 | org.apache.maven.plugins
39 | maven-antrun-plugin
40 | 1.6
41 |
42 |
43 | unzip jar file
44 | package
45 |
46 |
47 |
48 |
49 |
50 |
51 | run
52 |
53 |
54 |
55 |
56 |
57 |
58 | maven-assembly-plugin
59 | 2.3
60 |
61 |
62 |
63 | src/main/resources/assembly.xml
64 |
65 |
66 | false
67 |
68 |
69 |
70 | make-assembly
71 | package
72 |
73 | attached
74 |
75 |
76 |
77 |
78 |
79 |
80 | org.apache.maven.plugins
81 | maven-jar-plugin
82 | 2.4
83 |
84 |
85 |
86 | ${plugin.id}
87 | ${plugin.class}
88 | ${plugin.version}
89 | ${plugin.provider}
90 | ${plugin.dependencies}
91 |
92 |
93 |
94 |
95 |
96 |
97 | maven-deploy-plugin
98 |
99 | true
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 | org.slf4j:*
23 | com.curisprofound:shared-plugin-interface
24 |
25 |
26 |
27 |
28 |
29 | target/plugin-classes
30 | classes
31 |
32 |
33 | src/main/resources
34 |
35 |
36 | plugin.properties
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/HelloPlugin$HelloGreeting.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/HelloPlugin$HelloGreeting.class
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/HelloPlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/HelloPlugin.class
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-hello-plugin
2 | plugin.class=com.curisprofound.plugins.simple.HelloPlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/plugins/test-plugin-simple-1.0-SNAPSHOT/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-hello-plugin
2 | plugin.class=com.curisprofound.plugins.simple.HelloPlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/simple-plugin-container-1.0-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/simple-plugin-container-1.0-SNAPSHOT.jar
--------------------------------------------------------------------------------
/simple-plugin-container/src/test/simple-plugin-container-1.0-SNAPSHOT.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/src/test/simple-plugin-container-1.0-SNAPSHOT.zip
--------------------------------------------------------------------------------
/simple-plugin-container/target/classes/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | app
9 |
10 | dir
11 | zip
12 |
13 | false
14 |
15 |
16 | false
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 |
23 |
24 |
25 | ${project.build.directory}
26 |
27 |
28 | *.jar
29 |
30 |
31 | *-javadoc.jar
32 | *-sources.jar
33 |
34 |
35 |
36 | .
37 | plugins
38 |
39 | */**
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/classes/com/curisprofound/plugins/simple/Container.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/classes/com/curisprofound/plugins/simple/Container.class
--------------------------------------------------------------------------------
/simple-plugin-container/target/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/lib/shared-plugin-interfaces-1.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/lib/shared-plugin-interfaces-1.1.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/lib/slf4j-api-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/lib/slf4j-api-1.7.5.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/lib/slf4j-simple-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/lib/slf4j-simple-1.7.5.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/maven-archiver/pom.properties:
--------------------------------------------------------------------------------
1 | #Generated by Maven
2 | #Sun Jul 29 01:20:49 PDT 2018
3 | version=1.0-SNAPSHOT
4 | groupId=com.curisprofound
5 | artifactId=simple-plugin-container
6 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst:
--------------------------------------------------------------------------------
1 | com/curisprofound/plugins/simple/Container.class
2 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst:
--------------------------------------------------------------------------------
1 | /Users/rezaalemy/Projects/Spring/pf4j-sample/simple-plugin-container/src/main/java/com/curisprofound/plugins/simple/Container.java
2 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT.zip
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/extensions.idx:
--------------------------------------------------------------------------------
1 | # Generated by PF4J
2 | com.curisprofound.plugins.simple.SimplePlugin$SimpleIdentityPlugin
3 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 | org.slf4j:*
23 | com.curisprofound:*
24 |
25 |
26 |
27 |
28 |
29 | target/classes
30 | classes
31 |
32 |
33 | src/main/resources
34 |
35 |
36 | plugin.properties
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin.class
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/plugins/test-plugin-simple-1.0-SNAPSHOT/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT.zip
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/shared-plugin-interfaces-1.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/shared-plugin-interfaces-1.1.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/slf4j-api-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/slf4j-api-1.7.5.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/slf4j-simple-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/lib/slf4j-simple-1.7.5.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT.zip
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/extensions.idx:
--------------------------------------------------------------------------------
1 | # Generated by PF4J
2 | com.curisprofound.plugins.simple.SimplePlugin$SimpleIdentityPlugin
3 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 | org.slf4j:*
23 | com.curisprofound:*
24 |
25 |
26 |
27 |
28 |
29 | target/classes
30 | classes
31 |
32 |
33 | src/main/resources
34 |
35 |
36 | plugin.properties
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin.class
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/classes/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/plugins/test-plugin-simple-1.0-SNAPSHOT/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/simple-plugin-container-1.0-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-plugin-container/target/simple-plugin-container-1.0-SNAPSHOT/simple-plugin-container-1.0-SNAPSHOT.jar
--------------------------------------------------------------------------------
/simple-test-plugin/README.md:
--------------------------------------------------------------------------------
1 | ## Simple Plugin
2 |
3 | A plugin is packaged as a zip or jar file and is put in a directory for the container to scan, decompress and use. the POM file for the plugin shall contain dependenceis required to compile it as well as the information that needs to go into the manifest.
4 |
5 | Minimum dependencies include the PF4J and the shared interfaces.
6 |
7 | ```xml
8 |
9 |
10 | org.pf4j
11 | pf4j
12 | 2.3.0
13 |
14 |
15 | com.curisprofound
16 | shared-plugin-interfaces
17 | 1.1.0
18 |
19 |
20 | ```
21 |
22 | We also need to configure maven-jar-plugin to add plugin information to manifest:
23 |
24 |
25 | ```xml
26 | ....
27 |
28 | simple-hello-plugin
29 | com.curisprofound.plugins.simple.HelloPlugin
30 | 0.0.1
31 | Curis Profound
32 |
33 |
34 |
35 | ....
36 | ....
37 |
38 |
39 | org.apache.maven.plugins
40 | maven-jar-plugin
41 | 2.4
42 |
43 |
44 |
45 | ${plugin.id}
46 | ${plugin.class}
47 | ${plugin.version}
48 | ${plugin.provider}
49 | ${plugin.dependencies}
50 |
51 |
52 |
53 |
54 |
55 | ```
56 |
57 | To create the zip file, maven-assembly-plugin is used. this plugin is configured
58 | to read ```src/main/resources/assembly.xml``` file for instructions on how
59 | to create the zip file.
60 |
61 | The most important point on creating the assembly file is to ensure that it does not include dependencies that are shared between the plugin and the container or other plugins. for example, the ```slf4j``` or the shared interfaces should not be included in the plugin zip file as they will be included in the container dependencies.
62 |
63 | * we exclude the dependencies that are already declared in the container
64 |
65 | ```xml
66 |
67 |
68 | false
69 | runtime
70 | lib
71 |
72 | *:jar:*
73 |
74 |
75 | org.slf4j:*
76 | com.curisprofound:shared-plugin-interface
77 |
78 |
79 |
80 | ```
81 |
82 | * we include the classes, not the jar file, because the unzipped directory is not in the classpath
83 |
84 | ```xml
85 |
86 | target/classes
87 | classes
88 |
89 | ```
90 |
91 | * we include a plugin.properties file in the root of the zip file
92 |
93 | ```xml
94 |
95 | src/main/resources
96 |
97 |
98 | plugin.properties
99 |
100 |
101 | ```
102 |
103 | this just includes the properties we added to the manifest above
104 |
105 | ```
106 | plugin.id=simple-hello-plugin
107 | plugin.class=com.curisprofound.plugins.simple.HelloPlugin
108 | plugin.version=0.0.1
109 | plugin.provider=Curis Profound
110 | plugin.dependencies=
111 | ```
112 |
113 | ## The plugin code
114 |
115 | the actual plugin now can implement extension points and override start and stop hooks:
116 |
117 | ```java
118 | package com.curisprofound.plugins.simple;
119 |
120 | public class SimplePlugin extends Plugin {
121 |
122 | private static Logger log = LoggerFactory.getLogger(SimplePlugin.class);
123 |
124 | public SimplePlugin(PluginWrapper wrapper) {
125 | super(wrapper);
126 | }
127 |
128 | @Override
129 | public void start(){
130 | log.info("Simple Plugin Started");
131 | }
132 |
133 | @Override
134 | public void stop(){
135 | log.info("Simple Plugin Stopped");
136 | }
137 |
138 | @Extension
139 | public static class SimpleIdentityPlugin implements PluginInterface {
140 |
141 | public String identify() {
142 | return "A simple plugin with no dependency on Spring";
143 | }
144 |
145 | @Override
146 | public List> reactiveRoutes() {
147 | return new ArrayList<>();
148 | }
149 |
150 | @Override
151 | public List mvcControllers() {
152 | return new ArrayList<>();
153 | }
154 | }
155 | }
156 | ```
157 | Notice that the plugin returns empty lists (not null) for methods that it won't implement. this is a good idea to return the empty version of the object instead of null and avoid ```NullPointerException``` messsages.
158 |
159 |
160 | building the project with ```mvn clean package``` will create a zip file in the
161 | ```target``` directory. in the future steps we will move this zip file into the plugins directory and run it through the container.
162 |
163 | [Back to Contents](../#contents)
164 |
165 | [PF4J]: https://github.com/pf4j/pf4j
166 |
167 |
--------------------------------------------------------------------------------
/simple-test-plugin/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.curisprofound
8 | test-plugin-simple
9 | 1.0-SNAPSHOT
10 | Simple Test Plugin
11 | jar
12 |
13 |
14 | simple-hello-plugin
15 | com.curisprofound.plugins.simple.SimplePlugin
16 | 0.0.1
17 | Curis Profound
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.pf4j
25 | pf4j
26 | 2.3.0
27 |
28 |
29 | com.curisprofound
30 | shared-plugin-interfaces
31 | 1.1.0
32 |
33 |
34 |
35 |
36 |
37 |
38 | maven-assembly-plugin
39 | 2.3
40 |
41 |
42 |
43 | src/main/resources/assembly.xml
44 |
45 |
46 | false
47 |
48 |
49 |
50 | make-assembly
51 | package
52 |
53 | attached
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-jar-plugin
62 | 2.4
63 |
64 |
65 |
66 | ${plugin.id}
67 | ${plugin.class}
68 | ${plugin.version}
69 | ${plugin.provider}
70 | ${plugin.dependencies}
71 |
72 |
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-compiler-plugin
78 |
79 | 8
80 | 8
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/simple-test-plugin/src/main/java/com/curisprofound/plugins/simple/SimplePlugin.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.plugins.simple;
2 |
3 | import com.curisprofound.plugins.PluginInterface;
4 | import org.pf4j.Extension;
5 | import org.pf4j.Plugin;
6 | import org.pf4j.PluginWrapper;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class SimplePlugin extends Plugin {
14 |
15 | private static Logger log = LoggerFactory.getLogger(com.curisprofound.plugins.simple.SimplePlugin.class);
16 |
17 | public SimplePlugin(PluginWrapper wrapper) {
18 | super(wrapper);
19 | }
20 |
21 | @Override
22 | public void start(){
23 | log.info("Simple Plugin Started");
24 | }
25 | @Override
26 | public void stop(){
27 | log.info("Simple Plugin Stopped");
28 | }
29 |
30 | @Extension
31 | public static class SimpleIdentityPlugin implements PluginInterface {
32 |
33 | public String identify() {
34 | return "A simple plugin with no dependency on Spring";
35 | }
36 |
37 | @Override
38 | public List> reactiveRoutes() {
39 | return new ArrayList<>();
40 | }
41 |
42 | @Override
43 | public List mvcControllers() {
44 | return new ArrayList<>();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/simple-test-plugin/src/main/resources/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 | org.slf4j:*
23 | com.curisprofound:*
24 |
25 |
26 |
27 |
28 |
29 | target/classes
30 | classes
31 |
32 |
33 | src/main/resources
34 |
35 |
36 | plugin.properties
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/simple-test-plugin/src/main/resources/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/classes/META-INF/extensions.idx:
--------------------------------------------------------------------------------
1 | # Generated by PF4J
2 | com.curisprofound.plugins.simple.SimplePlugin$SimpleIdentityPlugin
3 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/classes/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 | org.slf4j:*
23 | com.curisprofound:*
24 |
25 |
26 |
27 |
28 |
29 | target/classes
30 | classes
31 |
32 |
33 | src/main/resources
34 |
35 |
36 | plugin.properties
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class
--------------------------------------------------------------------------------
/simple-test-plugin/target/classes/com/curisprofound/plugins/simple/SimplePlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/classes/com/curisprofound/plugins/simple/SimplePlugin.class
--------------------------------------------------------------------------------
/simple-test-plugin/target/classes/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/maven-archiver/pom.properties:
--------------------------------------------------------------------------------
1 | #Generated by Maven
2 | #Sun Jul 29 00:52:20 PDT 2018
3 | version=1.0-SNAPSHOT
4 | groupId=com.curisprofound
5 | artifactId=test-plugin-simple
6 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst:
--------------------------------------------------------------------------------
1 | com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class
2 | META-INF/extensions.idx
3 | com/curisprofound/plugins/simple/SimplePlugin.class
4 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst:
--------------------------------------------------------------------------------
1 | /Users/rezaalemy/Projects/Spring/pf4j-sample/simple-test-plugin/src/main/java/com/curisprofound/plugins/simple/SimplePlugin.java
2 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT.jar
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT.zip
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/META-INF/extensions.idx:
--------------------------------------------------------------------------------
1 | # Generated by PF4J
2 | com.curisprofound.plugins.simple.SimplePlugin$SimpleIdentityPlugin
3 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | *:jar:*
20 |
21 |
22 | org.slf4j:*
23 | com.curisprofound:*
24 |
25 |
26 |
27 |
28 |
29 | target/classes
30 | classes
31 |
32 |
33 | src/main/resources
34 |
35 |
36 | plugin.properties
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin$SimpleIdentityPlugin.class
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/com/curisprofound/plugins/simple/SimplePlugin.class
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/classes/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/lib/java-semver-0.9.0.jar
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/lib/pf4j-2.3.0.jar
--------------------------------------------------------------------------------
/simple-test-plugin/target/test-plugin-simple-1.0-SNAPSHOT/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=simple-identity-plugin
2 | plugin.class=com.curisprofound.plugins.simple.SimplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
7 |
--------------------------------------------------------------------------------
/spring-plugin-container/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 | .sts4-cache
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 | /plugins/
19 | .mvn
20 |
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /build/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
--------------------------------------------------------------------------------
/spring-plugin-container/README.md:
--------------------------------------------------------------------------------
1 | # Spring boot app as plugin container
2 |
3 | Using [PF4J-Spring]() package, it is rather straight-forward to add plugin support to an existing application. once more, the pom file needs to declare
4 | dependencies on ```pf4j-spring``` and the shared interfaces
5 |
6 | ```xml
7 |
8 | org.pf4j
9 | pf4j-spring
10 | 0.4.0
11 |
12 |
13 |
14 | com.curisprofound
15 | shared-plugin-interfaces
16 | 1.1.0
17 |
18 | ```
19 |
20 | the build section does not need to change, except if you decide to have an external directory added to the classpath, which comes in handy when resolving dependencies
21 |
22 | ```xml
23 |
24 | org.springframework.boot
25 | spring-boot-maven-plugin
26 |
27 |
28 | ./lib/
29 |
30 |
31 |
32 | ```
33 |
34 | The application needs to add a Singleton for ```PluginManager``` to the dependency injection platform. this can be done alongside other configuration
35 |
36 | ```java
37 | @Configuration
38 | public class AppConfig {
39 |
40 | @Bean
41 | public SpringPluginManager pluginManager() {
42 | return new SpringPluginManager();
43 | }
44 |
45 | @Bean
46 | public RouterFunction route() {
47 | String message = "Reactive endpoint on contaainer";
48 | return RouterFunctions.route(
49 | GET("/hello")
50 | .and(accept(MediaType.TEXT_PLAIN)),
51 | req -> ServerResponse
52 | .ok()
53 | .body(Mono.just(message), String.class));
54 | }
55 | }
56 | ```
57 |
58 | The above config also adds a ```/hello``` endpoint to show a use case of the container having its own endpoints.
59 |
60 | # Configuring the Plugin
61 |
62 | The plugin configuration is done through a class extending ```BeanFactoryAware``` and annotated with ```@Configuration```.
63 |
64 | ```java
65 | @Configuration
66 | public class PluginConfig implements BeanFactoryAware {
67 |
68 |
69 | private final SpringPluginManager pluginManager;
70 | private final ApplicationContext applicationContext;
71 | private final ObjectMapper objectMapper;
72 | private BeanFactory beanFactory;
73 |
74 | @Autowired
75 | public PluginConfig(SpringPluginManager pm, ApplicationContext applicationContext) {
76 | this.pluginManager = pm;
77 | this.applicationContext = applicationContext;
78 | this.objectMapper = new ObjectMapper();
79 | }
80 |
81 | @Override
82 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
83 | this.beanFactory = beanFactory;
84 | }
85 |
86 | @Bean
87 | @DependsOn("pluginManager")
88 | public RouterFunction> pluginEndpoints(PluginManager pm) {
89 | registerMvcEndpoints(pm);
90 | return getReactiveRoutes(pm);
91 | }
92 | ...
93 | ...
94 | @PreDestroy
95 | public void cleanup() {
96 | pluginManager.stopPlugins();
97 | }
98 | ```
99 |
100 | The PluginManager and the ApplicationContext are auto-wired to this class, and a BeanFactory is obtained by the ```setBeanFactory``` method getting called at the initialization of the class. It is important to have a ```@PreDestroy``` annotated method to stop the plugins on plugin manager.
101 |
102 | This class returns a Bean that registers the MVC and reactive endpoints the plugin provides. registering the MVC endpoints is done in two steps, first we add each endpoint as a singleton using the bean factory, then we call the ```afterPropertiesSet()``` method on ```RequestMappingHandlerMapping``` classes to map them to the correct endpoints:
103 |
104 | ```java
105 | private void registerMvcEndpoints(PluginManager pm) {
106 | pm.getExtensions(PluginInterface.class).stream()
107 | .flatMap(g -> g.mvcControllers().stream())
108 | .forEach(r -> ((ConfigurableBeanFactory) beanFactory)
109 | .registerSingleton(r.getClass().getName(), r));
110 | applicationContext
111 | .getBeansOfType(RequestMappingHandlerMapping.class)
112 | .forEach((k, v) -> v.afterPropertiesSet());
113 | }
114 | ```
115 |
116 | We use another approach for the reactive endpoints. here we provide a base, which allows the user to see which plugins are in the system:
117 |
118 | ```java
119 | private RouterFunction> baseRoot(PluginManager pm) {
120 | return route(GET("/plugins"),
121 | req -> ServerResponse.ok().body(Mono.just(pluginNamesMono(pm)), String.class));
122 | }
123 |
124 | private String pluginNamesMono(PluginManager pm) {
125 | try {
126 | List identityList = pm
127 | .getExtensions(PluginInterface.class).stream()
128 | .map(g-> g.getClass().getName() + ": " + g.identify())
129 | .collect(Collectors.toList());
130 | return objectMapper.writeValueAsString(identityList);
131 | } catch (JsonProcessingException e) {
132 | return "[]";
133 | }
134 | }
135 |
136 | ```
137 |
138 | to this base we add all if any router functions returned by plugins:
139 |
140 | ```java
141 | private RouterFunction> getReactiveRoutes(PluginManager pm) {
142 | RouterFunction> base = baseRoot(pm);
143 | RouterFunction> routes = pm
144 | .getExtensions(PluginInterface.class).stream()
145 | .flatMap(g -> g.reactiveRoutes().stream())
146 | .map(r-> (RouterFunction)r)
147 | .reduce((o,r )-> (RouterFunction) o.andOther(r))
148 | .orElse(null);
149 | return routes == null ? base : base.andOther(routes);
150 | }
151 | ```
152 |
153 | Once the application starts, it looks under the current directory for a directory called plugins to scan for the plugins. Consult the [PF4J Documentation][] on how to specify a location using environment variables.
154 |
155 | Once the zip files of the simple and spring plugin samples are in the plugins directory, here is the output the application confirms the correct discovery and installation of plugins and endpoints:
156 |
157 | ```bash
158 | $ java -jar target/spring-plugin-container-0.0.1-SNAPSHOT.jar
159 | ....
160 | ....
161 | Enabled plugins: []
162 | Disabled plugins: []
163 | PF4J version 2.0.0 in 'deployment' mode
164 | Plugin 'spring-sample-plugin@0.0.1' resolved
165 | Plugin 'simple-identity-plugin@0.0.1' resolved
166 | Start plugin 'spring-sample-plugin@0.0.1'
167 | Spring Sample plugin.start()
168 | Start plugin 'simple-identity-plugin@0.0.1'
169 | Simple Plugin Started
170 | Mapped "{[/plugin-mvc-controller],methods=[GET]}" onto public org.springframework.http.ResponseEntity com.curisprofound.springtestplugin.PluginController.greetMVC()
171 | Mapped (GET && /plugins) -> com.curisprofound.springplugincontainer.PluginConfig$$Lambda$238/90205195@1c72da34
172 | (GET && /plugin-end-point) -> com.curisprofound.springtestplugin.SpringSamplePlugin$SpringPlugin$2$$Lambda$243/280265505@6b0c2d26
173 | Mapped ((GET && /hello) && Accept: [text/plain]) -> com.curisprofound.springplugincontainer.AppConfig$$Lambda$244/1161667116@6e38921c
174 | Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
175 | Mapped URL path [/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
176 | Registering beans for JMX exposure on startup
177 | Started HttpServer on /0:0:0:0:0:0:0:0:8080
178 | Netty started on port(s): 8080
179 | Started SpringPluginContainerApplication in 2.71 seconds (JVM running for 3.192)
180 | Number of plugins found: 2
181 | com.curisprofound.plugins.simple.SimplePlugin$SimpleIdentityPlugin:A simple plugin with no dependency on Spring
182 | com.curisprofound.springtestplugin.SpringSamplePlugin$SpringPlugin:A plugin using Spring framework
183 | ```
184 |
185 | the /plugins will return
186 |
187 | ```json
188 | [
189 | "com.curisprofound.plugins.simple.SimplePlugin$SimpleIdentityPlugin: A simple plugin with no dependency on Spring",
190 | "com.curisprofound.springtestplugin.SpringSamplePlugin$SpringPlugin: A plugin using Spring framework"
191 | ]
192 | ```
193 |
194 | here is the return value for the rest of the endpoints
195 |
196 | |Endpoint| Returns|
197 | |--------|--------|
198 | |/hello| Reactive endpoint on contaainer|
199 | |/plugin-mvc-controller| An endpoint defined by annotation in plugin|
200 | |/plugin-end-point| reactive router endpoint|
201 |
202 |
203 | [Back to Contents](../#contents)
204 |
205 | [PF4J Documentation]:https://pf4j.org/
206 |
--------------------------------------------------------------------------------
/spring-plugin-container/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/spring-plugin-container/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/spring-plugin-container/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.curisprofound
7 | spring-plugin-container
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | spring-plugin-container
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 2.0.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-webflux
31 |
32 |
33 |
34 |
35 | org.pf4j
36 | pf4j-spring
37 | 0.4.0
38 |
39 |
40 |
41 | com.curisprofound
42 | shared-plugin-interfaces
43 | 1.1.0
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 | test
51 |
52 |
53 | io.projectreactor
54 | reactor-test
55 | test
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-maven-plugin
64 |
65 |
66 | ./lib/
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/spring-plugin-container/src/main/java/com/curisprofound/springplugincontainer/AppConfig.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springplugincontainer;
2 |
3 | import org.pf4j.spring.SpringPluginManager;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.http.MediaType;
7 | import org.springframework.web.reactive.function.server.RouterFunction;
8 | import org.springframework.web.reactive.function.server.RouterFunctions;
9 | import org.springframework.web.reactive.function.server.ServerResponse;
10 | import reactor.core.publisher.Mono;
11 |
12 | import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
13 | import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
14 |
15 | @Configuration
16 | public class AppConfig {
17 | @Bean
18 | public SpringPluginManager pluginManager() {
19 | return new SpringPluginManager();
20 | }
21 |
22 | @Bean
23 | public RouterFunction route() {
24 | return RouterFunctions.route(GET("/hello")
25 | .and(accept(MediaType.TEXT_PLAIN)),
26 | req -> ServerResponse.ok().body(Mono.just("Reactive endpoint on contaainer"), String.class));
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/spring-plugin-container/src/main/java/com/curisprofound/springplugincontainer/PluginConfig.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springplugincontainer;
2 |
3 | import com.curisprofound.plugins.PluginInterface;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.pf4j.PluginManager;
7 | import org.pf4j.spring.SpringPluginManager;
8 | import org.springframework.beans.BeansException;
9 | import org.springframework.beans.factory.BeanFactory;
10 | import org.springframework.beans.factory.BeanFactoryAware;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
13 | import org.springframework.context.ApplicationContext;
14 | import org.springframework.context.annotation.Bean;
15 | import org.springframework.context.annotation.Configuration;
16 | import org.springframework.context.annotation.DependsOn;
17 | import org.springframework.web.reactive.function.server.RouterFunction;
18 | import org.springframework.web.reactive.function.server.ServerResponse;
19 | import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
20 | import reactor.core.publisher.Mono;
21 |
22 | import javax.annotation.PreDestroy;
23 | import java.util.List;
24 | import java.util.stream.Collectors;
25 |
26 | import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
27 | import static org.springframework.web.reactive.function.server.RouterFunctions.route;
28 |
29 | @Configuration
30 | public class PluginConfig implements BeanFactoryAware {
31 |
32 |
33 | private final SpringPluginManager pluginManager;
34 | private final ApplicationContext applicationContext;
35 | private final ObjectMapper objectMapper;
36 | private BeanFactory beanFactory;
37 |
38 | @Autowired
39 | public PluginConfig(SpringPluginManager pm, ApplicationContext applicationContext) {
40 | this.pluginManager = pm;
41 | this.applicationContext = applicationContext;
42 | this.objectMapper = new ObjectMapper();
43 | }
44 |
45 | @Override
46 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
47 | this.beanFactory = beanFactory;
48 | }
49 |
50 | @Bean
51 | @DependsOn("pluginManager")
52 | public RouterFunction> pluginEndpoints(PluginManager pm) {
53 | registerMvcEndpoints(pm);
54 | return getReactiveRoutes(pm);
55 | }
56 |
57 | private RouterFunction> getReactiveRoutes(PluginManager pm) {
58 | RouterFunction> base = baseRoot(pm);
59 | RouterFunction> routes = pm.getExtensions(PluginInterface.class).stream()
60 | .flatMap(g -> g.reactiveRoutes().stream())
61 | .map(r-> (RouterFunction)r)
62 | .reduce((o,r )-> (RouterFunction) o.andOther(r))
63 | .orElse(null);
64 | return routes == null ? base : base.andOther(routes);
65 | }
66 |
67 | private RouterFunction> baseRoot(PluginManager pm) {
68 | return route(GET("/plugins"),
69 | req -> ServerResponse.ok().body(Mono.just(pluginNamesMono(pm)), String.class));
70 | }
71 |
72 | private String pluginNamesMono(PluginManager pm) {
73 | List identityList = pm.getExtensions(PluginInterface.class).stream()
74 | .map(g-> g.getClass().getName() + ": " + g.identify())
75 | .collect(Collectors.toList());
76 | try {
77 | return objectMapper.writeValueAsString(identityList);
78 | } catch (JsonProcessingException e) {
79 | return "[]";
80 | }
81 | }
82 |
83 |
84 | private void registerMvcEndpoints(PluginManager pm) {
85 | pm.getExtensions(PluginInterface.class).stream()
86 | .flatMap(g -> g.mvcControllers().stream())
87 | .forEach(r -> ((ConfigurableBeanFactory) beanFactory)
88 | .registerSingleton(r.getClass().getName(), r));
89 | applicationContext
90 | .getBeansOfType(RequestMappingHandlerMapping.class)
91 | .forEach((k, v) -> v.afterPropertiesSet());
92 | }
93 |
94 |
95 | @PreDestroy
96 | public void cleanup() {
97 | pluginManager.stopPlugins();
98 | }
99 |
100 | }
--------------------------------------------------------------------------------
/spring-plugin-container/src/main/java/com/curisprofound/springplugincontainer/SpringPluginContainerApplication.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springplugincontainer;
2 |
3 | import com.curisprofound.plugins.PluginInterface;
4 | import org.pf4j.spring.SpringPluginManager;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.boot.ApplicationArguments;
9 | import org.springframework.boot.ApplicationRunner;
10 | import org.springframework.boot.SpringApplication;
11 | import org.springframework.boot.autoconfigure.SpringBootApplication;
12 | import org.springframework.context.annotation.Bean;
13 |
14 | import java.util.List;
15 |
16 | @SpringBootApplication
17 | public class SpringPluginContainerApplication {
18 |
19 | private static Logger log = LoggerFactory.getLogger(SpringPluginContainerApplication.class);
20 |
21 | public static void main(String[] args) {
22 | SpringApplication.run(SpringPluginContainerApplication.class, args);
23 | }
24 |
25 | @Bean
26 | public ApplicationRunner run() {
27 | return new ApplicationRunner() {
28 |
29 | @Autowired
30 | private SpringPluginManager springPluginManager;
31 |
32 | @Override
33 | public void run(ApplicationArguments args) throws Exception {
34 | List plugins = springPluginManager.getExtensions(PluginInterface.class);
35 | log.info(String.format("Number of plugins found: %d", plugins.size()));
36 | plugins.forEach(c -> log.info(c.getClass().getName() + ":" + c.identify()));
37 | }
38 | };
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/spring-plugin-container/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/spring-plugin-container/src/main/resources/application.properties
--------------------------------------------------------------------------------
/spring-plugin-container/src/test/java/com/curisprofound/springplugincontainer/SpringPluginContainerApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springplugincontainer;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class SpringPluginContainerApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/spring-test-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 | .sts4-cache
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 |
19 | ### NetBeans ###
20 | /nbproject/private/
21 | /build/
22 | /nbbuild/
23 | /dist/
24 | /nbdist/
25 | /.nb-gradle/
--------------------------------------------------------------------------------
/spring-test-plugin/README.md:
--------------------------------------------------------------------------------
1 | # Spring-enabled plugins
2 |
3 | Developing plugins as Spring boot applications has a number of advantages, including the utility of
4 | Spring functionality, Dependency injection and auto-wiring, reactive libraries, etc.
5 |
6 | Plugins should also be able to define new endpoints in the container, whether the old-style annotated
7 | controllers or the new ```RouterFunction``` style for reactive endpoints.
8 |
9 | ## Pom file
10 |
11 | The pom file needs to include the shared interface and the [pf4j-spring](https://github.com/pf4j/pf4j-spring) package as dependencies.
12 | The rest of the dependencies would be the same that the Spring boot application would have required
13 | in standalone mode.
14 |
15 | The build section needs to be customized to create the correct plugin structure.
16 |
17 | * The ant-run plugin opens the jar and puts the classes in a separate directory
18 |
19 | ```xml
20 |
21 | org.apache.maven.plugins
22 | maven-antrun-plugin
23 | 1.6
24 |
25 |
26 | unzip jar file
27 | package
28 |
29 |
30 |
32 |
33 |
34 |
35 | run
36 |
37 |
38 |
39 |
40 | ```
41 |
42 | * The jar plugin sets the parameters for Manifest file
43 |
44 | ```xml
45 |
46 | org.apache.maven.plugins
47 | maven-jar-plugin
48 | 2.4
49 |
50 |
51 |
52 | ${plugin.id}
53 | ${plugin.class}
54 | ${plugin.version}
55 | ${plugin.provider}
56 | ${plugin.dependencies}
57 |
58 |
59 |
60 |
61 | ```
62 |
63 | * The maven-assemply-plugin uses the ```src/main/resources/assembly.xml``` to create the zip file
64 |
65 | The ```assembly.xml``` file needs to exclude any packages used by the container,
66 | and put the ```plugin.properties``` file in the root directory.
67 |
68 | ```xml
69 |
70 | plugin
71 |
72 | zip
73 |
74 | false
75 |
76 |
77 | false
78 | runtime
79 | lib
80 |
81 | org.pf4j:*
82 |
83 |
84 | org.springframework:*
85 | org.slf4j:*
86 | com.curisprofound:shared-plugin-interfaces
87 |
88 |
89 |
90 |
91 |
92 | target/plugin-classes
93 | classes
94 |
95 |
96 | src/main/resources
97 |
98 |
99 | plugin.properties
100 |
101 |
102 |
103 |
104 | ```
105 |
106 | # Configuration
107 |
108 | Using the ```@Configuration``` annotation, a class would be marked as configuration and can provide beans for later auto-wiring
109 |
110 | ```java
111 | //in GreetProvider.java
112 |
113 | public class GreetProvider {
114 | public String provide(){
115 | return "A plugin using Spring framework";
116 | }
117 | }
118 |
119 | //in ApplicationConfiguration.java
120 | @Configuration
121 | public class ApplicationConfiguration {
122 | @Bean
123 | public GreetProvider greetProvider(){
124 | return new GreetProvider();
125 | }
126 | }
127 | ```
128 |
129 | Restful endpoints can be created in annotated classes
130 |
131 | ```java
132 | @Controller
133 | @RequestMapping("/plugin-mvc-controller")
134 | public class PluginController {
135 | @GetMapping
136 | public ResponseEntity greetMVC(){
137 | String message = "An endpoint defined by annotation in plugin";
138 | return ResponseEntity.ok().body(message);
139 | }
140 | }
141 | ```
142 |
143 | The plugin is implemented as an extension to the ```SpringPlugin```, and has
144 | methods to start, stop, and most importantly, create application context which
145 | will be used to register the annotated configuration class:
146 |
147 | ```java
148 | public class SpringSamplePlugin extends SpringPlugin {
149 |
150 | private static final Logger log = LoggerFactory.getLogger(SpringSamplePlugin.class);
151 |
152 | public SpringSamplePlugin(PluginWrapper wrapper) {
153 | super(wrapper);
154 | }
155 |
156 | @Override
157 | public void start() {
158 | log.info("Spring Sample plugin.start()");
159 | }
160 |
161 | @Override
162 | public void stop() {
163 | log.info("Spring Sample plugin.stop()");
164 | super.stop(); // to close applicationContext
165 | }
166 |
167 | @Override
168 | protected ApplicationContext createApplicationContext() {
169 | AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
170 | applicationContext.setClassLoader(getWrapper().getPluginClassLoader());
171 | applicationContext.register(ApplicationConfiguration.class);
172 | applicationContext.refresh();
173 | return applicationContext;
174 | }
175 | ...
176 | ...
177 | }
178 | ```
179 |
180 | The interfaces to implement are included inside the plugin as static classes implementing the interface and annotated with ```@Extension```:
181 |
182 | ```java
183 |
184 | @Extension(ordinal = 1)
185 | public static class SpringPlugin implements PluginInterface {
186 |
187 | @Autowired
188 | private GreetProvider greetProvider;
189 |
190 |
191 |
192 | @Override
193 | public String identify() {
194 | return greetProvider.provide();
195 | }
196 |
197 | @Override
198 | public List mvcControllers() {
199 | return new ArrayList() {{
200 | add(new PluginController());
201 | }};
202 | }
203 |
204 | @Override
205 | public List> reactiveRoutes() {
206 | return new ArrayList>() {{
207 | add(route(GET("/plugin-end-point"),
208 | req -> ServerResponse
209 | .ok()
210 | .body(Mono.just("reactive router endpoint"),
211 | String.class)));
212 | }};
213 | }
214 | }
215 | ```
216 |
217 | Here the ```mvcControllers()``` returns a List of annotated classes to be used as restcontrollers and the ```reactiveRoutes()``` returns a list of ```RouterFunction``` objects to create the reactive endpoints. needless to say,
218 | a plugin can return an empty list if it doesn't have any endpoints to add.
219 |
220 | [Back to Contents](../#contents)
221 |
--------------------------------------------------------------------------------
/spring-test-plugin/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/spring-test-plugin/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/spring-test-plugin/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.curisprofound
7 | spring-test-plugin
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | spring-test-plugin
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 2.0.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 | spring-hello-plugin
26 | com.curisprofound.springtestplugin.SpringSamplePlugin
27 | 0.0.1
28 | Curis Profound
29 |
30 |
31 |
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-webflux
36 |
37 |
38 |
39 | com.curisprofound
40 | shared-plugin-interfaces
41 | 1.1.0
42 |
43 |
44 |
45 |
46 | org.pf4j
47 | pf4j-spring
48 | 0.4.0
49 |
50 |
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-starter-test
55 | test
56 |
57 |
58 | io.projectreactor
59 | reactor-test
60 | test
61 |
62 |
63 |
64 |
65 |
66 |
67 | org.apache.maven.plugins
68 | maven-antrun-plugin
69 | 1.6
70 |
71 |
72 | unzip jar file
73 | package
74 |
75 |
76 |
78 |
79 |
80 |
81 | run
82 |
83 |
84 |
85 |
86 |
87 |
88 | maven-assembly-plugin
89 | 2.3
90 |
91 |
92 |
93 | src/main/resources/assembly.xml
94 |
95 |
96 | false
97 |
98 |
99 |
100 | make-assembly
101 | package
102 |
103 | attached
104 |
105 |
106 |
107 |
108 |
109 |
110 | org.apache.maven.plugins
111 | maven-jar-plugin
112 | 2.4
113 |
114 |
115 |
116 | ${plugin.id}
117 | ${plugin.class}
118 | ${plugin.version}
119 | ${plugin.provider}
120 | ${plugin.dependencies}
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/java/com/curisprofound/springtestplugin/ApplicationConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springtestplugin;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | public class ApplicationConfiguration {
8 | @Bean
9 | public GreetProvider greetProvider(){
10 | return new GreetProvider();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/java/com/curisprofound/springtestplugin/GreetProvider.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springtestplugin;
2 |
3 | public class GreetProvider {
4 | public String provide(){
5 | return "A plugin using Spring framework";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/java/com/curisprofound/springtestplugin/PluginController.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springtestplugin;
2 |
3 | import org.springframework.http.ResponseEntity;
4 | import org.springframework.stereotype.Controller;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 |
8 | @Controller
9 | @RequestMapping("/plugin-mvc-controller")
10 | public class PluginController {
11 | @GetMapping
12 | public ResponseEntity greetMVC(){
13 | return ResponseEntity.ok().body("An endpoint defined by annotation in plugin");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/java/com/curisprofound/springtestplugin/SpringSamplePlugin.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springtestplugin;
2 |
3 | import com.curisprofound.plugins.PluginInterface;
4 | import org.pf4j.Extension;
5 | import org.pf4j.PluginWrapper;
6 | import org.pf4j.spring.SpringPlugin;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.context.ApplicationContext;
11 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
12 | import org.springframework.web.reactive.function.server.RouterFunction;
13 | import org.springframework.web.reactive.function.server.ServerResponse;
14 | import reactor.core.publisher.Mono;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
20 | import static org.springframework.web.reactive.function.server.RouterFunctions.route;
21 |
22 | public class SpringSamplePlugin extends SpringPlugin {
23 |
24 | private static final Logger log = LoggerFactory.getLogger(SpringSamplePlugin.class);
25 |
26 | public SpringSamplePlugin(PluginWrapper wrapper) {
27 | super(wrapper);
28 | }
29 |
30 | @Override
31 | public void start() {
32 | log.info("Spring Sample plugin.start()");
33 | }
34 |
35 | @Override
36 | public void stop() {
37 | log.info("Spring Sample plugin.stop()");
38 | super.stop(); // to close applicationContext
39 | }
40 |
41 | @Override
42 | protected ApplicationContext createApplicationContext() {
43 | AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
44 | applicationContext.setClassLoader(getWrapper().getPluginClassLoader());
45 | applicationContext.register(ApplicationConfiguration.class);
46 | applicationContext.refresh();
47 | return applicationContext;
48 | }
49 |
50 |
51 | @Extension(ordinal = 1)
52 | public static class SpringPlugin implements PluginInterface {
53 |
54 | @Autowired
55 | private GreetProvider greetProvider;
56 |
57 |
58 |
59 | @Override
60 | public String identify() {
61 | return greetProvider.provide();
62 | }
63 |
64 | @Override
65 | public List mvcControllers() {
66 | return new ArrayList() {{
67 | add(new PluginController());
68 | }};
69 | }
70 |
71 | @Override
72 | public List> reactiveRoutes() {
73 | return new ArrayList>() {{
74 | add(route(GET("/plugin-end-point"),
75 | req -> ServerResponse.ok().body(Mono.just("reactive router endpoint"), String.class)));
76 | }};
77 | }
78 |
79 |
80 | }
81 |
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/java/com/curisprofound/springtestplugin/SpringTestPluginApplication.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springtestplugin;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SpringTestPluginApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SpringTestPluginApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ralemy/pf4j-spring-tutorial/65c97de962ec8572f632b212dde369e3d873df13/spring-test-plugin/src/main/resources/application.properties
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/resources/assembly.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 | plugin
9 |
10 | zip
11 |
12 | false
13 |
14 |
15 | false
16 | runtime
17 | lib
18 |
19 | org.pf4j:*
20 |
21 |
22 | org.springframework:*
23 | org.slf4j:*
24 | com.curisprofound:shared-plugin-interfaces
25 |
26 |
27 |
28 |
29 |
30 | target/plugin-classes
31 | classes
32 |
33 |
34 | src/main/resources
35 |
36 |
37 | plugin.properties
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/main/resources/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=spring-sample-plugin
2 | plugin.class=com.curisprofound.springtestplugin.SpringSamplePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Curis Profound
5 | plugin.dependencies=
6 |
--------------------------------------------------------------------------------
/spring-test-plugin/src/test/java/com/curisprofound/springtestplugin/SpringTestPluginApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.curisprofound.springtestplugin;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class SpringTestPluginApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------