Extending an Application with Custom Plugins

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

In this tutorial, we will show how easily your our application can be made extensible using the Struts 2 plugins mechanism.

The Interface

First thing we have to do is plugin mechanism. To keep the demonstration simple, our plugin will expose a JavaBean that writes a message. Plugins may include any combination of JavaBeans, Actions, Interceptors, Results or other resources we'd like available to an application.

The Interface

At runtime, plugins are retrieved and referenced via an Interface. So, first, we should define an interface that our plugins plugin will implement. This interface must be available to both your our web application and the plugins, so keeping it on a separate jar is a good ideaplugin. To reduce coupling between the web application and the plugins, keep the interface in a separate JAR.

Code Block
Java
titleIMyPlugin.java
package example;

public interface IMyPlugIn {
   String saySomething();
}

The Plugin

Now lets create a plugin. Creating a plugin is a simple task, all you that we have an interface to implement we'll create the plugin. At load time, the framework looks for JARs containing a struts-plugin.xml file at the root of the archive. To create a plugin, all we need to do is build a jar with your classes, and a file called JAR and put the expected struts-plugin.xml on its at the root. First, the class implementing the interface defined on the first step

To get started, let's create a class that implements our IMyPlugin interface.

Code Block
Java
titleMyPlugin.java
package example.impl;

import example.IMyPlugin; 

public class MyPlugin implements IMyPlugin {
   public String saySomething() {
       return "We don't need no education";
//Sorry, I couldn't help it :)
   }
}

Now, struts-plugin.xmlInternally, the framework utilizes a number of JavaBeans. We can use the bean element to add our own JavaBeans to the set managed by the framework.

Code Block
XML
titlestruts-default.xml
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <bean type="example.IMyInterface" class="example.impl.MyPlugin" name="mypluginmyPlugin"/>
</struts>

To Finally, to install the plugin into your application, just drop the jar JAR file under WEB-INF/lib.

The Action

Now, lets get the framework to inject an instance of com.opensymphony.xwork2.inject.Container into our action, which we will use to discover available plugins at runtime. The JavaBeans configured by bean elements can be retrieved via a Container provided by XWork 2. We obtain a reference to the Container by using the @Inject notation. (This notation is part of the Guice framework that XWork and Struts use under the covers.) The framework predefines a Container object, and the @Inject annotation tells the framework to set its Container object to the Action property.

We might want to supply a number of JavaBeans to the application this way. In the Action, we will obtain a reference to the entire set of JavaBeans that might have been plugged in. Then, we can scroll through the set, displaying each JavaBean's message.

Code Block
Java
titleMyAction.java
package example.actions;

import example.IMyPlugin;

public class MyAction extends ActionSupport {
    Set<IMyPlugin> plugins;

    @Inject
    public void setContainer(Container container) {
        Set<String>  names = container.getInstanceNames(IMyPlugin.class);
        plugins = new HashSet<IMyPlugin>();
        for (String name : names) {
            plugins.add(container.getInstance(IMyPlugin.class, name));
        }
    }

     public Set<IMyPlugin> getPlugins() {
        return this.plugins;
    }
}

As seen by the Action class code, it's important to define a unique interface for any beans that we plugin, so that we can identify our beans later.

In the same way that we plugged in this JavaBean, we could also plugin and configure Action classes, Interceptors, Results, or any other JAR-able resource that an application might utilize.

The JSP

Let's do something with those plugins:

...