/pf4j-wicket

Plugin Framework for Wicket (PF4J - Wicket integration)

Primary LanguageJavaApache License 2.0Apache-2.0

PF4J - Wicket integration

Travis CI Build Status Maven Central

A simple plugin framework for wicket based on PF4J. You can view pf4j-wicket as a wrapper over PF4J (that is more general and can be used to create a modular Swing application for example).

Features/Benefits

This framework is lightweight (around 10KB) with minimal dependencies (only PF4J).

The beauty of this framework is that you can start with a monolithic application and as the application grows in complexity you can split the code (without modifications) in multiple plugins.
First create a package for each future plugin in your monolithic application. After this move each package in a plugin structure. You can play in each plugin with PackageResoure, PackageResourceReference, ... from wicket without be aware that your code is located in a plugin.

Components

  • WicketPlugin is a Plugin that implements IInitializer (hook for init/destroy application).
  • PluginManagerInitializer creates the plugin manager and register the created plugin manager in application using MetaDataKey. This class load, init, start, stop and destroy plugins (using the plugin manager object).
  • PluginComponentInjector scans the wicket component class for fields annotated by @javax.inject.Inject, looks up extensions of the required type for the given field from the plugin manager, and injects the extensions.

Using Maven

In your pom.xml you must define the dependencies to wicket plugin artifacts with:

<dependency>
    <groupId>org.pf4j</groupId>
    <artifactId>pf4j-wicket</artifactId>
    <version>${pf4j-wicket.version}</version>
</dependency>

where ${pf4j-wicket.version} is the last wicket plugin version.

You may want to check for the latest released version using Maven Search

How to use

It's very easy to use pf4j-wicket. All you need to do is to add a dependency to pf4j-wicket in your pom.xml. The main challenge for you to transform a monolithic wicket application in a modular wicket application is to identify what's your extension points and to write extensions for these extension point in your plugins.

The plugins are stored in a folder. You can specify the plugins folder in many way:

  • set pf4j.pluginsDir system property
  • servlet <context-param> with name pluginsDir (in your web.xml file)
  • filter <init-param> with name pluginsDir (in your web.xml file)

The default value for plugins folder is 'plugins'.

You can define an extension point in your application using ExtensionPoint interface marker.

public abstract class Section extends AbstractImageTab implements ExtensionPoint {

    public Section(IModel<String> title) {
        super(title);
    }

}

In below code I supply an extension for the Section extension point.

public class WelcomePlugin extends WicketPlugin {

    private static WelcomePlugin instance;
    
    public WelcomePlugin(PluginWrapper wrapper) {
        super(wrapper);
        
        instance = this;
    }

    public static WelcomePlugin get() { // for a quick access to this plugin (it's optional)
        return instance;
    }
    
    @Extension
    public static class WelcomeSection extends SimpleSection {

        public WelcomeSection() {
            super(Model.of("Welcome Plugin"));
        }

        @Override
        public ResourceReference getImage() {
            return new PackageResourceReference(WelcomePlugin.class, "res/datasource.png");
        }

        @Override
        public WebMarkupContainer getPanel(String panelId) {
            return new WelcomePanel(panelId, Model.of("This plugin contributes with a css file to the head of page."));
        }

    }

}

public class WelcomePanel extends SimplePanel {
    
    public WelcomePanel(String id, IModel<String> model) {
        super(id, model);
        
        messageLabel.add(AttributeModifier.append("class", "welcome"));
    }

    @Override
    public void renderHead(IHeaderResponse response) {
        super.renderHead(response);
        
        response.render(CssHeaderItem.forReference(new PackageResourceReference(WelcomePanel.class, "res/welcome.css")));
    }

}

You can use @Inject to retrieve all extensions for Section extension point (see demo/app/.../HomePage.java).

public class HomePage extends WebPage {

    @Inject
    private List<Section> sectionExtensions; // this field is populate by pf4j-wicket

    public HomePage() {     
        ...

        // add section extensions
        sections.addAll(sectionExtensions);

        // add tabbed panel to page
        add(new ImageTabbedPanel<Section>("tabs", sections));        
    }
    
}

Another option (without annotation) to retrieves all extensions for an extension point is pluginManager.getExtensions(Section.class).
For example:

PluginManager pluginManager = Application.get().getMetaData(PluginManagerInitializer.PLUGIN_MANAGER_KEY);
List<Section> sectionExtensions = pluginManager.getExtensions(Section.class);

If you want to supply a custom PluginManager than your Application must implements PluginManagerFactory.

For more information please see the demo sources.

Demo

I have a tiny demo application. The demo application is in demo folder. In demo/api folder I declared an extension point (Section) that is a tab in a wicket TabbedPanel. Each section has an title, an icon and a content (a simple text message in my demo). In demo/plugins/* I implemented two plugins: plugin1, plugin2 (each plugin adds an extension for Section).

The first plugin contributes with some JavaScript files to the head of page and the second plugin contributes with a Css file to the head of page.

To run the demo application use:

./run-demo.sh

In the internet browser type http://localhost:8081/.

Mailing list

Much of the conversation between developers and users is managed through [mailing list] (http://groups.google.com/group/wicket-plugin).

Versioning

This project will be maintained under the Semantic Versioning guidelines as much as possible.

Releases will be numbered with the follow format:

<major>.<minor>.<patch>

And constructed with the following guidelines:

  • Breaking backward compatibility bumps the major
  • New additions without breaking backward compatibility bumps the minor
  • Bug fixes and misc changes bump the patch

For more information on SemVer, please visit http://semver.org/.