Skip to content

8. Een plug-in maken

Het is mogelijk om applicaties, zogenaamde plug-ins, te maken die bij het opstarten van een Struts-applicatie worden geladen en bij het afsluiten ervan worden ontladen. Dit maakt het doorgaans mogelijk om initialisaties uit te voeren bij het opstarten van de applicatie en om bronnen vrij te geven bij het afsluiten ervan. Deze bewerkingen kunnen ook worden uitgevoerd door de klasse ActionServlet af te leiden van de controller, en dat is wat er in de vorige toepassing is gedaan. De plug-in is een alternatief voor deze oplossing. De plug-in kan een complexere toepassing zijn dan alleen het initialiseren van de omgeving. We hebben hier een voorbeeld van gezien in de les waarin de begrippen van declaratieve validatieregels werden geïntroduceerd. Een plug-in wordt gedeclareerd in het configuratiebestand van Struts. De plug-in ValidatorPlugIn werd dus als volgt gedeclareerd in het bestand struts-config.xml van de applicatie die er gebruik van maakte:

    <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 beschrijven nu een Struts-applicatie die gebruikmaakt van een plug-in.

8.1. Configuratie van de Struts-applicatie /plugin1

We stellen voor om de Struts-applicatie /plugin1 te bouwen, die als volgt is geconfigureerd:

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 zullen niet verder ingaan op dit standaardbestand.

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 hebben slechts één sectie toegevoegd, namelijk die voor de plug-in. De attributen van de <plug-in>-tag die hier worden gebruikt, zijn de volgende:

className
naam van de klasse van de plug-in
<set-property>
maakt het mogelijk de plug-in te initialiseren met (sleutel, waarde)-paren

Het doel van deze toepassing is om te laten zien hoe de plug-in zijn initialisatieparameters kan ophalen en deze beschikbaar kan maken voor andere objecten die dezelfde applicatiecontext delen. We zullen een eenvoudige weergave JSP gebruiken om de initialisatiewaarden van de plug-in weer te geven, wat verklaart waarom er geen actie in het configuratiebestand staat.

8.2. De Java-klasse van de plug-in

Een Java-klasse die als plug-in voor een Struts-toepassing dient, moet de interface org.apache.struts.action.PlugIn implementeren. Deze implementatie bestaat uit het schrijven van twee methoden:

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

Wanneer de Struts-applicatie wordt geladen, zal de controller alle plug-ins instantiëren die zijn gedeclareerd in het bestand struts-config.xml. Vervolgens voert hij de methode init van elk van deze plug-ins uit. In deze methode voert de plug-in zijn initialisaties uit. Hier beperken we ons tot het inlezen van de initialisatieparameters van de plug-in en deze in de context van de applicatie te plaatsen, zodat ze beschikbaar zijn voor alle andere objecten daarin. Wanneer de applicatie wordt ontladen, voert de controller de methode destroy van elke geladen plug-in uit. Dit is het moment om overbodige bronnen vrij te geven. Hier hoeven we niets te doen.

De code van de klasse is als volgt:

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 {

    // methode die wordt aangeroepen bij het verwijderen van de applicatiecontext
    public void destroy() {
    }

     // methode aangeroepen bij het voor het eerst aanmaken van de applicatiecontext
    public void init(ActionServlet servlet, ModuleConfig conf)
        throws ServletException {
         // naam van de klasse van dit object
        String className=this.getClass().getName();
        // lijst met plug-ins
        PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
         // doorzoeken van de plug-ins om degene te vinden
         // die de naam van deze klasse draagt
        boolean trouvé=false;
        for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
            // naam van de plug-in
            String pluginClassName=pluginConfigs[i].getClassName();
             // als dit niet de juiste plug-in is, gaan we verder
            if(! pluginClassName.equals(className)) continue;
            // dit is de juiste – we slaan de eigenschappen ervan op in de context
            servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
            trouvé=true;
        }//for i
    } //init
} //klasse

