Skip to content

8. Tworzenie wtyczki

Możliwe jest tworzenie aplikacji zwanych wtyczkami, które są ładowane podczas uruchamiania aplikacji Struts i wyładowywane podczas jej zamykania. Zazwyczaj pozwala to na przeprowadzenie operacji inicjalizacji podczas uruchamiania aplikacji oraz zwolnienie zasobów podczas jej zamykania. Operacje te można również wykonać poprzez utworzenie klasy pochodnej od klasy kontrolera ActionServlet, co zrobiono w poprzedniej aplikacji. Wtyczka stanowi alternatywę dla tego rozwiązania. Wtyczka może być aplikacją bardziej złożoną niż zwykła inicjalizacja środowiska. Przykład takiego rozwiązania widzieliśmy w lekcji, w której wprowadzono pojęcia reguł walidacji deklaratywnej. Wtyczka jest deklarowana w pliku konfiguracyjnym Struts. Wtyczka ValidatorPlugIn została zatem zadeklarowana w pliku struts-config.xml aplikacji, która z niej korzystała:

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

Opisujemy teraz aplikację Struts wykorzystującą wtyczkę.

8.1. Konfiguracja aplikacji Struts /plugin1

Zamierzamy zbudować aplikację Struts /plugin1 skonfigurowaną w następujący sposób:

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>

Nie będziemy się nad tym plikiem rozwodzić, ponieważ jest to plik standardowy.

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>

Wprowadziliśmy tylko jedną sekcję – tę dotyczącą wtyczki. Atrybuty tagu <plug-in> użyte w tym przypadku są następujące:

className
nazwa klasy wtyczki
<set-property>
umożliwia zainicjowanie wtyczki za pomocą par (klucz, wartość)

Celem tej aplikacji jest pokazanie, w jaki sposób wtyczka może pobrać swoje parametry inicjalizacyjne i udostępnić je innym obiektom działającym w tym samym kontekście aplikacji. Wykorzystamy prosty widok JSP do wyświetlenia wartości inicjalizacyjnych wtyczki, co wyjaśnia brak jakichkolwiek akcji w pliku konfiguracyjnym.

8.2. Klasa Java wtyczki

Klasa Java pełniąca rolę wtyczki dla aplikacji Struts musi implementować interfejs org.apache.struts.action.PlugIn. Implementacja ta polega na napisaniu dwóch metod:

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

Gdy aplikacja Struts zostanie załadowana, jej kontroler utworzy instancje wszystkich wtyczek zadeklarowanych w pliku struts-config.xml. Następnie wywoła metodę init każdej z nich. To właśnie w tej metodzie wtyczka przeprowadza swoje inicjalizacje. W tym przypadku ograniczymy się do odczytania parametrów inicjalizacyjnych wtyczki i umieszczenia ich w kontekście aplikacji, tak aby były dostępne dla wszystkich pozostałych obiektów aplikacji. Gdy aplikacja zostanie wyładowana, kontroler wywoła metodę destroy każdej z załadowanych wtyczek. Jest to moment na zwolnienie zasobów, które stały się zbędne. W tym przypadku nie musimy nic robić.

Kod klasy wygląda następująco:

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 {

    // metoda wywoływana podczas usuwania kontekstu aplikacji
    public void destroy() {
    }

     // metoda wywołana podczas początkowego tworzenia kontekstu aplikacji
    public void init(ActionServlet servlet, ModuleConfig conf)
        throws ServletException {
         // nazwa klasy tego obiektu
        String className=this.getClass().getName();
        // lista wtyczek
        PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
         // przeglądanie wtyczek w celu znalezienia tej,
         // która nosi nazwę tej klasy
        boolean trouvé=false;
        for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
            // nazwa wtyczki
            String pluginClassName=pluginConfigs[i].getClassName();
             // jeśli to nie jest właściwa wtyczka, kontynuujemy
            if(! pluginClassName.equals(className)) continue;
            // to jest właściwa wtyczka – zapisujemy jej właściwości w kontekście
            servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
            trouvé=true;
        }//for i
    } //inicjalizacja
} //klasa

