8. Creación de un complemento
Es posible crear aplicaciones llamadas complementos que se cargan al iniciar una aplicación Struts y se descargan al cerrarla. Esto permite, por lo general, realizar inicializaciones al iniciar la aplicación y liberar recursos al cerrarla. Estas operaciones también se pueden realizar derivando la clase ActionServlet del controlador, y eso es lo que se hizo en la aplicación anterior. El complemento es una alternativa a esta solución. El complemento puede ser una aplicación más compleja que una simple inicialización del entorno. Vimos un ejemplo de esto en la lección donde se introdujeron los conceptos de reglas de validación declarativas. Un complemento se declara en el archivo de configuración de Struts. El complemento ValidatorPlugIn se declaraba así en el archivo struts-config.xml de la aplicación que lo utilizaba:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
/>
</plug-in>
Ahora describiremos una aplicación Struts que utiliza un complemento.
8.1. Configuración de la aplicación Struts /plugin1
Nos proponemos desarrollar la aplicación Struts /plugin1 configurada de la siguiente manera:
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>
No nos detendremos en este archivo, ya que es estándar.
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>
Solo hemos incluido una sección, la del complemento. Los atributos de la etiqueta <plug-in> que se utilizan aquí son los siguientes:
nombre de la clase del complemento | |
permite inicializar el complemento con pares (clave, valor) |
El objetivo de esta aplicación es mostrar cómo el complemento puede recuperar sus parámetros de inicialización y ponerlos a disposición de otros objetos que comparten el mismo contexto de aplicación. Utilizaremos una vista sencilla, JSP, para mostrar los valores de inicialización del complemento, lo que explica por qué no hay ninguna acción en el archivo de configuración.
8.2. La clase Java del complemento
Una clase Java que sirva como complemento para una aplicación Struts debe implementar la interfaz org.apache.struts.action.PlugIn. Esta implementación consiste en escribir dos métodos:
- public void init(ActionServlet servlet, ModuleConfig conf)
- public void destroy()
Cuando se cargue la aplicación Struts, su controlador creará instancias de todos los complementos declarados en el archivo struts-config.xml. Luego, ejecutará el método init de cada uno de ellos. Es en este método donde el complemento realiza sus inicializaciones. Aquí, nos limitaremos a leer los parámetros de inicialización del complemento y a colocarlos en el contexto de la aplicación para que estén disponibles para todos los demás objetos de la misma. Cuando la aplicación vaya a ser descargada, el controlador ejecutará el método destroy de cada uno de los complementos cargados. Este es el momento de liberar los recursos que ya no son necesarios. Aquí, no tendremos nada que hacer.
El código de la clase es el siguiente:
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 llamado al eliminar el contexto de la aplicación
public void destroy() {
}
// método llamado al crear inicialmente el contexto de la aplicación
public void init(ActionServlet servlet, ModuleConfig conf)
throws ServletException {
// nombre de la clase de este objeto
String className=this.getClass().getName();
// lista de complementos
PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
// búsqueda entre los complementos para encontrar aquel
// que lleva el nombre de esta clase
boolean trouvé=false;
for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
// nombre del complemento
String pluginClassName=pluginConfigs[i].getClassName();
// si no es el complemento correcto, seguimos
if(! pluginClassName.equals(className)) continue;
// es el correcto: guardamos sus propiedades en el contexto
servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
trouvé=true;
}//for i
} //init
} //clase
Tenga en cuenta lo siguiente:
- el método init recibe un parámetro llamado aquí conf, de tipo ModuleConfig, que da acceso al contenido del archivo struts-config.xml.
- El método [ModuleConfig].findPlugInConfigs() permite recuperar todas las secciones <plug-in> del archivo de configuración de Struts en forma de una matriz de objetos PlugInConfig.
- La clase PluginConfig representa una sección <plug-in> del archivo de configuración. El método [PlugInConfig].getProperties nos permite acceder a los elementos <set-property> de la sección en forma de un diccionario java.util.Map.
- El diccionario de propiedades del complemento se coloca en el contexto de la aplicación.
- Dado que puede haber varios complementos, debemos identificar el que nos interesa. Es aquel que lleva el mismo nombre que la clase que se está ejecutando.
En este caso, hemos preferido colocar todo el diccionario en el contexto. Podríamos haber querido aprovechar este. La siguiente secuencia de código ilustra una forma de hacerlo:
Map initialisations = pluginConfigs[i].getProperties();
// recorrer las entradas del diccionario
Iterator entrées = initialisations.entrySet().iterator();
while (entrées.hasNext()) {
// obtener la entrada (clave, valor) actual
Map.Entry entrée = (Map.Entry) entrées.next();
String clé = (String) entrée.getKey();
String valeur = (String) entrée.getValue();
// procesar (clave, valor)
//...
}
8.3. El código de la vista infos.jsp
La vista infos.jsp se encarga de visualizar el contenido del diccionario de propiedades del complemento que se ha incorporado al contexto de la aplicación. Como la vista infos.jsp forma parte de este contexto, tiene acceso a él. Su código es el siguiente:
<%@ 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>
Notas:
- utilizamos las bibliotecas de etiquetas struts-logic y struts-bean
- La etiqueta <logic:iterate> nos permite mostrar el diccionario de inicializaciones que el método init del complemento ha colocado en el contexto. El atributo name designa el objeto sobre el que se debe iterar. Debe ser algo que se parezca a una colección, un iterador, etc. El objeto se busca en todos los ámbitos (página, solicitud, sesión, contexto). En este caso, se encontrará en el ámbito «context». El parámetro «id» sirve para asignar un nombre al elemento actual de la colección a medida que avanzan las iteraciones. Aquí, en el cuerpo de la etiqueta <logic:iterate>, element representará el elemento actual de un diccionario. Este está representado por un objeto java.util.Map.Entry, que es, a grandes rasgos, un par (clave, valor) del diccionario.
- En el cuerpo de la etiqueta <logic:iterate>, se muestra (<bean:write>) el contenido del elemento actual element. Este se considera un objeto con dos propiedades (property): la clave key y el valor value. Se muestran estas dos propiedades.
8.4. Implementación
El contexto de la aplicación se define en el archivo de configuración server.xml de Tomcat:
<Context path="/plugin11" reloadable="true" docBase="E:\data\serge\web\struts\plugins\1" />
La estructura de la aplicación es la siguiente:
![]() ![]() | ![]() | |
![]() | ||
8.5. Las pruebas
Iniciamos Tomcat y solicitamos el URL http://localhost:8080/plugin1/infos.jsp:

Observamos que la vista infos.jsp sí tuvo acceso a la información almacenada en el contexto de la aplicación por medio del complemento.
8.6. Conclusión
Hemos demostrado que es posible inicializar una aplicación Struts mediante un complemento. Esto puede ser una alternativa a derivar la clase ActionServlet para realizar la misma tarea.



