@ -31,9 +31,10 @@ Also, PF4J can be used in web applications. For my web applications when I want
Components
-------------------
- **Plugin** is the base class for all plugins types. Each plugin is loaded into a separate class loader to avoid conflicts.
- **PluginManager** is used for all aspects of plugins management (loading, starting, stopping).
- **PluginManager** is used for all aspects of plugins management (loading, starting, stopping). You can use a built-in implementation as `DefaultPluginManager`, `JarPluginManager` or you can implement a custom plugin manager starting from `AbstractPluginManager` (implement only factory methods).
- **PluginLoader** loads all information (classes) needed by a plugin.
- **ExtensionPoint** is a point in the application where custom code can be invoked. It's a java interface marker.
Any java interface or abstract class can be marked as an extension point (implements _ExtensionPoint_ interface).
Any java interface or abstract class can be marked as an extension point (implements `ExtensionPoint` interface).
- **Extension** is an implementation of an extension point. It's a java annotation on a class.
Artifacts
@ -81,7 +82,7 @@ It's very simple to add pf4j in your application:
```java
public static void main(String[] args) {
...
PluginManager pluginManager = new DefaultPluginManager();
pluginManager.loadPlugins();
pluginManager.startPlugins();
@ -94,7 +95,7 @@ In above code, I created a **DefaultPluginManager** (it's the default implementa
**PluginManager** interface) that loads and starts all active(resolved) plugins.
Each available plugin is loaded using a different java class loader, **PluginClassLoader**.
The **PluginClassLoader** contains only classes found in **PluginClasspath** (default _classes_ and _lib_ folders) of plugin and runtime classes and libraries of the required/dependent plugins. This class loader is a _Parent Last ClassLoader_ - it loads the classes from the plugin's jars before delegating to the parent class loader.
The plugins are stored in a folder. You can specify the plugins folder in the constructor of DefaultPluginManager. If the plugins folder is not specified
The plugins are stored in a folder. You can specify the plugins folder in the constructor of DefaultPluginManager. If the plugins folder is not specified
than the location is returned by `System.getProperty("pf4j.pluginsDir", "plugins")`.
The structure of plugins folder is:
@ -123,7 +124,7 @@ Plugin-Provider: Decebal Suiu
Plugin-Version: 0.0.1
```
In above manifest I described a plugin with id `welcome-plugin`, with class `ro.fortsoft.pf4j.demo.welcome.WelcomePlugin`, with version `0.0.1` and with dependencies
In above manifest I described a plugin with id `welcome-plugin`, with class `ro.fortsoft.pf4j.demo.welcome.WelcomePlugin`, with version `0.0.1` and with dependencies
to plugins `x, y, z`.
**NOTE:** The plugin version must be compliant with [Semantic Versioning](http://semver.org) (PF4J uses `jsemver` as implementation for SemVer because it comes with support for comparing versions)
@ -247,7 +248,7 @@ The differences between a DISABLED plugin and a STARTED plugin are:
* a STARTED plugin may contribute extension instances, a DISABLED plugin may not
DISABLED plugins still have valid class loaders and their classes can be manually
loaded and explored, but the resource loading - which is important for inspection -
loaded and explored, but the resource loading - which is important for inspection -
has been handicapped by the DISABLED check.
As integrators of pf4j evolve their extension APIs it will become
@ -267,7 +268,7 @@ Your application, as a PF4J consumer, has full control over each plugin (state).
Development mode
--------------------------
PF4J can run in two modes: **DEVELOPMENT** and **DEPLOYMENT**.
The DEPLOYMENT(default) mode is the standard workflow for plugins creation: create a new Maven module for each plugin, codding the plugin (declares new extension points and/or
The DEPLOYMENT(default) mode is the standard workflow for plugins creation: create a new Maven module for each plugin, codding the plugin (declares new extension points and/or
add new extensions), pack the plugin in a zip file, deploy the zip file to plugins folder. These operations are time consuming and from this reason I introduced the DEVELOPMENT runtime mode.
The main advantage of DEVELOPMENT runtime mode for a plugin developer is that he/she is not enforced to pack and deploy the plugins. In DEVELOPMENT mode you can developing plugins in a simple and fast mode.
@ -277,13 +278,13 @@ First, you can change the runtime mode using the "pf4j.mode" system property or
For example I run the pf4j demo in eclipse in DEVELOPMENT mode adding only `"-Dpf4j.mode=development"` to the pf4j demo launcher.
You can retrieve the current runtime mode using `PluginManager.getRuntimeMode()` or in your Plugin implementation with `getWrapper().getRuntimeMode()`(see [WelcomePlugin](https://github.com/decebals/pf4j/blob/master/demo/plugins/plugin1/src/main/java/ro/fortsoft/pf4j/demo/welcome/WelcomePlugin.java)).
The DefaultPluginManager determines automatically the correct runtime mode and for DEVELOPMENT mode overrides some components(pluginsDirectory is __"../plugins"__, __PropertiesPluginDescriptorFinder__ as PluginDescriptorFinder, __DevelopmentPluginClasspath__ as PluginClassPath).
Another advantage of DEVELOPMENT runtime mode is that you can execute some code lines only in this mode (for example more debug messages).
Another advantage of DEVELOPMENT runtime mode is that you can execute some code lines only in this mode (for example more debug messages).
**NOTE:** If you use Eclipse than make sure annotation processing is enabled at least for any projects registering objects using annotations. In the properties for your new project go to __Java Compiler > Annotation Processing__
Check the __“Enable Project Specific Settings”__ and make sure __“Enable annotation processing”__ is checked.
If you use Maven as build manger, after each dependency modification in your plugin (Maven module) you must run __Maven > Update Project...__
For more details see the demo application.
For more details see the demo application.
Enable/Disable plugins
-------------------
@ -321,24 +322,24 @@ welcome-plugin
```
All comment lines (line that start with # character) are ignored.
If a file with enabled.txt exists than disabled.txt is ignored. See enabled.txt and disabled.txt from the demo folder.
If a file with enabled.txt exists than disabled.txt is ignored. See enabled.txt and disabled.txt from the demo folder.
Default/System extension
-------------------
Starting with version 0.9 you can define an extension directly in the application jar (you're not obligated
to put the extension in a plugin - you can see this extension as a default/system extension).
See [WhazzupGreeting](https://github.com/decebals/pf4j/blob/master/demo/app/src/main/java/ro/fortsoft/pf4j/demo/WhazzupGreeting.java)
Starting with version 0.9 you can define an extension directly in the application jar (you're not obligated
to put the extension in a plugin - you can see this extension as a default/system extension).
See [WhazzupGreeting](https://github.com/decebals/pf4j/blob/master/demo/app/src/main/java/ro/fortsoft/pf4j/demo/WhazzupGreeting.java)
for a real example.
This is great for starting application phase. In this scenario you have a minimalist plugin framework with one class loader
(the application class loader), similar with Java [ServiceLoader](https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html)
This is great for starting application phase. In this scenario you have a minimalist plugin framework with one class loader
(the application class loader), similar with Java [ServiceLoader](https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html)
but with the following benefits:
- no need to write provider-configuration files in the resource directory `META-INF/services`, you using the elegant
`@Extension` annotation from PF4J
- anytime you can switch to the multiple class loader mechanism without to change one code line in your application
Of course the code present in the `Boot` class from the demo application it is functional but you can use a more minimalist code
skipping `pluginManager.loadPlugins()` and `pluginManager.startPlugins()`.
Of course the code present in the `Boot` class from the demo application it is functional but you can use a more minimalist code
skipping `pluginManager.loadPlugins()` and `pluginManager.startPlugins()`.
```java
public static void main(String[] args) {
@ -367,19 +368,19 @@ public static void main(String[] args) {
ServiceLoader interoperability
-------------------
Starting with version 0.12 PF4J comes with a better support for `ServiceLoader`.
PF4J can read `META-INF/services` (Java Service Provider mechanism) as extensions, so,
if you have a modular application based on `java.util.ServiceLoader` class you can replace entirely the `ServiceLoader.load()`
PF4J can read `META-INF/services` (Java Service Provider mechanism) as extensions, so,
if you have a modular application based on `java.util.ServiceLoader` class you can replace entirely the `ServiceLoader.load()`
calls from your application with `PluginManager.getExtensions()` and migrate smooth from ServiceLoader to PF4J.
Also you have the possibility to change the `ExtensionStorage` used in `ExtensionAnnotationProcessor`.
Also you have the possibility to change the `ExtensionStorage` used in `ExtensionAnnotationProcessor`.
By default we use the format with `META-INF/extensions.idx`
```
ro.fortsoft.pf4j.demo.HowdyGreeting
ro.fortsoft.pf4j.demo.WhazzupGreeting
```
but you can use a more standard location and format, `META-INF/services/<extension-point>`, used by Java Service Provider
(see `java.util.ServiceLoader`) via `ServiceProviderExtensionStorage` implementation.
but you can use a more standard location and format, `META-INF/services/<extension-point>`, used by Java Service Provider
(see `java.util.ServiceLoader`) via `ServiceProviderExtensionStorage` implementation.
In this case the format of `META-INF/services/ro.fortsoft.pf4j.demo.api.Greeting` is