Skip to content

8. Creazione di un plugin

È possibile creare applicazioni denominate plugin che vengono caricate all’avvio di un’applicazione Struts e scaricate al momento della sua chiusura. Ciò consente tipicamente di eseguire operazioni di inizializzazione all’avvio dell’applicazione e di liberare le risorse al momento della sua chiusura. Queste operazioni possono essere eseguite anche derivando la classe ActionServlet dal controller, come è stato fatto nell’applicazione precedente. Il plugin rappresenta un’alternativa a questa soluzione. Il plugin può essere un’applicazione più complessa di una semplice inizializzazione dell’ambiente. Ne abbiamo visto un esempio nella lezione in cui sono stati introdotti i concetti delle regole di validazione dichiarative. Un plugin viene dichiarato nel file di configurazione di Struts. Il plugin ValidatorPlugIn era così dichiarato nel file struts-config.xml dell’applicazione che lo utilizzava:

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

Descriviamo ora un'applicazione Struts che utilizza un plugin.

8.1. Configurazione dell'applicazione Struts /plugin1

Ci proponiamo di realizzare l'applicazione Struts /plugin1 configurata come segue:

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>

Non ci soffermeremo su questo file, che è 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>

Abbiamo inserito solo una sezione, quella relativa al plugin. Gli attributi del tag <plug-in> utilizzati in questo caso sono i seguenti:

className
nome della classe del plugin
<set-property>
consente di inizializzare il plugin con coppie (chiave, valore)

Lo scopo di questa applicazione è mostrare come il plugin possa recuperare i propri parametri di inizializzazione e renderli disponibili agli altri oggetti che condividono lo stesso contesto applicativo. Utilizzeremo una semplice vista JSP per visualizzare i valori di inizializzazione del plugin, il che spiega perché non vi sia alcuna azione nel file di configurazione.

8.2. La classe Java del plugin

Una classe Java che funge da plugin per un'applicazione Struts deve implementare l'interfaccia org.apache.struts.action.PlugIn. Tale implementazione consiste nello scrivere due metodi:

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

Quando l'applicazione Struts verrà caricata, il suo controller istanzierà tutti i plugin dichiarati nel file struts-config.xml. Successivamente, eseguirà il metodo init di ciascuno di essi. È all'interno di questo metodo che il plugin esegue le proprie inizializzazioni. In questo caso, ci limiteremo a leggere i parametri di inizializzazione del plugin e a inserirli nel contesto dell’applicazione, in modo che siano disponibili per tutti gli altri oggetti della stessa. Quando l’applicazione verrà scaricata, il controller eseguirà il metodo destroy di ciascuno dei plugin caricati. È il momento di liberare le risorse che non sono più necessarie. In questo caso, non dovremo fare nulla.

Il codice della classe è il seguente:

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 {

    // metodo chiamato al momento della rimozione del contesto dell'applicazione
    public void destroy() {
    }

     // metodo chiamato durante la creazione iniziale del contesto dell'applicazione
    public void init(ActionServlet servlet, ModuleConfig conf)
        throws ServletException {
         // nome della classe di questo oggetto
        String className=this.getClass().getName();
        // elenco dei plugin
        PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
         // ricerca tra i plugin per individuare quello
         // che porta il nome di questa classe
        boolean trouvé=false;
        for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
            // nome del plugin
            String pluginClassName=pluginConfigs[i].getClassName();
             // se non è il plugin corretto, si prosegue
            if(! pluginClassName.equals(className)) continue;
            // è quello giusto: si memorizzano le sue proprietà nel contesto
            servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
            trouvé=true;
        }//for i
    } //init
} //classe

Da notare i seguenti punti:

  • il metodo init riceve un parametro denominato qui conf di tipo ModuleConfig che consente di accedere al contenuto del file struts-config.xml.
  • il metodo [ModuleConfig].findPlugInConfigs() consente di recuperare tutte le sezioni <plug-in> del file di configurazione di Struts sotto forma di un array di oggetti PlugInConfig.
  • La classe PluginConfig rappresenta una sezione <plug-in> del file di configurazione. Il metodo [PlugInConfig].getProperties ci permette di accedere agli elementi <set-property> della sezione sotto forma di un dizionario java.util.Map.
  • Il dizionario delle proprietà del plugin viene inserito nel contesto dell'applicazione.
  • Poiché possono esserci più plugin, dobbiamo individuare quello che ci interessa. Si tratta di quello che porta lo stesso nome della classe in esecuzione.

In questo caso abbiamo preferito inserire l’intero dizionario nel contesto. Avremmo potuto scegliere di utilizzarlo. La seguente sequenza di codice illustra un modo per farlo:

            Map initialisations = pluginConfigs[i].getProperties();
             // iterare sulle voci del dizionario
            Iterator entrées = initialisations.entrySet().iterator();
            while (entrées.hasNext()) {
                 // recuperare la voce (chiave, valore) corrente
                Map.Entry entrée = (Map.Entry) entrées.next();
                String clé = (String) entrée.getKey();
                String valeur = (String) entrée.getValue();
                // elaborare (chiave, valore)
                //...
            }

8.3. Il codice della vista infos.jsp

La vista infos.jsp ha il compito di visualizzare il contenuto del dizionario delle proprietà del plugin che è stato inserito nel contesto dell'applicazione. Poiché la vista infos.jsp fa parte di questo contesto, può accedervi. Il suo codice è il seguente:

<%@ 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>

Note:

  • utilizziamo le librerie di tag struts-logic e struts-bean
  • il tag <logic:iterate> ci permette di visualizzare il dizionario delle inizializzazioni che è stato inserito nel contesto dal metodo init del plugin. L'attributo name indica l'oggetto su cui eseguire l'iterazione. Deve trattarsi di qualcosa che assomigli a una collezione, un iteratore, ... L'oggetto viene cercato in tutti gli ambiti (pagina, richiesta, sessione, contesto). In questo caso verrà trovato nell’ambito context. Il parametro id serve ad assegnare un nome all’elemento corrente della collezione man mano che si procede con le iterazioni. Qui, nel corpo del tag <logic:iterate>, element rappresenterà l’elemento corrente di un dizionario. Quest’ultimo è rappresentato da un oggetto java.util.Map.Entry che è, in sostanza, una coppia (chiave, valore) del dizionario.
  • Nel corpo del tag <logic:iterate>, si visualizza (<bean:write>) il contenuto dell’elemento corrente element. Quest’ultimo è considerato come un oggetto con due proprietà (property): la chiave key e il valore value. Queste due proprietà vengono visualizzate.

8.4. Distribuzione

Il contesto dell’applicazione è definito nel file di configurazione server.xml di Tomcat:

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

La struttura dell’applicazione è la seguente:

 
 

8.5. I test

Avviamo Tomcat e richiediamo l'http://localhost:8080/plugin1/infos.jsp: URL:

Image

Constatiamo che la vista infos.jsp ha effettivamente avuto accesso alle informazioni memorizzate nel contesto dell'applicazione tramite il plugin.

8.6. Conclusione

Abbiamo dimostrato che è possibile inizializzare un'applicazione Struts utilizzando un plugin. Questa può rappresentare una soluzione alternativa a quella di derivare la classe ActionServlet per svolgere la stessa operazione.