Skip to content

8. Criação de um plugin

É possível criar aplicações denominadas «plugins», que são carregadas no arranque de uma aplicação Struts e descarregadas quando esta é encerrada. Isto permite, normalmente, realizar inicializações no arranque da aplicação e libertar recursos quando esta é encerrada. Estas operações também podem ser realizadas derivando a classe ActionServlet do controlador, e foi isso que se fez na aplicação anterior. O plugin é uma alternativa a esta solução. O plugin pode ser uma aplicação mais complexa do que uma simples inicialização do ambiente. Vimos um exemplo disso na lição em que foram introduzidos os conceitos de regras de validação declarativas. Um plugin é declarado no ficheiro de configuração do Struts. O plugin ValidatorPlugIn foi, assim, declarado no ficheiro struts-config.xml da aplicação que o utilizava:

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

Passamos agora a descrever uma aplicação Struts que utiliza um plugin.

8.1. Configuração da aplicação Struts /plugin1

Propomos construir a aplicação Struts /plugin1 configurada da seguinte forma:

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>

Não nos deteremos neste ficheiro, que é padrão.

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>

Introduzimos apenas uma secção, a do plugin. Os atributos da baliza <plug-in> utilizados aqui são os seguintes:

className
nome da classe do plugin
<set-property>
permite inicializar o plugin com pares (chave, valor)

O objetivo desta aplicação é mostrar como o plugin pode recuperar os seus parâmetros de inicialização e disponibilizá-los a outros objetos que partilhem o mesmo contexto de aplicação. Iremos utilizar uma vista simples, JSP, para apresentar os valores de inicialização do plugin, o que explica a ausência de qualquer ação no ficheiro de configuração.

8.2. A classe Java do plugin

Uma classe Java que funcione como plugin para uma aplicação Struts deve implementar a interface org.apache.struts.action.PlugIn. Esta implementação consiste em escrever dois métodos:

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

Quando a aplicação Struts for carregada, o seu controlador irá instanciar todos os plug-ins declarados no ficheiro struts-config.xml. Em seguida, executará o método init de cada um deles. É neste método que o plug-in realiza as suas inicializações. Aqui, limitar-nos-emos a ler os parâmetros de inicialização do plugin e a colocá-los no contexto da aplicação, para que fiquem disponíveis para todos os outros objetos da mesma. Quando a aplicação for descarregada, o controlador executará o método destroy de cada um dos plugins carregados. Este é o momento de libertar os recursos que já não são necessários. Aqui, não teremos nada a fazer.

O código da classe é o seguinte:

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 {

    // método chamado ao eliminar o contexto da aplicação
    public void destroy() {
    }

     // método chamado durante a criação inicial do contexto da aplicação
    public void init(ActionServlet servlet, ModuleConfig conf)
        throws ServletException {
         // nome da classe deste objeto
        String className=this.getClass().getName();
        // lista de plugins
        PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
         // análise dos plugins para encontrar aquele
         // que tenha o nome desta classe
        boolean trouvé=false;
        for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
            // nome do plugin
            String pluginClassName=pluginConfigs[i].getClassName();
             // se não for o plugin certo, continuamos
            if(! pluginClassName.equals(className)) continue;
            // é o plugin certo — guardamos as suas propriedades no contexto
            servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
            trouvé=true;
        }//for i
    } //init
} //classe

É importante ter em conta os seguintes pontos:

  • o método init recebe um parâmetro denominado aqui conf, do tipo ModuleConfig, que dá acesso ao conteúdo do ficheiro struts-config.xml.
  • O método [ModuleConfig].findPlugInConfigs() permite recuperar todas as secções <plug-in> do ficheiro de configuração do Struts sob a forma de um tabuleiro de objetos PlugInConfig.
  • A classe PluginConfig representa uma secção <plug-in> do ficheiro de configuração. O método [PlugInConfig].getProperties permite-nos aceder aos elementos <set-property> da secção sob a forma de um dicionário java.util.Map.
  • O dicionário de propriedades do plugin é colocado no contexto da aplicação.
  • Como podem existir vários plugins, temos de identificar aquele que nos interessa. É aquele que tem o mesmo nome que a classe que está a ser executada.

Neste caso, optámos por colocar o dicionário na íntegra no contexto. Poderíamos ter optado por explorar apenas parte dele. A seguinte sequência de código ilustra uma forma de o fazer:

            Map initialisations = pluginConfigs[i].getProperties();
             // iterar pelas entradas do dicionário
            Iterator entrées = initialisations.entrySet().iterator();
            while (entrées.hasNext()) {
                 // recuperar a entrada (chave, valor) atual
                Map.Entry entrée = (Map.Entry) entrées.next();
                String clé = (String) entrée.getKey();
                String valeur = (String) entrée.getValue();
                // processar (chave, valor)
                //...
            }

8.3. O código da vista infos.jsp

A vista infos.jsp tem como função visualizar o conteúdo do dicionário de propriedades do plugin que foi colocado no contexto da aplicação. Como a vista infos.jsp faz parte desse contexto, tem acesso ao mesmo. O seu código é o seguinte:

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

Pontos a ter em conta:

  • utilizamos as bibliotecas de tags struts-logic e struts-bean
  • a tag <logic:iterate> permite-nos apresentar o dicionário «initialisations», que foi inserido no contexto pelo método «init» do plugin. O atributo «name» designa o objeto sobre o qual se deve iterar. Trata-se de algo que deve assemelhar-se a uma coleção, um iterador, etc. O objeto é procurado em todos os escopos (página, pedido, sessão, contexto). Neste caso, será encontrado no âmbito «context». O parâmetro «id» serve para atribuir um nome ao elemento atual da coleção ao longo das iterações. Aqui, no corpo da baliza <logic:iterate>, element representará o elemento atual de um dicionário. Este é representado por um objeto java.util.Map.Entry, que é, em termos gerais, um par (chave, valor) do dicionário.
  • No corpo da baliza <logic:iterate>, exibe-se (<bean:write>) o conteúdo do elemento atual element. Este é considerado como um objeto com duas propriedades (property): a chave key e o valor value. Estas duas propriedades são exibidas.

8.4. Implantação

O contexto da aplicação é definido no ficheiro de configuração server.xml do Tomcat:

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

A estrutura da aplicação é a seguinte:

 
 

8.5. Os testes

Iniciamos o Tomcat e solicitamos o URL http://localhost:8080/plugin1/infos.jsp:

Image

Constatamos que a vista infos.jsp teve efetivamente acesso às informações armazenadas no contexto da aplicação pelo plugin.

8.6. Conclusão

Demonstrámos que é possível inicializar uma aplicação Struts utilizando um plugin. Esta pode ser uma solução alternativa à derivação da classe ActionServlet para realizar a mesma tarefa.