Należy zwrócić uwagę na następujące kwestie:

  • metoda init przyjmuje parametr o nazwie conf typu ModuleConfig, który zapewnia dostęp do zawartości pliku struts-config.xml.
  • Metoda [ModuleConfig].findPlugInConfigs() pozwala pobrać wszystkie sekcje <plug-in> z pliku konfiguracyjnego Struts w postaci tablicy obiektów typu PlugInConfig.
  • Klasa PluginConfig reprezentuje sekcję <plug-in> pliku konfiguracyjnego. Metoda [PlugInConfig].getProperties umożliwia nam dostęp do elementów <set-property> sekcji w postaci słownika java.util.Map.
  • Słownik właściwości wtyczki jest umieszczony w kontekście aplikacji.
  • Ponieważ może istnieć wiele wtyczek, musimy znaleźć tę, która nas interesuje. Jest to ta, która nosi tę samą nazwę co uruchamiana klasa.

W tym przypadku zdecydowaliśmy się umieścić cały słownik w kontekście. Moglibyśmy jednak chcieć wykorzystać właśnie ten słownik. Poniższy fragment kodu ilustruje jeden ze sposobów postępowania:

            Map initialisations = pluginConfigs[i].getProperties();
             // przechodzimy przez elementy słownika
            Iterator entrées = initialisations.entrySet().iterator();
            while (entrées.hasNext()) {
                 // pobieranie bieżącej pozycji (klucz, wartość)
                Map.Entry entrée = (Map.Entry) entrées.next();
                String clé = (String) entrée.getKey();
                String valeur = (String) entrée.getValue();
                // przetwarzanie (klucz, wartość)
                //...
            }

8.3. Kod widoku infos.jsp

Widok infos.jsp służy do wyświetlania zawartości słownika właściwości wtyczki, który został umieszczony w kontekście aplikacji. Ponieważ widok infos.jsp jest częścią tego kontekstu, ma do niego dostęp. Jego kod wygląda następująco:

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

Uwagi:

  • korzystamy z bibliotek tagów struts-logic i struts-bean
  • tag <logic:iterate> pozwala nam wyświetlić słownik inicjalizacji, który został umieszczony w kontekście przez metodę init wtyczki. Atrybut name określa obiekt, nad którym ma odbywać się iteracja. Powinien to być element przypominający kolekcję, iterator itp. Obiekt jest wyszukiwany we wszystkich zakresach (strona, żądanie, sesja, kontekst). W tym przypadku zostanie on znaleziony w zakresie kontekstu. Parametr id służy do nadawania nazwy bieżącemu elementowi kolekcji w trakcie iteracji. W tym przypadku, w treści tagu <logic:iterate>, element będzie reprezentował bieżący element słownika. Jest on reprezentowany przez obiekt java.util.Map.Entry, który jest w przybliżeniu parą (klucz, wartość) ze słownika.
  • W treści tagu <logic:iterate> wyświetla się (<bean:write>) zawartość bieżącego elementu element. Jest on traktowany jako obiekt posiadający dwie właściwości (property): klucz key i wartość value. Obie te właściwości są wyświetlane.

8.4. Wdrożenie

Kontekst aplikacji jest zdefiniowany w pliku konfiguracyjnym server.xml serwera Tomcat:

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

Struktura drzewa aplikacji wygląda następująco:

 
 

8.5. Testy

Uruchamiamy Tomcat i wysyłamy żądanie do serwisu URL http://localhost:8080/plugin1/infos.jsp:

Image

Stwierdzamy, że widok infos.jsp uzyskał dostęp do informacji przechowywanych w kontekście aplikacji przez wtyczkę.

8.6. Wniosek

Wykazaliśmy, że można zainicjować aplikację Struts za pomocą wtyczki. Może to stanowić alternatywę dla rozwiązania polegającego na dziedziczeniu klasy ActionServlet w celu wykonania tej samej czynności.