Skip to content

8. Creating a Plugin

It is possible to create applications called plugins that are loaded when a Struts application starts and unloaded when it shuts down. This typically allows for initialization when the application starts and resource release when it shuts down. These operations can also be performed by extending the ActionServlet class of the controller, which is what was done in the previous application. The plugin is an alternative to this solution. A plugin can be a more complex application than a simple environment initialization. We saw an example of this in the lesson where declarative validation rules were introduced. A plugin is declared in the Struts configuration file. The ValidatorPlugIn was declared in the struts-config.xml file of the application that used it as follows:

    <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
        <set-property 
        property="pathnames" 
      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
    />
    </plug-in>

We will now describe a Struts application using a plugin.

8.1. Configuration of the Struts /plugin1 application

We propose to build the Struts application /plugin1 configured as follows:

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <taglib>
      <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

</web-app>

We won’t dwell on this file, as it is standard.

struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>

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

<struts-config>

    <plug-in className="istia.st.struts.plugins.MyPlugin">
        <set-property property="passwdFileName" value="data/passwd"/>
        <set-property property="groupFileName" value="data/group"/>        
    </plug-in>

</struts-config>

We have added only one section, the one for the plugin. The attributes of the <plug-in> tag used here are as follows:

className
plugin class name
<set-property>
allows the plugin to be initialized with (key, value) pairs

The purpose of this application is to demonstrate how the plugin can retrieve its initialization parameters and make them available to other objects sharing the same application context. We will use a simple JSP view to display the plugin’s initialization values, which explains why there is no action in the configuration file.

8.2. The plugin's Java class

A Java class serving as a plugin for a Struts application must implement the org.apache.struts.action.PlugIn interface. This implementation involves writing two methods:

  • public void init(ActionServlet servlet, ModuleConfig conf)
  • public void destroy()

When the Struts application is loaded, its controller will instantiate all plugins declared in the struts-config.xml file. It will then execute the init method for each one. It is within this method that the plugin performs its initialization. Here, we will simply read the plugin’s initialization parameters and place them in the application context so that they are available to all other objects in the application. When the application is unloaded, the controller will execute the destroy method for each of the loaded plugins. This is the time to release resources that are no longer needed. Here, we will have nothing to do.

The class code is as follows:

package istia.st.struts.plugins;

import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.config.PlugInConfig;

public class MyPlugin implements PlugIn {

    // Method called when the application context is destroyed
    public void destroy() {
    }

    // Method called during the initial creation of the application context
    public void init(ActionServlet servlet, ModuleConfig conf)
        throws ServletException {
        // name of this object's class
        String className = this.getClass().getName();
        // list of plugins
        PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
        // search through the plugins to find the one
        // that has the name of this class
        boolean found = false;
        for (int i = 0; !found && i < pluginConfigs.length; i++) {
            // plugin name
            String pluginClassName = pluginConfigs[i].getClassName();
            // if it's not the right plugin, continue
            if(! pluginClassName.equals(className)) continue;
            // it's the right one - store its properties in the context
            servlet.getServletContext().setAttribute("initializations", pluginConfigs[i].getProperties());
            found=true;
        }//for i
    } //init
} //class

Please note the following points:

  • The init method takes a parameter called conf (of type ModuleConfig) that provides access to the contents of the struts-config.xml file.
  • The [ModuleConfig].findPlugInConfigs() method retrieves all <plug-in> sections from the Struts configuration file in the form of an array of PlugInConfig objects.
  • The PluginConfig class represents a <plug-in> section of the configuration file. The [PlugInConfig].getProperties method allows us to access the <set-property> elements of the section in the form of a java.util.Map dictionary.
  • The plugin's properties dictionary is placed in the application context.
  • Since there may be multiple plugins, we need to find the one we are interested in. It is the one with the same name as the class being executed.

Here, we chose to place the entire dictionary in the context. We could have chosen to use it. The following code snippet illustrates one way to do this:

            Map initializations = pluginConfigs[i].getProperties();
            // iterate over the dictionary entries
            Iterator entries = initializations.entrySet().iterator();
            while (entries.hasNext()) {
                // retrieve the current entry (key, value)
                Map.Entry entry = (Map.Entry) entries.next();
                String key = (String) entry.getKey();
                String value = (String) entry.getValue();
                // process (key, value)
                //...
            }

8.3. The code for the infos.jsp view

The infos.jsp view is responsible for displaying the contents of the plugin's property dictionary, which has been placed in the application context. Since the infos.jsp view is part of this context, it has access to it. Its code is as follows:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head>
        <title>Plugin</title>
    </head>
    <body>
        <h3>Plugin Info<br></h3>
        <table border="1">
            <tr>
                <th>Key</th><th>Value</th>
            </tr>            
            <logic:iterate id="element" name="initializations">
                <tr>
                    <td><bean:write name="element" property="key"/></td>
                    <td><bean:write name="element" property="value"/></td>
                </tr>
            </logic:iterate>
        </table>
    </body>
</html>

Notes:

  • We use the struts-logic and struts-bean tag libraries
  • The <logic:iterate> tag allows us to display the initializations dictionary that was placed in the context by the plugin's init method. The name attribute specifies the object to be iterated over. This should be something like a collection, an iterator, etc. The object is searched for in all scopes (page, request, session, context). Here, it will be found in the context scope. The id parameter is used to name the current element of the collection as the iteration proceeds. Here, within the body of the <logic:iterate> tag, element will represent the current element of a dictionary. This is represented by a java.util.Map.Entry object, which is essentially a (key, value) pair from the dictionary.
  • In the body of the <logic:iterate> tag, we display (<bean:write>) the contents of the current element element. This is treated as an object with two properties: the key and the value. Both of these properties are displayed.

8.4. Deployment

The application context is defined in Tomcat’s server.xml configuration file:

<Context path="/plugin11" reloadable="true" docBase="E:\data\serge\web\struts\plugins\1" />

The application directory structure is as follows:

 
 

8.5. Testing

We start Tomcat and request the URL http://localhost:8080/plugin1/infos.jsp:

Image

We observe that the infos.jsp view successfully accessed the information stored in the application context via the plugin.

8.6. Conclusion

We have demonstrated that a Struts application can be initialized using a plugin. This can serve as an alternative to deriving the ActionServlet class to achieve the same result.