Let op de volgende punten:

  • de methode init ontvangt een parameter die hier conf wordt genoemd, van het type ModuleConfig, die toegang geeft tot de inhoud van het bestand struts-config.xml.
  • Met de methode [ModuleConfig].findPlugInConfigs() kunnen alle <plug-in>-secties uit het Struts-configuratiebestand worden opgehaald in de vorm van een array van PlugInConfig-objecten.
  • De klasse PluginConfig vertegenwoordigt een <plug-in>-sectie van het configuratiebestand. Met de methode [PlugInConfig].getProperties krijgen we toegang tot de <set-property>-elementen van de sectie in de vorm van een woordenboek java.util.Map.
  • Het woordenboek met de eigenschappen van de plug-in wordt in de context van de applicatie geplaatst.
  • Aangezien er meerdere plug-ins kunnen zijn, moeten we degene vinden die voor ons van belang is. Dit is de plug-in met dezelfde naam als de klasse die wordt uitgevoerd.

We hebben er hier de voorkeur aan gegeven om het volledige woordenboek in de context op te nemen. We hadden er ook gebruik van kunnen maken. De volgende codereeks illustreert een manier om dit te doen:

            Map initialisations = pluginConfigs[i].getProperties();
             // door de items in het woordenboek lopen
            Iterator entrées = initialisations.entrySet().iterator();
            while (entrées.hasNext()) {
                 // het huidige item (sleutel, waarde) ophalen
                Map.Entry entrée = (Map.Entry) entrées.next();
                String clé = (String) entrée.getKey();
                String valeur = (String) entrée.getValue();
                // (sleutel, waarde) verwerken
                //...
            }

8.3. De code van de weergave infos.jsp

De weergave infos.jsp is bedoeld om de inhoud van het eigenschappenwoordenboek van de plug-in weer te geven die in de context van de applicatie is geplaatst. Aangezien de weergave infos.jsp deel uitmaakt van deze context, heeft deze er toegang toe. De code ervan is als volgt:

<%@ 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>Infos du plugin<br></h3>
        <table border="1">
            <tr>
                <th>Clé</th><th>Valeur</th>
            </tr>            
            <logic:iterate id="element" name="initialisations">
                <tr>
                    <td><bean:write name="element" property="key"/></td>
                    <td><bean:write name="element" property="value"/></td>
                </tr>
            </logic:iterate>
        </table>
    </body>
</html>

Opmerkingen:

  • we gebruiken de tagbibliotheken struts-logic en struts-bean
  • met de tag <logic:iterate> kunnen we het initialisatiewoordenboek weergeven dat door de init-methode van de plug-in in de context is geplaatst. Het attribuut name geeft het object aan waarover moet worden geïtereerd. Dit moet iets zijn dat lijkt op een verzameling, een iterator, ... Het object wordt gezocht in alle scopes (pagina, verzoek, sessie, context). Hier wordt het gevonden in de context-scope. De parameter id wordt gebruikt om het huidige element van de verzameling tijdens de iteraties een naam te geven. Hier, in de body van de tag <logic:iterate>, vertegenwoordigt element het huidige element van een woordenboek. Dit wordt vertegenwoordigd door een object java.util.Map.Entry, dat grofweg een (sleutel, waarde)-paar uit het woordenboek is.
  • In de body van de tag <logic:iterate> wordt de inhoud van het huidige element element weergegeven (<bean:write>). Dit wordt beschouwd als een object met twee eigenschappen (property): de sleutel key en de waarde value. Deze twee eigenschappen worden weergegeven.

8.4. Implementatie

De context van de applicatie wordt gedefinieerd in het Tomcat-configuratiebestand server.xml:

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

De structuur van de applicatie is als volgt:

 
 

8.5. De tests

We starten Tomcat en roepen de URL-http://localhost:8080/plugin1/infos.jsp op:

Image

We zien dat de weergave infos.jsp inderdaad toegang heeft gekregen tot de informatie die door de plug-in in de applicatiecontext is opgeslagen.

8.6. Conclusie

We hebben aangetoond dat het mogelijk is om een Struts-applicatie te initialiseren met behulp van een plug-in. Dit kan een alternatief zijn voor het afleiden van de klasse ActionServlet om hetzelfde te bereiken.