├── .editorconfig
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── demo
├── api
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── org
│ │ └── pf4j
│ │ └── demo
│ │ └── api
│ │ └── Greeting.java
├── app
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── assembly
│ │ └── assembly.xml
│ │ ├── java
│ │ └── org
│ │ │ └── pf4j
│ │ │ └── demo
│ │ │ ├── Boot.java
│ │ │ ├── Greetings.java
│ │ │ ├── SpringConfiguration.java
│ │ │ └── WhazzupGreeting.java
│ │ └── resources
│ │ └── log4j.properties
├── plugins
│ ├── disabled.txt
│ ├── enabled.txt
│ ├── plugin1
│ │ ├── plugin.properties
│ │ ├── pom.xml
│ │ └── src
│ │ │ └── main
│ │ │ ├── assembly
│ │ │ └── assembly.xml
│ │ │ └── java
│ │ │ └── org
│ │ │ └── pf4j
│ │ │ └── demo
│ │ │ └── welcome
│ │ │ └── WelcomePlugin.java
│ ├── plugin2
│ │ ├── plugin.properties
│ │ ├── pom.xml
│ │ └── src
│ │ │ └── main
│ │ │ ├── assembly
│ │ │ └── assembly.xml
│ │ │ └── java
│ │ │ └── org
│ │ │ └── pf4j
│ │ │ └── demo
│ │ │ └── hello
│ │ │ ├── HelloMessageProvider.java
│ │ │ ├── HelloPlugin.java
│ │ │ ├── MessageProvider.java
│ │ │ └── SpringConfiguration.java
│ └── pom.xml
└── pom.xml
├── pf4j-spring
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── pf4j
│ └── spring
│ ├── ExtensionsInjector.java
│ ├── SingletonSpringExtensionFactory.java
│ ├── SpringExtensionFactory.java
│ ├── SpringPlugin.java
│ └── SpringPluginManager.java
├── pom.xml
├── run-demo.bat
└── run-demo.sh
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Pippo code formatting styles
2 | # Checkout http://editorconfig.org/ for more information and how to use it
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | end_of_line = lf
9 | indent_style = space
10 | indent_size = 4
11 |
12 | #[{*.java,*.xml,*.js,*.css]
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | push:
4 | branches:
5 | - '*'
6 | pull_request:
7 | types: [opened, synchronize, reopened]
8 | jobs:
9 | build:
10 | name: Build
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | with:
15 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
16 | - name: Set up JDK 17
17 | uses: actions/setup-java@v4
18 | with:
19 | distribution: "temurin"
20 | java-version: 17
21 | cache: maven
22 | - name: Cache SonarCloud packages
23 | uses: actions/cache@v4
24 | with:
25 | path: ~/.sonar/cache
26 | key: ${{ runner.os }}-sonar
27 | restore-keys: ${{ runner.os }}-sonar
28 | - name: Build and analyze
29 | env:
30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
31 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
32 | run: cd pf4j-spring && mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | target/
3 | *.iml
4 | .settings
5 | .project
6 | .classpath
7 | demo-dist/
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk8
4 | # - openjdk11
5 | after_success:
6 | - mvn clean cobertura:cobertura coveralls:report
7 |
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ### [Unreleased][unreleased]
6 |
7 | #### Fixed
8 |
9 | #### Changed
10 |
11 | #### Added
12 |
13 | #### Removed
14 |
15 | ### [0.10.0] - 2025-05-24
16 |
17 | #### Changed
18 | - [#89]: Upgrade dependencies (PF4J 3.13.0 and Spring Framework 6.2.2)
19 |
20 | ### [0.9.0] - 2024-05-10
21 |
22 | #### Fixed
23 | - [#58]: SpringPlugin start/stop/start results in Exception
24 |
25 | [unreleased]: https://github.com/decebals/pf4j-spring/compare/release-0.10.0...HEAD
26 | [0.10.0]: https://github.com/decebals/pf4j-spring/compare/release-0.9.0...release-0.10.0
27 | [0.9.0]: https://github.com/decebals/pf4j-spring/compare/release-0.8.0...release-0.9.0
28 |
29 | [#89]: https://github.com/pf4j/pf4j-spring/pull/89
30 | [#58]: https://github.com/pf4j/pf4j-spring/issues/58
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PF4J - Spring Framework integration
2 | =====================
3 | [](https://gitter.im/decebals/pf4j?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 | [](https://github.com/pf4j/pf4j-spring/actions/workflows/build.yml)
5 | [](http://search.maven.org/#search|ga|1|pf4j-spring)
6 |
7 | This project is a proof of concept related to how you can integrate [PF4J](https://github.com/pf4j/pf4j) with Spring Framework.
8 |
9 | Components
10 | -------------------
11 | - **ExtensionsInjector** allows PF4J's extensions to be exposed as Spring beans.
12 | - **SpringPlugin** your plugin extends this class if your plugin contains Spring beans
13 | - **SpringExtensionFactory** use this ExtensionFactory in your PluginManager if you have SpringPlugins
14 | - **SpringPluginManager** a Spring aware PluginManager
15 |
16 | Using Maven
17 | -------------------
18 | In your pom.xml you must define the dependencies to PF4J-Spring artifact with:
19 |
20 | ```xml
21 |
22 | org.pf4j
23 | pf4j-spring
24 | ${pf4j-spring.version}
25 |
26 | ```
27 |
28 | where ${pf4j-spring.version} is the last pf4j-spring version.
29 |
30 | You may want to check for the latest released version using [Maven Search](http://search.maven.org/#search%7Cga%7C1%7Cpf4j-spring)
31 |
32 | Also you can use the latest SNAPSHOT via the Sonatype Maven Repository. For this, you must add above lines in your `pom.xml`:
33 |
34 | ```xml
35 |
36 |
37 | sonatype-nexus-snapshots
38 | https://oss.sonatype.org/content/repositories/snapshots
39 |
40 | false
41 |
42 |
43 | true
44 |
45 |
46 |
47 | ```
48 |
49 | How to use
50 | -------------------
51 | Create the Spring configuration (declare some beans) using annotations with:
52 | ```java
53 | @Configuration
54 | public class SpringConfiguration {
55 |
56 | @Bean
57 | public SpringPluginManager pluginManager() {
58 | return new SpringPluginManager();
59 | }
60 |
61 | @Bean
62 | @DependsOn("pluginManager")
63 | public Greetings greetings() {
64 | return new Greetings();
65 | }
66 |
67 | }
68 | ```
69 |
70 | `SpringExtensionFactory` creates a new extension instance every time a request is done.
71 | If you want a singleton extension instance please use `SingletonSpringExtensionFactory` that always returns a specific instance. Optional you can specify the extension classes for which you want singletons.
72 |
73 | Start your application (plain java code):
74 | ```java
75 | public class Boot {
76 |
77 | public static void main(String[] args) {
78 | // retrieves the Spring application context
79 | ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
80 |
81 | // retrieves automatically the extensions for the Greeting.class extension point
82 | Greetings greetings = applicationContext.getBean(Greetings.class);
83 | greetings.printGreetings();
84 |
85 | // stop plugins
86 | PluginManager pluginManager = applicationContext.getBean(PluginManager.class);
87 | /*
88 | // retrieves manually the extensions for the Greeting.class extension point
89 | List greetings = pluginManager.getExtensions(Greeting.class);
90 | System.out.println("greetings.size() = " + greetings.size());
91 | */
92 | pluginManager.stopPlugins();
93 | }
94 |
95 | }
96 | ```
97 |
98 | Consume the PF4J extensions as Spring beans:
99 | ```java
100 | public class Greetings {
101 |
102 | @Autowired
103 | private List greetings;
104 |
105 | public void printGreetings() {
106 | System.out.println(String.format("Found %d extensions for extension point '%s'", greetings.size(), Greeting.class.getName()));
107 | for (Greeting greeting : greetings) {
108 | System.out.println(">>> " + greeting.getGreeting());
109 | }
110 | }
111 |
112 | }
113 | ```
114 |
115 | The output is:
116 | ```
117 | Found 2 extensions for extension point 'org.pf4j.demo.api.Greeting'
118 | >>> Welcome
119 | >>> Hello
120 | ```
121 |
122 | Bellow I present you a more complex example where a plugin (see demo plugin2 - HelloPlugin) uses Spring Framework internally.
123 |
124 | First, create an interface `MessageProvider` with an implementation class `HelloMessageProvider`
125 | ```java
126 | public interface MessageProvider {
127 |
128 | String getMessage();
129 |
130 | }
131 |
132 | public class HelloMessageProvider implements MessageProvider {
133 |
134 | @Override
135 | public String getMessage() {
136 | return "Hello";
137 | }
138 |
139 | }
140 | ```
141 |
142 | Declare the plugin's beans via Spring Configuration
143 | ```java
144 | @Configuration
145 | public class SpringConfiguration {
146 |
147 | @Bean
148 | public MessageProvider messageProvider() {
149 | return new HelloMessageProvider();
150 | }
151 |
152 | }
153 | ```
154 |
155 | Create my (Spring) plugin
156 | ```java
157 | public class HelloPlugin extends SpringPlugin {
158 |
159 | public HelloPlugin(PluginWrapper wrapper) {
160 | super(wrapper);
161 | }
162 |
163 | @Override
164 | public void start() {
165 | System.out.println("HelloPlugin.start()");
166 | }
167 |
168 | @Override
169 | public void stop() {
170 | System.out.println("HelloPlugin.stop()");
171 | super.stop(); // to close applicationContext
172 | }
173 |
174 | @Override
175 | protected ApplicationContext createApplicationContext() {
176 | AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
177 | applicationContext.setClassLoader(getWrapper().getPluginClassLoader());
178 | applicationContext.register(SpringConfiguration.class);
179 | applicationContext.refresh();
180 |
181 | return applicationContext;
182 | }
183 |
184 | @Extension
185 | public static class HelloGreeting implements Greeting {
186 |
187 | @Autowired
188 | private MessageProvider messageProvider;
189 |
190 | @Override
191 | public String getGreeting() {
192 | // return "Hello";
193 | // complicate a little bit the code
194 | return messageProvider.getMessage();
195 | }
196 |
197 | }
198 |
199 | }
200 | ```
201 |
202 | Ready, your extension is available in your application via `PluginManager` or `Spring Autowire`.
203 |
204 | For more details please see the demo application.
205 |
206 | Implementation details
207 | -------------------
208 | __ExtensionsInjector__ injects each PF4J's extension as a bean in Spring Framework. For example if you run the demo application
209 | you will see these lines in log:
210 |
211 | ```
212 | 2014-06-16 16:40:36,573 DEBUG org.pf4j.spring.ExtensionsInjector - Registering extensions of the plugin 'welcome-plugin' as beans
213 | 2014-06-16 16:40:36,586 DEBUG org.pf4j.spring.ExtensionsInjector - Register extension 'org.pf4j.demo.welcome.WelcomePlugin$WelcomeGreeting' as bean
214 | 2014-06-16 16:40:36,589 DEBUG org.pf4j.spring.ExtensionsInjector - Registering extensions of the plugin 'hello-plugin' as beans
215 | 2014-06-16 16:40:36,589 DEBUG org.pf4j.spring.ExtensionsInjector - Register extension 'org.pf4j.demo.hello.HelloPlugin$HelloGreeting' as bean
216 | ```
217 |
218 | The bean name is the extension class name (for example 'org.pf4j.demo.welcome.WelcomePlugin$WelcomeGreeting').
219 |
220 | For more information please see the demo sources.
221 |
222 | Demo
223 | -------------------
224 | I have a tiny demo application. The demo application is in demo package.
225 |
226 | Run the pf4j-spring demo (Boot class contains the main method) from IDE (IntelliJ in my case) with these arguments as VM options:
227 | ```
228 | -Dpf4j.mode=development
229 | ```
230 |
231 | and working directory:
232 | ```
233 | pf4j-spring/demo/app
234 | ```
235 |
--------------------------------------------------------------------------------
/demo/api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j.demo
6 | pf4j-spring-demo-parent
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | pf4j-spring-demo-api
12 | 0.11.0-SNAPSHOT
13 | jar
14 | Demo Api
15 |
16 |
17 |
18 |
19 | maven-deploy-plugin
20 |
21 | true
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.pf4j
30 | pf4j-spring
31 | ${project.version}
32 | provided
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/demo/api/src/main/java/org/pf4j/demo/api/Greeting.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo.api;
17 |
18 | import org.pf4j.ExtensionPoint;
19 |
20 | /**
21 | * @author Decebal Suiu
22 | */
23 | public interface Greeting extends ExtensionPoint {
24 |
25 | String getGreeting();
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/demo/app/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j.demo
6 | pf4j-spring-demo-parent
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | pf4j-spring-demo-app
12 | 0.11.0-SNAPSHOT
13 | jar
14 | Demo App
15 |
16 |
17 | org.pf4j.demo.Boot
18 | 1.7.5
19 |
20 |
21 |
22 |
23 |
24 | maven-assembly-plugin
25 | 2.3
26 |
27 |
28 |
29 | src/main/assembly/assembly.xml
30 |
31 |
32 | false
33 |
34 |
35 |
36 | make-assembly
37 | package
38 |
39 | attached
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-jar-plugin
48 | 2.3.1
49 |
50 |
51 |
52 | true
53 | lib/
54 | ${main.class}
55 |
56 |
57 |
58 |
59 |
60 |
61 | maven-deploy-plugin
62 |
63 | true
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | org.pf4j
72 | pf4j-spring
73 | ${project.version}
74 |
75 |
76 |
77 | org.pf4j.demo
78 | pf4j-spring-demo-api
79 | ${project.version}
80 |
81 |
82 |
83 |
84 | log4j
85 | log4j
86 | 1.2.16
87 |
88 |
89 |
90 | org.slf4j
91 | slf4j-log4j12
92 | ${slf4j.version}
93 |
94 |
95 |
96 | commons-lang
97 | commons-lang
98 | 2.4
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/demo/app/src/main/assembly/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 |
38 |
--------------------------------------------------------------------------------
/demo/app/src/main/java/org/pf4j/demo/Boot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo;
17 |
18 | import org.apache.commons.lang.StringUtils;
19 | import org.springframework.context.ApplicationContext;
20 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
21 | import org.pf4j.PluginManager;
22 |
23 | /**
24 | * A boot class that start the demo.
25 | *
26 | * @author Decebal Suiu
27 | */
28 | public class Boot {
29 |
30 | public static void main(String[] args) {
31 | // print logo
32 | printLogo();
33 |
34 | // retrieves the spring application context
35 | ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
36 |
37 | // retrieves automatically the extensions for the Greeting.class extension point
38 | Greetings greetings = applicationContext.getBean(Greetings.class);
39 | greetings.printGreetings();
40 |
41 | // stop plugins
42 | PluginManager pluginManager = applicationContext.getBean(PluginManager.class);
43 | /*
44 | // retrieves manually the extensions for the Greeting.class extension point
45 | List greetings = pluginManager.getExtensions(Greeting.class);
46 | System.out.println("greetings.size() = " + greetings.size());
47 | */
48 | pluginManager.stopPlugins();
49 | }
50 |
51 | private static void printLogo() {
52 | System.out.println(StringUtils.repeat("#", 40));
53 | System.out.println(StringUtils.center("PF4J-SPRING", 40));
54 | System.out.println(StringUtils.repeat("#", 40));
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/demo/app/src/main/java/org/pf4j/demo/Greetings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo;
17 |
18 | import org.springframework.beans.factory.annotation.Autowired;
19 | import org.pf4j.demo.api.Greeting;
20 |
21 | import java.util.List;
22 |
23 | /**
24 | * @author Decebal Suiu
25 | */
26 | //@Component
27 | public class Greetings {
28 |
29 | @Autowired
30 | private List greetings;
31 |
32 | public void printGreetings() {
33 | System.out.println(String.format("Found %d extensions for extension point '%s'", greetings.size(), Greeting.class.getName()));
34 | for (Greeting greeting : greetings) {
35 | System.out.println(">>> " + greeting.getGreeting());
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/demo/app/src/main/java/org/pf4j/demo/SpringConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo;
17 |
18 | import org.pf4j.spring.SpringPluginManager;
19 | import org.springframework.context.annotation.Bean;
20 | import org.springframework.context.annotation.Configuration;
21 | import org.springframework.context.annotation.DependsOn;
22 |
23 | /**
24 | * @author Decebal Suiu
25 | */
26 | @Configuration
27 | public class SpringConfiguration {
28 |
29 | @Bean
30 | public SpringPluginManager pluginManager() {
31 | return new SpringPluginManager();
32 | }
33 |
34 | @Bean
35 | @DependsOn("pluginManager")
36 | public Greetings greetings() {
37 | return new Greetings();
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/demo/app/src/main/java/org/pf4j/demo/WhazzupGreeting.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo;
17 |
18 | import org.pf4j.Extension;
19 | import org.pf4j.demo.api.Greeting;
20 |
21 | /**
22 | * @author Decebal Suiu
23 | */
24 | @Extension
25 | public class WhazzupGreeting implements Greeting {
26 |
27 | @Override
28 | public String getGreeting() {
29 | return "Whazzup";
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/demo/app/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=DEBUG, Console
2 |
3 | #
4 | # PF4J log
5 | #
6 | log4j.logger.org.pf4j=DEBUG, Console
7 | log4j.logger.org.pf4j.PluginClassLoader=WARN, Console
8 | log4j.additivity.org.pf4j=false
9 |
10 | #
11 | # Appenders
12 | #
13 | log4j.appender.Console=org.apache.log4j.ConsoleAppender
14 | log4j.appender.Console.layout=org.apache.log4j.PatternLayout
15 | #log4j.appender.Console.layout.conversionPattern=%-5p - %-32.32c{1} - %m\n
16 | log4j.appender.Console.layout.ConversionPattern=%d %p %c - %m%n
17 |
--------------------------------------------------------------------------------
/demo/plugins/disabled.txt:
--------------------------------------------------------------------------------
1 | ########################################
2 | # - load all plugins except these
3 | # - add one plugin id on each line
4 | # - put this file in plugins folder
5 | ########################################
6 | #welcome-plugin
7 |
--------------------------------------------------------------------------------
/demo/plugins/enabled.txt:
--------------------------------------------------------------------------------
1 | ########################################
2 | # - load only these plugins
3 | # - add one plugin id on each line
4 | # - put this file in plugins folder
5 | ########################################
6 | #welcome-plugin
7 |
--------------------------------------------------------------------------------
/demo/plugins/plugin1/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=welcome-plugin
2 | plugin.class=org.pf4j.demo.welcome.WelcomePlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Decebal Suiu
5 | plugin.dependencies=
6 |
--------------------------------------------------------------------------------
/demo/plugins/plugin1/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j.demo
6 | pf4j-spring-demo-plugins
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | pf4j-spring-demo-plugin1
12 | 0.11.0-SNAPSHOT
13 | jar
14 | Demo Plugin #1
15 |
16 |
17 | welcome-plugin
18 | org.pf4j.demo.welcome.WelcomePlugin
19 | 0.0.1
20 | Decebal Suiu
21 |
22 |
23 |
24 |
25 |
26 |
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-antrun-plugin
50 | 1.6
51 |
52 |
53 | unzip jar file
54 | package
55 |
56 |
57 |
58 |
59 |
60 |
61 | run
62 |
63 |
64 |
65 |
66 |
67 |
68 | maven-assembly-plugin
69 | 2.3
70 |
71 |
72 |
73 | src/main/assembly/assembly.xml
74 |
75 |
76 | false
77 |
78 |
79 |
80 | make-assembly
81 | package
82 |
83 | attached
84 |
85 |
86 |
87 |
88 |
89 |
90 | org.apache.maven.plugins
91 | maven-jar-plugin
92 | 2.4
93 |
94 |
95 |
96 | ${plugin.id}
97 | ${plugin.class}
98 | ${plugin.version}
99 | ${plugin.provider}
100 | ${plugin.dependencies}
101 |
102 |
103 |
104 |
105 |
106 |
107 | maven-deploy-plugin
108 |
109 | true
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | commons-lang
118 | commons-lang
119 | 2.6
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/demo/plugins/plugin1/src/main/assembly/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 |
23 |
31 |
32 |
33 | target/plugin-classes
34 | classes
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/plugins/plugin1/src/main/java/org/pf4j/demo/welcome/WelcomePlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo.welcome;
17 |
18 | import org.apache.commons.lang.StringUtils;
19 |
20 | import org.pf4j.Extension;
21 | import org.pf4j.Plugin;
22 | import org.pf4j.PluginWrapper;
23 | import org.pf4j.RuntimeMode;
24 | import org.pf4j.demo.api.Greeting;
25 |
26 | /**
27 | * @author Decebal Suiu
28 | */
29 | public class WelcomePlugin extends Plugin {
30 |
31 | public WelcomePlugin(PluginWrapper wrapper) {
32 | super(wrapper);
33 | }
34 |
35 | @Override
36 | public void start() {
37 | System.out.println("WelcomePlugin.start()");
38 | // for testing the development mode
39 | if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) {
40 | System.out.println(StringUtils.upperCase("WelcomePlugin"));
41 | }
42 | }
43 |
44 | @Override
45 | public void stop() {
46 | System.out.println("WelcomePlugin.stop()");
47 | }
48 |
49 | @Extension
50 | public static class WelcomeGreeting implements Greeting {
51 |
52 | @Override
53 | public String getGreeting() {
54 | return "Welcome";
55 | }
56 |
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/plugin.properties:
--------------------------------------------------------------------------------
1 | plugin.id=hello-plugin
2 | plugin.class=org.pf4j.demo.hello.HelloPlugin
3 | plugin.version=0.0.1
4 | plugin.provider=Decebal Suiu
5 | plugin.dependencies=
6 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j.demo
6 | pf4j-spring-demo-plugins
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | pf4j-spring-demo-plugin2
12 | 0.11.0-SNAPSHOT
13 | jar
14 | Demo Plugin #2
15 |
16 |
17 | hello-plugin
18 | org.pf4j.demo.hello.HelloPlugin
19 | 0.0.1
20 | Decebal Suiu
21 |
22 |
23 |
24 |
25 |
26 |
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-antrun-plugin
50 | 1.6
51 |
52 |
53 | unzip jar file
54 | package
55 |
56 |
57 |
58 |
59 |
60 |
61 | run
62 |
63 |
64 |
65 |
66 |
67 |
68 | maven-assembly-plugin
69 | 2.3
70 |
71 |
72 |
73 | src/main/assembly/assembly.xml
74 |
75 |
76 | false
77 |
78 |
79 |
80 | make-assembly
81 | package
82 |
83 | attached
84 |
85 |
86 |
87 |
88 |
89 |
90 | org.apache.maven.plugins
91 | maven-jar-plugin
92 | 2.4
93 |
94 |
95 |
96 | ${plugin.id}
97 | ${plugin.class}
98 | ${plugin.version}
99 | ${plugin.provider}
100 | ${plugin.dependencies}
101 |
102 |
103 |
104 |
105 |
106 |
107 | maven-deploy-plugin
108 |
109 | true
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/src/main/assembly/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 |
23 |
31 |
32 |
33 | target/plugin-classes
34 | classes
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/src/main/java/org/pf4j/demo/hello/HelloMessageProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo.hello;
17 |
18 | /**
19 | * @author Decebal Suiu
20 | */
21 | //@Component
22 | public class HelloMessageProvider implements MessageProvider {
23 |
24 | @Override
25 | public String getMessage() {
26 | return "Hello";
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/src/main/java/org/pf4j/demo/hello/HelloPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo.hello;
17 |
18 | import org.springframework.beans.factory.annotation.Autowired;
19 | import org.springframework.context.ApplicationContext;
20 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
21 | import org.pf4j.Extension;
22 | import org.pf4j.PluginWrapper;
23 | import org.pf4j.demo.api.Greeting;
24 | import org.pf4j.spring.SpringPlugin;
25 |
26 | /**
27 | * A very simple plugin.
28 | *
29 | * @author Decebal Suiu
30 | */
31 | public class HelloPlugin extends SpringPlugin {
32 |
33 | public HelloPlugin(PluginWrapper wrapper) {
34 | super(wrapper);
35 | }
36 |
37 | @Override
38 | public void start() {
39 | System.out.println("HelloPlugin.start()");
40 | }
41 |
42 | @Override
43 | public void stop() {
44 | System.out.println("HelloPlugin.stop()");
45 | super.stop(); // to close applicationContext
46 | }
47 |
48 | @Override
49 | protected ApplicationContext createApplicationContext() {
50 | AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
51 | applicationContext.setClassLoader(getWrapper().getPluginClassLoader());
52 | applicationContext.register(SpringConfiguration.class);
53 | applicationContext.refresh();
54 |
55 | return applicationContext;
56 | }
57 |
58 | @Extension(ordinal=1)
59 | public static class HelloGreeting implements Greeting {
60 |
61 | private final MessageProvider messageProvider;
62 |
63 | @Autowired
64 | public HelloGreeting(final MessageProvider messageProvider) {
65 | this.messageProvider = messageProvider;
66 | }
67 |
68 | @Override
69 | public String getGreeting() {
70 | // return "Hello";
71 | // complicate a little bit the code
72 | return messageProvider.getMessage();
73 | }
74 |
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/src/main/java/org/pf4j/demo/hello/MessageProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo.hello;
17 |
18 | /**
19 | * @author Decebal Suiu
20 | */
21 | public interface MessageProvider {
22 |
23 | String getMessage();
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/demo/plugins/plugin2/src/main/java/org/pf4j/demo/hello/SpringConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.demo.hello;
17 |
18 | import org.springframework.context.annotation.Bean;
19 | import org.springframework.context.annotation.Configuration;
20 |
21 | /**
22 | * @author Decebal Suiu
23 | */
24 | @Configuration
25 | public class SpringConfiguration {
26 |
27 | @Bean
28 | public MessageProvider messageProvider() {
29 | return new HelloMessageProvider();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/demo/plugins/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j.demo
6 | pf4j-spring-demo-parent
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | pf4j-spring-demo-plugins
12 | 0.11.0-SNAPSHOT
13 | pom
14 | Demo Plugins Parent
15 |
16 |
17 |
18 |
19 | false
20 | src/main/java
21 |
22 | **/*.java
23 |
24 |
25 |
26 | src/main/resources
27 |
28 |
29 |
30 |
31 |
32 | maven-dependency-plugin
33 |
34 |
35 | process-sources
36 |
37 | copy-dependencies
38 |
39 |
40 | ${project.build.directory}/lib
41 | provided
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.eclipse.m2e
52 | lifecycle-mapping
53 | 1.0.0
54 |
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-dependency-plugin
61 | [2.0,)
62 |
63 | copy-dependencies
64 |
65 |
66 |
67 |
70 |
71 | true
72 | true
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | plugin1
86 | plugin2
87 |
88 |
89 |
90 |
91 | org.pf4j
92 | pf4j-spring
93 | ${project.version}
94 | provided
95 |
96 |
97 |
98 | org.pf4j.demo
99 | pf4j-spring-demo-api
100 | ${project.version}
101 | provided
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j
6 | pf4j-spring-parent
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | org.pf4j.demo
12 | pf4j-spring-demo-parent
13 | 0.11.0-SNAPSHOT
14 | pom
15 | Demo Parent
16 |
17 |
18 | true
19 | true
20 | true
21 |
22 |
23 |
24 |
25 |
26 | false
27 | src/main/java
28 |
29 | **/*.java
30 |
31 |
32 |
33 | src/main/resources
34 |
35 |
36 |
37 |
38 |
39 | app
40 | api
41 | plugins
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/pf4j-spring/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.pf4j
6 | pf4j-spring-parent
7 | 0.11.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | pf4j-spring
12 | 0.11.0-SNAPSHOT
13 | PF4J-Spring
14 | PF4J-Spring Integration
15 |
16 |
17 | pf4j_pf4j-spring
18 |
19 |
20 |
21 |
22 |
23 | org.jacoco
24 | jacoco-maven-plugin
25 | 0.8.11
26 |
27 |
28 | prepare-agent
29 |
30 | prepare-agent
31 |
32 |
33 |
34 | report
35 | test
36 |
37 | report
38 |
39 |
40 |
41 | XML
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.pf4j
53 | pf4j
54 | ${pf4j.version}
55 |
56 |
57 |
58 |
59 | org.springframework
60 | spring-core
61 | ${spring.version}
62 |
63 |
64 |
65 | org.springframework
66 | spring-context
67 | ${spring.version}
68 |
69 |
70 |
71 | jakarta.annotation
72 | jakarta.annotation-api
73 | 3.0.0
74 |
75 |
76 |
77 |
78 | org.slf4j
79 | slf4j-log4j12
80 | ${slf4j.version}
81 |
82 |
83 |
84 | commons-lang
85 | commons-lang
86 | 2.4
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/pf4j-spring/src/main/java/org/pf4j/spring/ExtensionsInjector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.spring;
17 |
18 | import org.pf4j.PluginWrapper;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 | import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
22 |
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.Set;
26 |
27 | /**
28 | * @author Decebal Suiu
29 | */
30 | public class ExtensionsInjector {
31 |
32 | private static final Logger log = LoggerFactory.getLogger(ExtensionsInjector.class);
33 |
34 | protected final SpringPluginManager springPluginManager;
35 | protected final AbstractAutowireCapableBeanFactory beanFactory;
36 |
37 | public ExtensionsInjector(SpringPluginManager springPluginManager, AbstractAutowireCapableBeanFactory beanFactory) {
38 | this.springPluginManager = springPluginManager;
39 | this.beanFactory = beanFactory;
40 | }
41 |
42 | public void injectExtensions() {
43 | // add extensions from classpath (non plugin)
44 | Set extensionClassNames = springPluginManager.getExtensionClassNames(null);
45 | for (String extensionClassName : extensionClassNames) {
46 | try {
47 | log.debug("Register extension '{}' as bean", extensionClassName);
48 | Class> extensionClass = getClass().getClassLoader().loadClass(extensionClassName);
49 | registerExtension(extensionClass);
50 | } catch (ClassNotFoundException e) {
51 | log.error(e.getMessage(), e);
52 | }
53 | }
54 |
55 | // add extensions for each started plugin
56 | List startedPlugins = springPluginManager.getStartedPlugins();
57 | for (PluginWrapper plugin : startedPlugins) {
58 | log.debug("Registering extensions of the plugin '{}' as beans", plugin.getPluginId());
59 | extensionClassNames = springPluginManager.getExtensionClassNames(plugin.getPluginId());
60 | for (String extensionClassName : extensionClassNames) {
61 | try {
62 | log.debug("Register extension '{}' as bean", extensionClassName);
63 | Class> extensionClass = plugin.getPluginClassLoader().loadClass(extensionClassName);
64 | registerExtension(extensionClass);
65 | } catch (ClassNotFoundException e) {
66 | log.error(e.getMessage(), e);
67 | }
68 | }
69 | }
70 | }
71 |
72 | /**
73 | * Register an extension as bean.
74 | * Current implementation register extension as singleton using {@code beanFactory.registerSingleton()}.
75 | * The extension instance is created using {@code pluginManager.getExtensionFactory().create(extensionClass)}.
76 | * The bean name is the extension class name.
77 | * Override this method if you wish other register strategy.
78 | */
79 | protected void registerExtension(Class> extensionClass) {
80 | Map extensionBeanMap = springPluginManager.getApplicationContext().getBeansOfType(extensionClass);
81 | if (extensionBeanMap.isEmpty()) {
82 | Object extension = springPluginManager.getExtensionFactory().create(extensionClass);
83 | beanFactory.registerSingleton(extensionClass.getName(), extension);
84 | } else {
85 | log.debug("Bean registeration aborted! Extension '{}' already existed as bean!", extensionClass.getName());
86 | }
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/pf4j-spring/src/main/java/org/pf4j/spring/SingletonSpringExtensionFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.spring;
17 |
18 | import org.pf4j.PluginManager;
19 |
20 | import java.util.Arrays;
21 | import java.util.HashMap;
22 | import java.util.List;
23 | import java.util.Map;
24 |
25 | /**
26 | * A {@link SpringExtensionFactory} that always returns a specific instance.
27 | * Optional you can specify the extension classes for which you want singletons.
28 | *
29 | * @author Decebal Suiu
30 | */
31 | public class SingletonSpringExtensionFactory extends SpringExtensionFactory {
32 |
33 | private final List extensionClassNames;
34 |
35 | private Map cache;
36 |
37 | public SingletonSpringExtensionFactory(PluginManager pluginManager) {
38 | this(pluginManager, true);
39 | }
40 |
41 | public SingletonSpringExtensionFactory(PluginManager pluginManager, String... extensionClassNames) {
42 | this(pluginManager, true, extensionClassNames);
43 | }
44 |
45 | public SingletonSpringExtensionFactory(PluginManager pluginManager, boolean autowire, String... extensionClassNames) {
46 | super(pluginManager, autowire);
47 |
48 | this.extensionClassNames = Arrays.asList(extensionClassNames);
49 |
50 | cache = new HashMap<>(); // simple cache implementation
51 | }
52 |
53 | @Override
54 | @SuppressWarnings("unchecked")
55 | public T create(Class extensionClass) {
56 | String extensionClassName = extensionClass.getName();
57 | if (cache.containsKey(extensionClassName)) {
58 | return (T) cache.get(extensionClassName);
59 | }
60 |
61 | T extension = super.create(extensionClass);
62 | if (extensionClassNames.isEmpty() || extensionClassNames.contains(extensionClassName)) {
63 | cache.put(extensionClassName, extension);
64 | }
65 |
66 | return extension;
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/pf4j-spring/src/main/java/org/pf4j/spring/SpringExtensionFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.spring;
17 |
18 | import org.pf4j.Extension;
19 | import org.pf4j.ExtensionFactory;
20 | import org.pf4j.Plugin;
21 | import org.pf4j.PluginManager;
22 | import org.pf4j.PluginWrapper;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 | import org.springframework.beans.factory.annotation.Autowired;
26 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
27 | import org.springframework.context.ApplicationContext;
28 |
29 | import java.lang.reflect.Constructor;
30 | import java.lang.reflect.InvocationTargetException;
31 | import java.util.Comparator;
32 | import java.util.Optional;
33 | import java.util.stream.Stream;
34 |
35 | import static java.util.Objects.nonNull;
36 |
37 | /**
38 | * Basic implementation of an extension factory.
39 | *
40 | * Uses Springs {@link AutowireCapableBeanFactory} to instantiate a given extension class. All kinds of
41 | * {@link Autowired} are supported (see example below). If no {@link ApplicationContext} is available (this is the case
42 | * if either the related plugin is not a {@link SpringPlugin} or the given plugin manager is not a
43 | * {@link SpringPluginManager}), standard Java reflection will be used to instantiate an extension.
44 | *
45 | * Creates a new extension instance every time a request is done.
46 | *
47 | * Example of supported autowire modes:
48 | *
68 | *
69 | * @author Decebal Suiu
70 | * @author m-schroeer
71 | */
72 | public class SpringExtensionFactory implements ExtensionFactory {
73 |
74 | private static final Logger log = LoggerFactory.getLogger(SpringExtensionFactory.class);
75 | public static final boolean AUTOWIRE_BY_DEFAULT = true;
76 |
77 | private static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
78 |
79 | /**
80 | * The plugin manager is used for retrieving a plugin from a given extension class
81 | * and as a fallback supplier of an application context.
82 | */
83 | protected final PluginManager pluginManager;
84 | /**
85 | * Indicates if springs autowiring possibilities should be used.
86 | */
87 | protected final boolean autowire;
88 |
89 | public SpringExtensionFactory(final PluginManager pluginManager) {
90 | this(pluginManager, AUTOWIRE_BY_DEFAULT);
91 | }
92 |
93 | public SpringExtensionFactory(final PluginManager pluginManager, final boolean autowire) {
94 | this.pluginManager = pluginManager;
95 | this.autowire = autowire;
96 | if (!autowire) {
97 | log.warn("Autowiring is disabled although the only reason for existence of this special factory is" +
98 | " supporting spring and its application context.");
99 | }
100 | }
101 |
102 | /**
103 | * Creates an instance of the given {@code extensionClass}. If {@link #autowire} is set to {@code true} this method
104 | * will try to use springs autowiring possibilities.
105 | *
106 | * @param extensionClass The class annotated with {@code @}{@link Extension}.
107 | * @param The type for that an instance should be created.
108 | * @return an instance of the the requested {@code extensionClass}.
109 | * @see #getApplicationContextBy(Class)
110 | */
111 | @Override
112 | public T create(final Class extensionClass) {
113 | if (!this.autowire) {
114 | log.warn("Create instance of '" + nameOf(extensionClass) + "' without using springs possibilities as" +
115 | " autowiring is disabled.");
116 | return createWithoutSpring(extensionClass);
117 | }
118 |
119 | return getApplicationContextBy(extensionClass)
120 | .map(applicationContext -> createWithSpring(extensionClass, applicationContext))
121 | .orElseGet(() -> createWithoutSpring(extensionClass));
122 | }
123 |
124 | /**
125 | * Creates an instance of the given {@code extensionClass} by using the {@link AutowireCapableBeanFactory} of the given
126 | * {@code applicationContext}. All kinds of autowiring are applied:
127 | *
128 | *
Constructor injection
129 | *
Setter injection
130 | *
Field injection
131 | *
132 | *
133 | * @param extensionClass The class annotated with {@code @}{@link Extension}.
134 | * @param The type for that an instance should be created.
135 | * @param applicationContext The context to use for autowiring.
136 | * @return an autowired extension instance.
137 | */
138 | @SuppressWarnings("unchecked")
139 | protected T createWithSpring(final Class extensionClass, final ApplicationContext applicationContext) {
140 | final AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
141 |
142 | log.debug("Instantiate extension class '" + nameOf(extensionClass) + "' by using constructor autowiring.");
143 | // Autowire by constructor. This does not include the other types of injection (setters and/or fields).
144 | final Object autowiredExtension = beanFactory.autowire(extensionClass, AUTOWIRE_CONSTRUCTOR,
145 | // The value of the 'dependencyCheck' parameter is actually irrelevant as the using constructor of 'RootBeanDefinition'
146 | // skips action when the autowire mode is set to 'AUTOWIRE_CONSTRUCTOR'. Although the default value in
147 | // 'AbstractBeanDefinition' is 'DEPENDENCY_CHECK_NONE', so it is set to false here as well.
148 | false);
149 | log.trace("Created extension instance by constructor injection: " + autowiredExtension);
150 |
151 | log.debug("Completing autowiring of extension: " + autowiredExtension);
152 | // Autowire by using remaining kinds of injection (e. g. setters and/or fields).
153 | beanFactory.autowireBean(autowiredExtension);
154 | log.trace("Autowiring has been completed for extension: " + autowiredExtension);
155 |
156 | return (T) autowiredExtension;
157 | }
158 |
159 | /**
160 | * Retrieves springs {@link ApplicationContext} from the extensions plugin or the {@link #pluginManager}.
161 | *
162 | * The ordering of checks is:
163 | *
164 | *
If the given {@code extensionClass} belongs to a plugin that is a {@link SpringPlugin} the plugins context will be returned.
165 | *
Otherwise, if the given {@link #pluginManager} of this instance is a {@link SpringPluginManager} the managers context will be returned.
166 | *
If none of these checks fits, {@code null} is returned.
167 | *
168 | *
169 | * @param extensionClass The class annotated with {@code @}{@link Extension}.
170 | * @param The Type of extension for that an {@link ApplicationContext} is requested.
171 | * @return the best fitting context, or {@code null}.
172 | */
173 | protected Optional getApplicationContextBy(final Class extensionClass) {
174 | final Plugin plugin = Optional.ofNullable(this.pluginManager.whichPlugin(extensionClass))
175 | .map(PluginWrapper::getPlugin)
176 | .orElse(null);
177 |
178 | final ApplicationContext applicationContext;
179 |
180 | if (plugin instanceof SpringPlugin) {
181 | log.debug(" Extension class ' " + nameOf(extensionClass) + "' belongs to spring-plugin '" + nameOf(plugin)
182 | + "' and will be autowired by using its application context.");
183 | applicationContext = ((SpringPlugin) plugin).getApplicationContext();
184 | } else if (this.pluginManager instanceof SpringPluginManager) {
185 | log.debug(" Extension class ' " + nameOf(extensionClass) + "' belongs to a non spring-plugin (or main application)" +
186 | " '" + nameOf(plugin) + ", but the used PF4J plugin-manager is a spring-plugin-manager. Therefore" +
187 | " the extension class will be autowired by using the managers application contexts");
188 | applicationContext = ((SpringPluginManager) this.pluginManager).getApplicationContext();
189 | } else {
190 | log.warn(" No application contexts can be used for instantiating extension class '" + nameOf(extensionClass) + "'."
191 | + " This extension neither belongs to a PF4J spring-plugin (id: '" + nameOf(plugin) + "') nor is the used" +
192 | " plugin manager a spring-plugin-manager (used manager: '" + nameOf(this.pluginManager.getClass()) + "')." +
193 | " At perspective of PF4J this seems highly uncommon in combination with a factory which only reason for existence" +
194 | " is using spring (and its application context) and should at least be reviewed. In fact no autowiring can be" +
195 | " applied although autowire flag was set to 'true'. Instantiating will fallback to standard Java reflection.");
196 | applicationContext = null;
197 | }
198 |
199 | return Optional.ofNullable(applicationContext);
200 | }
201 |
202 | /**
203 | * Creates an instance of the given class object by using standard Java reflection.
204 | *
205 | * @param extensionClass The class annotated with {@code @}{@link Extension}.
206 | * @param The type for that an instance should be created.
207 | * @return an instantiated extension.
208 | * @throws IllegalArgumentException if the given class object has no public constructor.
209 | * @throws RuntimeException if the called constructor cannot be instantiated with {@code null}-parameters.
210 | */
211 | @SuppressWarnings("unchecked")
212 | protected T createWithoutSpring(final Class extensionClass) throws IllegalArgumentException {
213 | final Constructor> constructor = getPublicConstructorWithShortestParameterList(extensionClass)
214 | // An extension class is required to have at least one public constructor.
215 | .orElseThrow(() -> new IllegalArgumentException("Extension class '" + nameOf(extensionClass)
216 | + "' must have at least one public constructor."));
217 | try {
218 | log.debug("Instantiate '" + nameOf(extensionClass) + "' by calling '" + constructor + "'with standard Java reflection.");
219 | // Creating the instance by calling the constructor with null-parameters (if there are any).
220 | return (T) constructor.newInstance(nullParameters(constructor));
221 | } catch (final InstantiationException | IllegalAccessException | InvocationTargetException ex) {
222 | // If one of these exceptions is thrown it it most likely because of NPE inside the called constructor and
223 | // not the reflective call itself as we precisely searched for a fitting constructor.
224 | log.error(ex.getMessage(), ex);
225 | throw new RuntimeException("Most likely this exception is thrown because the called constructor (" + constructor + ")" +
226 | " cannot handle 'null' parameters. Original message was: "
227 | + ex.getMessage(), ex);
228 | }
229 | }
230 |
231 | private Optional> getPublicConstructorWithShortestParameterList(final Class> extensionClass) {
232 | return Stream.of(extensionClass.getConstructors())
233 | .min(Comparator.comparing(Constructor::getParameterCount));
234 | }
235 |
236 | private Object[] nullParameters(final Constructor> constructor) {
237 | return new Object[constructor.getParameterCount()];
238 | }
239 |
240 | private String nameOf(final Plugin plugin) {
241 | return nonNull(plugin)
242 | ? plugin.getWrapper().getPluginId()
243 | : "system";
244 | }
245 |
246 | private String nameOf(final Class clazz) {
247 | return clazz.getName();
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/pf4j-spring/src/main/java/org/pf4j/spring/SpringPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.spring;
17 |
18 | import org.pf4j.Plugin;
19 | import org.pf4j.PluginWrapper;
20 | import org.springframework.context.ApplicationContext;
21 | import org.springframework.context.ConfigurableApplicationContext;
22 |
23 | /**
24 | * @author Decebal Suiu
25 | */
26 | public abstract class SpringPlugin extends Plugin {
27 |
28 | protected ApplicationContext applicationContext;
29 |
30 | public SpringPlugin(PluginWrapper wrapper) {
31 | super(wrapper);
32 | }
33 |
34 | public final ApplicationContext getApplicationContext() {
35 | if (applicationContext == null) {
36 | applicationContext = createApplicationContext();
37 | }
38 |
39 | return applicationContext;
40 | }
41 |
42 | @Override
43 | public void stop() {
44 | // close applicationContext
45 | if (applicationContext instanceof ConfigurableApplicationContext) {
46 | ((ConfigurableApplicationContext) applicationContext).close();
47 | }
48 |
49 | applicationContext = null;
50 | }
51 |
52 | protected abstract ApplicationContext createApplicationContext();
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/pf4j-spring/src/main/java/org/pf4j/spring/SpringPluginManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.pf4j.spring;
17 |
18 | import org.pf4j.DefaultPluginManager;
19 | import org.pf4j.ExtensionFactory;
20 | import org.springframework.beans.BeansException;
21 | import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
22 | import org.springframework.context.ApplicationContext;
23 | import org.springframework.context.ApplicationContextAware;
24 |
25 | import jakarta.annotation.PostConstruct;
26 | import java.nio.file.Path;
27 | import java.util.List;
28 |
29 | /**
30 | * @author Decebal Suiu
31 | */
32 | public class SpringPluginManager extends DefaultPluginManager implements ApplicationContextAware {
33 |
34 | private ApplicationContext applicationContext;
35 |
36 | public SpringPluginManager() {
37 | super();
38 | }
39 |
40 | public SpringPluginManager(Path... pluginsRoots) {
41 | super(pluginsRoots);
42 | }
43 |
44 | public SpringPluginManager(List pluginsRoots) {
45 | super(pluginsRoots);
46 | }
47 |
48 | @Override
49 | protected ExtensionFactory createExtensionFactory() {
50 | return new SpringExtensionFactory(this);
51 | }
52 |
53 | @Override
54 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
55 | this.applicationContext = applicationContext;
56 | }
57 |
58 | public ApplicationContext getApplicationContext() {
59 | return applicationContext;
60 | }
61 |
62 | /**
63 | * This method load, start plugins and inject extensions in Spring
64 | */
65 | @PostConstruct
66 | public void init() {
67 | loadPlugins();
68 | startPlugins();
69 |
70 | AbstractAutowireCapableBeanFactory beanFactory = (AbstractAutowireCapableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
71 | ExtensionsInjector extensionsInjector = new ExtensionsInjector(this, beanFactory);
72 | extensionsInjector.injectExtensions();
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.sonatype.oss
6 | oss-parent
7 | 7
8 |
9 |
10 | 4.0.0
11 | org.pf4j
12 | pf4j-spring-parent
13 | 0.11.0-SNAPSHOT
14 | pom
15 | PF4J-Spring Parent
16 | PF4J-Spring Integration
17 |
18 |
19 |
20 | The Apache Software License, Version 2.0
21 | http://www.apache.org/licenses/LICENSE-2.0.txt
22 | repo
23 |
24 |
25 |
26 |
27 | scm:git:https://github.com/pf4j/pf4j-spring.git
28 | scm:git:git@github.com:pf4j/pf4j-spring.git
29 | git@github.com/pf4j/pf4j-spring.git
30 | HEAD
31 |
32 |
33 |
34 |
35 | ossrh
36 | https://oss.sonatype.org/content/repositories/snapshots
37 |
38 |
39 | ossrh
40 | https://oss.sonatype.org/service/local/staging/deploy/maven2
41 |
42 |
43 |
44 |
45 | UTF-8
46 | 17
47 |
48 | 3.13.0
49 | 6.2.2
50 | 2.0.16
51 |
52 | 4.12
53 | 2.0.28-beta
54 | 2.7
55 | 3.1.0
56 |
57 | false
58 | false
59 | false
60 |
61 | pf4j
62 | https://sonarcloud.io
63 |
64 |
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-compiler-plugin
70 | 3.8.0
71 |
72 | ${java.version}
73 | ${java.version}
74 | true
75 |
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-javadoc-plugin
81 | 3.0.1
82 |
83 | ${javadoc.disabled}
84 |
85 |
86 |
87 |
88 | jar
89 |
90 |
91 |
92 |
93 |
94 |
95 | org.apache.maven.plugins
96 | maven-source-plugin
97 | 3.0.1
98 |
99 | ${source.disabled}
100 |
101 |
102 |
103 |
104 | jar
105 |
106 |
107 |
108 |
109 |
110 |
111 | org.apache.maven.plugins
112 | maven-deploy-plugin
113 | 2.8.1
114 |
115 | ${deploy.disabled}
116 |
117 |
118 |
119 |
120 | org.apache.maven.plugins
121 | maven-release-plugin
122 | 2.5.3
123 |
124 | deploy
125 | true
126 | release-@{project.version}
127 |
128 |
129 |
130 |
131 | org.apache.maven.plugins
132 | maven-resources-plugin
133 | 3.1.0
134 |
135 |
136 |
137 | org.apache.maven.plugins
138 | maven-surefire-plugin
139 | 2.22.1
140 |
141 |
142 |
143 | maven-jar-plugin
144 | 2.4
145 |
146 |
147 |
148 | true
149 | true
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | pf4j-spring
159 | demo
160 |
161 |
162 |
163 |
164 | jdk8-build
165 |
166 | [1.8,)
167 |
168 |
169 | none
170 |
171 |
172 |
173 | travis
174 |
175 |
176 | env.TRAVIS
177 | true
178 |
179 |
180 |
181 |
182 |
183 | org.codehaus.mojo
184 | cobertura-maven-plugin
185 | ${cobertura.version}
186 |
187 |
188 | xml
189 |
190 |
191 |
192 |
193 | org.eluder.coveralls
194 | coveralls-maven-plugin
195 | ${coveralls.version}
196 |
197 |
198 |
199 |
200 |
201 | release-sign-artifacts
202 |
203 |
204 | performRelease
205 | true
206 |
207 |
208 |
209 |
210 |
211 | org.apache.maven.plugins
212 | maven-gpg-plugin
213 |
214 |
215 | sign-artifacts
216 | verify
217 |
218 | sign
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | jdk9-build
228 |
229 | [1.9,)
230 |
231 |
232 |
233 |
234 | javax.annotation
235 | javax.annotation-api
236 | 1.3.2
237 |
238 |
239 |
240 |
241 |
242 |
243 |
--------------------------------------------------------------------------------
/run-demo.bat:
--------------------------------------------------------------------------------
1 | REM
2 | REM This script creates and run the pf4j-spring demo.
3 | REM
4 |
5 | REM create artifacts using maven
6 | call mvn clean package -DskipTests
7 |
8 | REM create demo-dist folder
9 | rmdir demo-dist /s /q
10 | mkdir demo-dist
11 | mkdir demo-dist\plugins
12 |
13 | REM copy artifacts to demo-dist folder
14 | xcopy demo\app\target\pf4j-spring-demo-app-*.zip demo-dist /s /i
15 | xcopy demo\plugins\plugin1\target\pf4j-spring-demo-plugin1-*.zip demo-dist\plugins /s
16 | xcopy demo\plugins\plugin2\target\pf4j-spring-demo-plugin2-*.zip demo-dist\plugins /s
17 | xcopy demo\plugins\enabled.txt demo-dist\plugins /s
18 | xcopy demo\plugins\disabled.txt demo-dist\plugins /s
19 |
20 | cd demo-dist
21 |
22 | REM unzip app
23 | jar xf pf4j-spring-demo-app-*.zip
24 | del pf4j-spring-demo-app-*.zip
25 |
26 | REM run demo
27 | rename pf4j-spring-demo-app-*-SNAPSHOT.jar pf4j-spring-demo.jar
28 | java -jar pf4j-spring-demo.jar
29 |
30 | cd ..
31 |
--------------------------------------------------------------------------------
/run-demo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This script creates and run the pf4j-spring demo.
5 | #
6 |
7 | # create artifacts using maven
8 | mvn clean package -DskipTests
9 |
10 | # create demo-dist folder
11 | rm -fr demo-dist
12 | mkdir -p demo-dist/plugins
13 |
14 | # copy artifacts to demo-dist folder
15 | cp demo/app/target/pf4j-spring-demo-*.zip demo-dist/
16 | cp demo/plugins/plugin1/target/pf4j-spring-demo-plugin1-*.zip demo-dist/plugins/
17 | cp demo/plugins/plugin2/target/pf4j-spring-demo-plugin2-*.zip demo-dist/plugins/
18 | cp demo/plugins/enabled.txt demo-dist/plugins/
19 | cp demo/plugins/disabled.txt demo-dist/plugins/
20 |
21 | cd demo-dist
22 |
23 | # unzip app
24 | jar xf pf4j-spring-demo-app-*.zip
25 | rm pf4j-spring-demo-app-*.zip
26 |
27 | # run demo
28 | mv pf4j-spring-demo-app-*-SNAPSHOT.jar pf4j-spring-demo.jar
29 | java -jar pf4j-spring-demo.jar
30 |
31 | cd -
32 |
--------------------------------------------------------------------------------