04. ManualConfiguracion_openFWPA_20111230_v1.0

Anuncio
openFWPA Internacional
openFWPA
Manual de configuración de openFWPA
(ManualConfiguración_openFWPA_20111230_v1.0)
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
2 de
296
ÍNDICE
1. Control del documento..........................................................................................................................8
1.1. Información general .......................................................................................................................8
1.2. Histórico de revisiones...................................................................................................................8
1.3. Estado del documento ....................................................................................................................8
2. Introducción ..........................................................................................................................................9
3. Desarrollo de aplicaciones ....................................................................................................................9
3.1. Estructura de directorios ..............................................................................................................10
3.2. Compilación y despliegue del sistema .........................................................................................10
3.3. Pruebas unitarias ..........................................................................................................................11
4. Sistema de Logging (log4j).................................................................................................................12
4.1. Loggers.........................................................................................................................................13
4.2. Appenders ....................................................................................................................................14
4.3. Layouts.........................................................................................................................................15
4.4. Configuración...............................................................................................................................15
4.4.1. Ejemplo de configuración .....................................................................................................19
4.5. Componentes del openFWPA para Logging ...............................................................................23
4.5.1. LoggingManager...................................................................................................................23
4.5.2. PrincastHTMLLayout ...........................................................................................................25
4.5.3. Pistas de auditoría .................................................................................................................25
4.5.4. Pistas de rendimiento ............................................................................................................26
5. Spring ..................................................................................................................................................27
5.1. Spring en openFWPA ..................................................................................................................28
5.2. Estableciendo el datasource .........................................................................................................32
5.3. Enlazando con los DAOs .............................................................................................................35
5.4. Enlazando con los Manager .........................................................................................................36
5.4.1. Gestión de transacciones.......................................................................................................38
5.5. Enlazando con los Delegate .........................................................................................................40
5.6. Enlazando con los Actions...........................................................................................................40
6. Capa de acceso a datos........................................................................................................................41
6.1. Alternativas para implementar la capa de acceso a datos ............................................................42
6.2. ¿Qué es iBATIS? .........................................................................................................................43
6.2.1. iBATIS en openFWPA .........................................................................................................44
6.3. Pool de conexiones.......................................................................................................................51
6.3.1. Datasource en Apache Tomcat .............................................................................................54
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
3 de
296
6.4. Pruebas unitarias ..........................................................................................................................55
6.4.1. Convenciones a seguir ..........................................................................................................56
6.4.2. Pruebas unitarias de objetos que acceden a bases de datos...................................................57
6.4.2.1. Pruebas unitarias de DAOs ............................................................................................60
6.4.2.2. Más información sobre la implementación de pruebas unitarias ...................................63
7. Capa de negocio ..................................................................................................................................64
7.1. Business Managers.......................................................................................................................64
7.1.1. Prueba unitaria sobre la capa Manager .................................................................................66
7.2. Business Delegate ........................................................................................................................71
8. Controlador .........................................................................................................................................76
8.1. web.xml........................................................................................................................................78
8.2. Declaración de las Actions...........................................................................................................86
8.3. Jerarquía de Actions.....................................................................................................................90
8.3.1. Clase PrincastAction .............................................................................................................92
8.3.1.1. Creando un error en una PrincastAction ........................................................................94
8.3.1.2. Creando un mensaje de advertencia en una PrincastAction ..........................................95
8.3.1.3. Modificando una redirección .........................................................................................96
8.3.1.4. Almacenamiento interno de una Action .........................................................................97
8.3.1.5. Interrupción de la maquinaria de estados de la Action ................................................100
8.3.1.5.1. Paginación sin reejecución de la lógica de negocio ..............................................100
8.3.2. Diferentes tipos de PrincastAction......................................................................................101
8.3.2.1. Implementaciones concretas ........................................................................................101
8.3.2.1.1. PrincastExistAttributeAction ................................................................................101
8.3.2.1.2. PrincastRemoveAttributeAction ...........................................................................101
8.3.2.1.3. PrincastForwardAction .........................................................................................102
8.3.2.1.4. PrincastParameterAction.......................................................................................102
8.3.2.2. Actions Compuestas (Dispatch)...................................................................................103
8.3.2.2.1. PrincastDispatchAction.........................................................................................103
8.3.2.2.2. PrincastLookupDispatchAction ............................................................................108
8.3.2.2.3. PrincastCRUDAction............................................................................................110
8.3.2.2.3.1. Validación de Formularios en acciones compuestas......................................112
8.3.2.2.4. Actions para Listados............................................................................................113
8.3.2.2.4.1. PrincastListAction..........................................................................................114
8.3.2.2.4.2. PrincastPDFReportAction..............................................................................114
8.3.2.2.4.3. PrincastDispatchPDFReportAction ...............................................................116
8.3.2.2.4.4. PrincastXMLAction .......................................................................................116
8.3.2.2.4.5. PrincastDispatchXMLAction.........................................................................119
8.4. Action Forms..............................................................................................................................119
8.4.1. Validación de formularios...................................................................................................124
8.4.1.1. Validaciones de openFWPA ........................................................................................126
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
4 de
296
8.4.1.2. Implementación de validadores ...................................................................................128
8.5. Mapeo en el fichero struts-config.xml .......................................................................................130
9. La vista..............................................................................................................................................140
9.1. Hojas de estilo (CSS) .................................................................................................................140
9.1.1. Hojas de estilo en la aplicación de ejemplo ........................................................................140
9.2. Composición de las páginas JSP (vistas) ...................................................................................145
9.3. Pantalla de error .........................................................................................................................154
9.4. Tablas de paginación..................................................................................................................155
9.5. Creación de menús .....................................................................................................................161
9.5.1. Información general ............................................................................................................161
9.5.2. Definir los menús ................................................................................................................163
9.5.3. Displayers específicos de openFWPA ................................................................................167
9.5.4. Enlaces en los menús ..........................................................................................................168
9.5.5. Integración de Struts-menu con una aplicación Struts........................................................169
9.5.6. La librería de tags struts-menu-el.tld ..................................................................................171
9.5.7. Uso de la librería de tags en la página menu.jsp.................................................................171
9.5.8. Recursos utilizados por el displayer PrincastTabbedMenu ................................................172
9.5.9. Forwards a entradas de menú..............................................................................................175
9.5.10. Enlaces con parámetros dinámicos ...................................................................................176
9.6. Internacionalización ...................................................................................................................176
9.7. View Helpers, View Adapters, Acciones...................................................................................177
9.8. Accesibilidad..............................................................................................................................179
9.9. Librería de etiquetas para el diseño de interfaces de usuario (UI).............................................180
9.9.1. Selección de fechas y calendarios.......................................................................................183
9.9.1.1. Etiqueta <date:calendar/> ............................................................................................183
9.9.1.2. Configuración del calendario .......................................................................................184
9.9.1.3. Escribir la fecha actual .................................................................................................185
9.9.2. Barra de navegación............................................................................................................186
9.9.2.1. Generar una barra de navegación.................................................................................187
9.9.3. Etiquetas para componentes gráficos ..................................................................................188
9.9.3.1. Etiqueta para renderizar Paneles de Componentes para la UI (similares a los fieldset de
HTML) ......................................................................................................................................189
9.9.3.2. Etiqueta para renderiza el caption o título de las etiquetas panel ................................190
9.9.3.3. Etiqueta para generar el bloque central de información de una página con un borde
superior y otro inferior ..............................................................................................................191
9.9.3.4. Etiqueta para renderizar el caption o título de las etiquetas box..................................192
9.9.3.5. Etiqueta para renderizar un bloque en área determinada de la página sin aspecto visual
...................................................................................................................................................193
9.9.3.6. Etiqueta para renderizar elementos de bloque de tipo fila ...........................................194
9.9.3.7. Etiqueta para renderizar elementos de bloque de tipo columna...................................194
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
5 de
296
9.9.4. Notificación de errores <ui:errors>.....................................................................................196
9.9.5. Etiquetas de utilidad y propósito general ............................................................................196
9.9.5.1. Etiqueta para ocultar o mostrar código en función de un objeto .................................196
9.9.5.2. Etiqueta para generar código en función del rol de usuario (coincidencia).................197
9.9.5.3. Etiqueta para generar código en función del rol de usuario (no coincidencia)............198
9.9.5.4. Etiqueta para generar código de combos relacionadas entre si....................................198
9.9.5.5. Etiqueta para generar código para incluir los js utilizados en DWR ...........................200
10. Sistema de Inicialización y Arranque .............................................................................................201
10.1. Declaración de objetos inicializables.......................................................................................202
10.1.1. Variables ${…} en el fichero de inicialización ................................................................205
10.2. Desarrollo de objetos inicializables .........................................................................................206
10.3. Arranque de aplicaciones Web ................................................................................................207
10.4. Arranque manual......................................................................................................................207
11. Sistema de configuración de aplicaciones ......................................................................................208
11.1. Implementación de los objetos configurables ..........................................................................210
11.1.1. Implementando el interface Configurable.........................................................................210
11.1.1.1. Conjunto de Parámetros de Configuración (ConfigurationParameters) ....................210
11.1.1.2. Eventos de Configuración (ConfigurationEvent) ......................................................211
11.1.2. Registro de un objeto en el FrameworkConfigurator........................................................212
11.1.3. Ejemplo de clase que implementa la interfaz Configurable .............................................213
11.2. Plugins de configuración..........................................................................................................214
11.2.1. Añadir un plugin de configuración ...................................................................................214
11.2.1.1. Declaración de plugins en el fichero de inicialización ..............................................215
11.2.1.2. Plugins en openFWPA ...............................................................................................217
11.2.1.2.1. Plugins basados en Properties .............................................................................218
11.2.1.2.2. Plugins basados en XML ....................................................................................219
12. Filtros Web......................................................................................................................................225
12.1. Filtros de openFWPA. PrincastFilter .......................................................................................225
12.1.1. Implementación de un nuevo filtro ...................................................................................226
12.1.2. Gestión de los filtros de forma dinámica ..........................................................................229
12.1.3. Filtros activables por reglas ..............................................................................................229
12.2. Configuración del filtro SecurityFilter.....................................................................................230
12.3. Filtro de navegación.................................................................................................................230
12.4. Filtros de Activación................................................................................................................231
12.4.1. Filtro de Temporalidad......................................................................................................232
13. Excepciones ....................................................................................................................................233
13.1. Loggeo de las Excepciones en los DAO..................................................................................234
13.2. Excepciones durante el proceso de autenticación ....................................................................235
14. Informes ..........................................................................................................................................238
14.1. Creación de diseños XML........................................................................................................239
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
6 de
296
14.2. La herramienta iReports...........................................................................................................240
14.2.1. Visión general de la Interfaz .............................................................................................241
14.2.2. Compilar y establecer programas externos .......................................................................241
14.2.3. Nuevo informe con iReports .............................................................................................244
14.2.4. Parametros en iReport.......................................................................................................246
14.2.5. Fields.................................................................................................................................247
14.2.6. Variables ...........................................................................................................................247
14.3. Clases del OpenFWPA para la renderización de informes ......................................................248
14.3.1. Informes simples ...............................................................................................................248
14.3.2. Multi Reports ....................................................................................................................250
14.3.2.1. Forma de actuar:.........................................................................................................250
14.3.3. Las fuentes de datos de los informes. ...............................................................................250
14.3.4. Utilizando JasperReports en Linux / Unix sin X11. .........................................................250
14.3.5. Clase para la generación de tablas en PDF. ......................................................................250
14.4. Ejemplo de creación de infome con openFWPA .....................................................................251
14.4.1. Diseñar con iReports y obtener XML ...............................................................................251
14.4.2. Guardar el XML................................................................................................................254
14.4.3. Compilación ......................................................................................................................255
14.4.4. Crear clase Action que extienda PrincastPDFReportAction (abstracta)...........................256
14.4.5. Resultado final ..................................................................................................................259
15. Seguridad en aplicaciones con openFWPA ....................................................................................261
15.1. Seguridad .................................................................................................................................261
15.1.1. Autentificación básica.......................................................................................................262
15.1.2. Autentificación basada en formulario ...............................................................................262
15.1.3. Autentificación basada en el Filtro de Seguridad de openFWPA.....................................262
15.1.3.1. Integración con seguridad Web J2EE ........................................................................264
15.1.3.2. Configuración.............................................................................................................265
15.1.3.2.1. Parámetros básicos..............................................................................................265
15.1.3.2.2. Configuración JAAS ...........................................................................................268
15.1.3.2.3. Reglas de Seguridad............................................................................................272
15.1.3.3. Paso de Credenciales..................................................................................................277
15.1.3.4. Diseño de páginas de login ........................................................................................280
15.1.3.5. Excepciones durante el proceso de autenticación ......................................................284
15.1.3.6. Niveles de Seguridad .................................................................................................284
16. Pruebas de rendimiento...................................................................................................................284
16.1. Tipos de pruebas ......................................................................................................................286
16.1.1. Pruebas de carga................................................................................................................286
16.1.2. Prueba de estrés.................................................................................................................286
16.1.3. Prueba de estabilidad (soak testing)..................................................................................286
16.1.4. Pruebas de picos (spike testing) ........................................................................................286
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
7 de
296
16.2. Herramientas ............................................................................................................................286
16.3. Pruebas de rendimiento en openFWPA ...................................................................................287
17. Anexo: Consola de gestión de Tomcat 7 ........................................................................................288
17.1. Mensajes...................................................................................................................................290
17.2. Gestor .......................................................................................................................................290
17.3. Aplicaciones.............................................................................................................................291
17.4. Desplegar .................................................................................................................................293
17.4.1. Despliegue utilizando un directorio o un fichero WAR del propio servidor Tomcat.......293
17.4.1.1. Despliegue mediante el directorio o la URL del fichero WAR .................................293
17.4.1.2. Despliegue mediante el directorio o la URL en el directorio base de Tomcat ..........294
17.4.1.3. Despliegue mediante URL de archivo de configuración XML .................................295
17.4.2. Desplegar a través de un archive WAR externo ...............................................................295
17.5. Diagnósticos.............................................................................................................................295
17.6. Información del servidor..........................................................................................................296
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
8 de
296
1. Control del documento
1.1. Información general
Título
Manual de Instalación en Windows
Creado por:
Jorge Méndez Rodríguez
A revisar por:
Consultores Senior: Juan José Parada Vales e Ignacio Álvarez Valdeón
A aprobar por:
Jefe de Proyecto: Joaquín Fernández Juárez
1.2. Histórico de revisiones
Versión
Fecha
Autor
1.0
30/12/2011
Jorge Méndez Rodríguez
Observaciones
1.3. Estado del documento
Versión
Estado
Fecha
1.0
Definitivo
30/12/2011
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
9 de
296
2. Introducción
El objetivo de este documento es detallar los diferentes componentes existentes en openFWPA y la
configuración de los mismos a la hora de realizar una aplicación J2EE utilizando el Framework.
En los diferentes apartados se muestran ejemplos, de utilización y configuración de los diferentes
componentes, extraídos de la aplicación de ejemplo (sampleapp) que se distribuye con el
Framework.
1 Aplicación de ejemplo - sampleapp
3. Desarrollo de aplicaciones
Antes de comenzar el desarrollo de una aplicación Web con openFWPA, es importante tener en cuenta
las directrices y recomendaciones que se indican en este apartado.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
10 de
296
3.1. Estructura de directorios
Las aplicaciones definirán una estructura de directorios siguiendo la plantilla:
•
•
build, target: Contendrá los .class generados para el proyecto.
src: Este directorio contendrá varios subdirectorios:
o db: Contendrá los scripts de creación de la base de datos o la propia base de datos. En
caso de darse soporte a más de una base de datos o más de una versión, ha de crearse un
directorio para cada una de las BD.
o config: Contendrá los ficheros necesarios para la creación del fichero EAR necesario
para desplegar la aplicación en el contenedor J2EE (como por ejemplo application.
xml), así como los ficheros con la información necesaria para la configuración de
recursos que necesitará la aplicación (por ejemplo DataSources. En este caso podría
incluirse un fichero data-sources.xml con la información a añadir al fichero datasources.xml del contenedor J2EE para la definición de los mismos).
o main:
java: Contendrá los ficheros de código fuente Java y de recursos de la
aplicación, y el fichero build.xml con las taras de Ant.
jasperreports: Contendrá los fuentes de los informes generados con el Ireports.
resources: Contendrá los ficheros de properties con los parámetros de
configuración de la aplicación.
• beans: Contendrá los xml donde están registrados las beans de Spring.
• resources: Contendrá el fichero de properties con los mensajes
internacionalizados.
• sqlMaps: Contendrá los xml asociados a los sql-maps de Ibatis.
Webapp:
• pages: Contendrá el resto de ficheros de la aplicación: páginas HTML,
JSP, imágenes, hojas de estilo CSS, etc.
• WEB-INF: Contendrá los ficheros de configuración XML (web.xml,
strutsconfig.xml, validation.xml, etc.), DTDs y TLDs.
• lib: Contendrá las librerías que será necesario distribuir con la
aplicación, puesto que no estarán incluidas en el contenedor J2EE.
o test: Contendrá el conjunto de pruebas unitarias.
• dist: Se trata de un directorio temporal empleado para la generación de los jars, ears,…
necesarios para el proyecto.
3.2. Compilación y despliegue del sistema
Maven es una herramienta de control para el control de la construcción y ciclo de vida de los proyectos
de software. Será una de las piedras angulares de nuestro sistema, y lo utilizaremos entre otras cosas
para realizar el compilado, generar los jar, los war, los ear, dependencias de otros jar,…
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
11 de
296
Los ficheros de configuración de Maven están escritos en XML y tienen por nombre pom.xml. Cada
uno de ellos contiene los datos de configuración de nuestro proyecto como por ejemplo las
dependencias con otros jar.
En el directorio raíz de openFWPA existe un fichero pom.xml, que realiza la carga del resto de
subproyectos (a través de sus correspondientes pom.xml) que tenemos disponibles en este Framework.
<modules>
<module>xml-generico</module>
<module>fwpa-core</module>
<module>fwpa-security</module>
<module>fwpa-web-resources</module>
<module>sampleapp</module>
<module>blankapp</module>
<module>proxies</module>
<module>fwpa-doc</module>
</modules>
A continuación vamos a comentar las principales tareas que tendremos disponibles en Maven (como se
verá en el manual de instalación, para agilizar el proceso de desarrollo se recomienda utilizar el plugin
m2e para integrar maven con Eclipse):
•
•
•
•
•
•
•
compile. Creará los .class y los dejará en el directorio target
test. Ejecuta los test unitarios disponibles en el proyecto, y muestra su resultado.
packaged. Creará el jar, war, ear, …, del proyecto, según la configuración que tenga el fichero
pom.xml del proyecto.
install. Añadirá el .jar del proyecto al repositorio local de Maven.
deploy. Útil si tenemos un repositorio de Maven en red. Hace las mismas tareas que install, y
después añade el .jar al repositorio en red.
javadoc:javadoc. Genera la documentación del proyecto
clean. Limpia el proyecto, eliminando los .class generados previamente por ejemplo a través
del comando “compile”.
3.3. Pruebas unitarias
Es muy recomendable la implementación de pruebas unitarias, al menos para todos los componentes
críticos de la aplicación. Es también recomendable, en aplicaciones Web, implementar pruebas
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
12 de
296
unitarias para todos los objetos de acceso a datos (DAO). Para facilitar esta tarea se puede utilizar la
librería JUnit y DBUnit, suministrada en openFWPA.
4. Sistema de Logging (log4j)
Para la gestión de las sentencias de log, en openFWPA se utiliza la librería: Log4j
(http://logging.apache.org/log4j/).
Log4j tiene tres componentes principales:
•
•
•
Loggers
Appenders
Layouts.
Estos tres tipos de componentes trabajan juntos para permitir a los desarrolladores escribir mensajes de
log de acuerdo a un tipo de mensaje y prioridad, y para controlar en tiempo de ejecución la forma en
que estos mensajes se formatean y donde se escriben.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
13 de
296
2 http://logging.apache.org/
4.1. Loggers
Son entidades con nombre. Sus nombres son sensibles al contexto y siguen una regla de nombrado
jerárquica. Por ejemplo, el logger de nombre “com.foo” es padre del logger de nombre “com.foo.Bar”.
El logger root reside en la cima de la jerarquía de loggers. Siempre existe y no puede ser recuperado
por nombre. Para recuperarlo se ha de invocar a método estático Logger.getRootLogger().
Es posible asignar un nivel a un logger. Los niveles disponibles por orden de menor a mayor son:
•
DEBUG. para mostrar mensajes de depuración.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
14 de
296
INFO. para mostrar información sobre lo que está haciendo la aplicación.
WARN. para mostrar mensajes de alerta sobre eventos de los que se desea mantener constancia,
pero que no afectan al correcto funcionamiento del problema.
ERROR. para mostrar mensajes de error que afectan a la aplicación, pero que lo permiten
seguir funcionando (por ejemplo, algún error en un parámetro de configuración).
FATAL. para mostrar mensajes críticos del sistema, generalmente después del mensaje la
aplicación finalizará.
Si a un logger no se le asigna un nivel, lo hereda de su antecesor más cercano que tenga asignado uno.
Para asegurarse que todos los loggers tienen un nivel, el logger raíz siempre tiene asignado un nivel.
Las escrituras se realizan invocando a alguno de los métodos de impresión del logger: debug, info,
warn, error, fatal y log. El método de impresión define el nivel de la escritura. Una escritura se dice
que está habilitada si su nivel es mayor o igual que el nivel de su logger. De otra forma se dice que la
escritura esta deshabilitada.
El orden de los niveles es: DEBUG < INFO < WARN < ERROR < FATAL.
4.2. Appenders
Log4j permite que los mensajes se impriman en múltiples destinos, a cada uno de los cuales se le
denomina Appender. Algunos de los Appenders disponibles son:
•
•
•
•
•
•
•
•
•
•
ConsoleAppender. Escribe los mensajes de log en la consola.
FileAppender. Escribe los mensajes de log en un fichero.
RollingFileAppender. Escribe los mensajes de log a un fichero al que se le pueden definir
políticas de rotación para que no crezca indefinidamente.
DailyRollingFileAppender. Escribe los mensajes de log en un fichero a que se le puede definir
políticas de rotación basadas en la fecha.
SocketAppender. Escribe los mensajes de log hacia un servidor remoto de log.
SMTPAppender. Envía un correo electrónico con los mensajes de log, generalmente se utiliza
para los niveles ERROR y FATAL.
JDBCAppender. Escribe los mensajes de error a una base de datos.
SyslogAppender. Escribe los mensajes de error hacia el daemon syslog de los sistemas
operativos Unix.
NTEventLogAppender. Escribe los mensajes de log en los log del sistema de Windows NT.
JMSAppenders. Serializa los eventos y los transmite como mensaje JMS de tipo
ObjectMessage.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
15 de
296
Para más información sobre las opciones de configuración de los Appenders, consultar la
documentación de Log4j.
4.3. Layouts
El Layout es el responsable de formatear los mensajes de log de acuerdo a las definiciones del
desarrollador. Los tipos de Layouts disponibles son:
•
•
•
•
•
SimpleLayout. Prioridad del mensaje seguida por “-“, y después el mensaje de log.
PatternLayout. Especifica el formato de salida de acuerdo a unos patrones de conversión
similares a los de la función “printf” del lenguaje C (para más información consultar la
documentación).
HTMLLayout. Especifica que la salida será una tabla HTML.
XMLLayout. Especifica que la salida será un fichero XML que cumple con el log4j.dtd.
TTCCLayout. Consiste en la fecha, thread, categoría y NDC, cualquiera de estos cuatro campos
puede ser deshabilitado y habilitado individualmente.
4.4. Configuración
En la siguiente imagen, “Estados del Sistema de Logging” se puede ver el ciclo de vida de la
configuración del Sistema de Log de una aplicación que utiliza openFWPA.
Inicio
Fin
No Log
Arranque
Runtime
3 Estados de Sistemas de Loggins
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
16 de
296
Los estados por los que puede pasar son los que siguen:
1. No Log. En este estado no hay configuración alguna cargada. Si se lanza alguna sentencia de
log, aparecerá un WARNING en la salida estándar del servidor (openFWPA está configurado
por defecto para utilizar Tomcat). Este estado no debería producirse pero se puede dar en caso
de que se inicialicen componentes antes que el Framework (listeners, ejbs, etc.).
2. Arranque. Se carga la configuración de arranque del openFWPA. Esta configuración se
definirá en el fichero log4j.properties ubicado en el classpath de la aplicación. En este fichero
se puede definir una configuración de log, únicamente activa durante el proceso de arranque de
la aplicación.
4 Path del fichero log4j.properties en openFWPA
A continuación se muestra el contenido por defecto del fichero “log4j.properties” en
openFWPA.
log4j.rootCategory=info, Console, HTML
log4j.category.org.springframework = debug
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
17 de
296
log4j.category.es.princast.framework = debug
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} %p
%m%n
%c[%t]
-
log4j.appender.HTML=org.apache.log4j.DailyRollingFileAppender
log4j.appender.HTML.File=appblank-startup-log.html
log4j.appender.HTML.layout=es.princast.framework.core.logging.layouts.Princ
astHTMLLayout
3. Runtime. En este estado se supone activa la configuración de log de la aplicación. Esta
configuración se define en el fichero xml indicado en el parámetro de configuración
LOGGING_XMLCONF, o en el fichero de properties, cuyo path se indica en el parámetro de
configuración, LOGGING_PROPERTIES.
En openFWPA el parámetro LOGGING_XMLCONF se encuentra definido en el fichero
“global.properties” que podemos encontrar en “WEB-INF/global.properties”, tal y como se
indica en la siguiente imagen:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
18 de
296
5 Path del fichero global.properties en openFWPA
A continuación se muestra el contenido por defecto del fichero “global.properties” en openFWPA.
HIT.COUNTER=es.princast.framework.core.management.mcounters.historic.Histor
icalCounter
ACTION_MGMT=es.princast.framework.web.action.monitoring.PrincastActionMgmtI
nterfaceImpl
LOGGING_XMLCONF=WEB-INF/log4j.xml
http.PORT=8082
https.PORT=8447
https/cert.PORT=8447
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
19 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
ITEM.SEPARATOR = /
JMX.SERVER.ADAPTOR
es.princast.framework.core.management.adapters.OC4JMBeanServerAdapter
=
4.4.1. Ejemplo de configuración
El sistema de logging se configura a través de, por ejemplo, el fichero WEB-INF/log4j.xml (path que
se especifica bajo la constante de configuración: LOGGING_XMLCONF, mostrada en el apartado
anterior).
6 Path del fichero WEB-INF/log4j.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
20 de
296
Puede verse un ejemplo de utilización en la aplicación en blanco (AppBlank) y en la de ejemplo
(SampleApp).
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "dtd/log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="Carrito: %d %-5p [%t] %c{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<aprender name="PERFORMANCE"
class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="carrito-performance.html" />
<layout
class="es.princast.framework.core.logging.layouts.PrincastHTMLLayout">
</layout>
</appender>
<appender name="HTML"
class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="carrito-log.html" />
<layout
class="es.princast.framework.core.logging.layouts.PrincastHTMLLayout">
</layout>
</appender>
<appender name="AUDIT" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="carrito-audit.html" />
<layout
class="es.princast.framework.core.logging.layouts.PrincastHTMLLayout">
</layout>
</appender>
<category name="es.princast.framework">
<priority value ="DEBUG" />
<appender-ref ref="HTML" />
</category>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
21 de
296
<category name="debug">
<priority value ="DEBUG" />
<appender-ref ref="HTML" />
</category>
<category name="PISTA_AUDITORIA">
<priority value ="INFO" />
<appender-ref ref="AUDIT" />
</category>
<category name="PISTA_RENDIMIENTO">
<priority value ="INFO" />
<appender-ref ref="PERFORMANCE" />
</category>
<root>
<priority value ="INFO" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
En este fichero se definen varios Appenders (o destinos donde el logger va a escribir). La salida
estándar, un fichero HTML (que cambiará todos los días) y otro Appender de nombre Audit similar al
anterior. Para cada uno de ellos se define también el layout o plantilla que se utilizará para escribir la
salida.
También se definen categorías, donde se especifica para cada logger el nivel que tendrá y los
Appenders que utilizará.
A continuación se muestra la salida de un Appender que escribe en un fichero HTML.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
22 de
296
7 Ejemplo de salida de un Appender en formato HTML
Para más información sobre la configuración del logger consultar la documentación del mismo en la
dirección http://logging.apache.org/log4j/docs/manual.html.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
23 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
4.5. Componentes del openFWPA para Logging
4.5.1. LoggingManager
En openFWPA el controlador centralizado del sistema de Logging es la clase LogginManager,
definido como un bean de Spring en el fichero “princast-init-script.xml”, como veremos a lo largo de
este apartado.
En el núcleo (core) del openFWPA se define la clase LoggingManager, cuyo objeto es ser un
controlador centralizado para todo el Sistema de Logging. Esta clase permite:
•
•
Cargar configuraciones Log4J desde ficheros (xml o de properties).
Obtener los loggers estándar del framework: Pista de Auditoría y Pista de Rendimiento.
El LoggerManager se puede gestionar desde la consola JMX.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
24 de
296
8 Estados Path del fichero WEB_INF/princast-init-script.xml
Como ya comentamos, la clase LogginManager se define como un bean de Spring en el fichero
“WEB_INF/princast-init-script.xml”, tal y como podemos ver a continuación:
<!--Gestor de logging -->
<bean id="loggingManager"
class="es.princast.framework.core.logging.LoggingManager"
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
25 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
factory-method="getLogging" lazy-init="false" singleton="true">
</bean>
Todo los beans definidos en el fichero “princast—init-script.xml” se cargan con el arranque de
openFWPA.
4.5.2. PrincastHTMLLayout
Además de los layouts incluidos en Log4J (Ver “Layouts”), las aplicaciones también pueden utilizar
PrincastHTMLLayout. Este objeto es igual que el HTMLLayout estándar, con la diferencia de que
muestra la fecha y hora en que se escribe la sentencia de log.
4.5.3. Pistas de auditoría
Las aplicaciones han de registrar todas las operaciones de usuario que realicen en la denominada pista
de auditoria. Para cada entrada aparecerá el usuario y la dirección IP desde la que se realizó la
operación (registro NDC), más una descripción de la operación realizada.
La salida es configurable, pudiendo ser de distintos formatos y en distintos soportes. Por defecto, se
vuelca en un fichero en formato HTML. Cada día se mueve el contenido de este log a un fichero con la
extensión .YYYY-MM-DD. El siguiente ejemplo se ha sacado de la aplicación de ejemplo, y muestra
la ejecución de dos operaciones marcadas como auditables:
9 Ejemplo de operaciones auditadas
Un ejemplo de código que escribe información en la pista de auditoria sería el siguiente:
LoggingManager.getLogging().getAuditingTrack().info("[" + NDC.peek() + "]
Añadiendo producto al carrito");
Se hace uso de la clase LoggingManager de openFWPA, la cual se obtiene mediante el método
estático getLogging(). El método getAuditingTrack() del LoggingManager devolverá la pista de
auditoria, en la cual se escribirá como si se tratase de cualquier otro logger.
Es necesario incluir la información sobre el usuario y la IP desde la que está accediendo, información
disponible mediante el método peek de la clase NDC de Log4j.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
26 de
296
La pista de auditoria es un logger (Log4J) sobre el que se escribe la traza de accesos. Este logger se
configura, de igual forma que los loggers de aplicación, utilizando el fichero log4j.xml.
<appender name="AUDIT" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="example-audit.html" />
<layout
class="es.princast.framework.core.logging.layouts.PrincastHTMLLayout">
</layout>
</appender>
<category name="PISTA_AUDITORIA">
<priority value ="INFO" />
<appender-ref ref="AUDIT" />
</category>
El nombre del logger de auditoría se puede configurar en el fichero de inicialización de openFWPA:
“princast-init-script.xml”, como se indica en el ejemplo.
<bean id="loggingManager"
class="es.princast.framework.core.logging.LoggingManager"
factory-method="getLogging" lazy-init="false" singleton="true">
<property name="auditingTrack">
<value>MY_AUDIT_TRACK</value>
</property>
</bean>
El nombre por defecto del logger de auditoría es: “PISTA_AUDITORIA”.
4.5.4. Pistas de rendimiento
La Pista de Rendimiento es un logger, muy similar a la Pista de Auditoría, que permite escribir las
mediciones de rendimiento que se realicen en la aplicación. La configuración de la Pista de
Rendimiento, se realizará en el fichero log4j.xml.
<appender name="PERFORMANCE"
class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="example-audit.html" />
<layout
class="es.princast.framework.core.logging.layouts.PrincastHTMLLayout">
</layout>
</appender>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
27 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<category name="PISTA_RENDIMIENTO">
<priority value ="INFO" />
<appender-ref ref="AUDIT" />
</category>
El nombre del logger de rendimiento se puede configurar en la definición del LoggingManager
en el fichero de arranque princast-init-script.xml.
<bean id="loggingManager"
class="es.princast.framework.core.logging.LoggingManager"
factory-method="getLogging" lazy-init="false" singleton="true">
<property name="performanceTrack">
<value>MY_PERFORMANCE_TRACK</value>
</property>
</bean>
El nombre por defecto del logger de la Pista de Rendimiento es: “PISTA_RENDIMIENTO”.
Para obtener los loggers estándar del Framework:
• Pista de Auditoría getAuditingTrack()
• Pista de Rendimiento getPerformanceTrack()
5. Spring
Spring Framework es una plataforma que nos proporciona una infraestructura que actúa de soporte
para desarrollar aplicaciones Java. Spring maneja toda la infraestructura y así te puedes centrar en tu
aplicación. Diciéndolo más coloquialmente, Spring es el “pegamento” que une todos los componentes
de la aplicación, maneja su ciclo de vida y la interacción entre ellos.
Aunque es más habitual utilizar Spring en entornos Web, también se podría utilizar para cualquier otro
tipo de aplicación que tengamos que desarrollar.
Más información sobre Spring en http://www.springsource.org/.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
28 de
296
10 http://www.springsource.org/
5.1. Spring en openFWPA
Spring se encarga de gestionar las dependencias, instanciar los objectos e inyectarlos por reflexión. En
resumen, se declaran en un fichero XML los componentes de tu aplicación y sus dependencias. Spring
procesa este fichero XML, crea los componentes y sus relaciones entre ellos.
En openFWPA se hace un uso intensivo de la inversión de control para implementar la arquitectura de
referencia. En las aplicaciones realizadas con openFWPA se hace uso de Spring Framework, que
ofrece la implementación del patrón AbstractFactory basado en ficheros XML.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
29 de
296
Esto permite, eliminar los elementos de unión en las aplicaciones, como las factorías, y singletons.
Además, permite tener la arquitectura modularizada en "piezas", que por estar definidas en un fichero
XML, son intercambiables. Lo que deriva, en un sistema débilmente acoplado, más tolerable a
cambios y modificaciones.
Para manejar la Arquitectura de referencia con Spring, openFWPA se hace uso de una serie de ficheros
XML, donde se definen los beans que forman parte de la arquitectura del sistema. Estos ficheros están
ubicados en “src/java/beans” y sigue la estructura de directorios, propuesta para la arquitectura.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
30 de
296
11 Path del directorio bean en openFWPA
Los ficheros siguen la sintaxis de definición de beans de Spring, al igual que el fichero de
inicialización de openFWPA (princast-init-script.xml).
Para hacer uso de la inversión de control, es necesario seguir una serie de pasos. Como ejemplo, se va
a ver cómo se construye una clase Action dependiente de una clase Delegate desde cero. El proceso de
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
31 de
296
inyectar la dependencia se ha denominado "enlazado", tomándolo como traducción libre del término
"wiring", utilizado en el manual de referencia de Spring.
La primera tarea que hay que hacer, es implementar el Action. Como se tiene una dependencia, con un
Delegate, se introduce un campo o propiedad (privado o protegido), en la clase Action. Además, se
define un setter para ese campo, de esta forma se puede inyectar esa dependencia.
A la hora de usar el objeto Delegate se utiliza normalmente, aunque parezca que al usarlo apunta a un
valor nulo, el motor de inversión de control se encarga de inicializarlo.
public class GetListaProductoAction extends PrincastListAction {
// inyeccion de dependencia (/beans/web/action-beans.xml)
protected CarritoDelegate carritoDelegate;
public void setCarritoDelegate(CarritoDelegate carritoDelegate) {
this.carritoDelegate = carritoDelegate;
}
protected Object getContentList(ActionMapping mapping,
ActionForm form, HttpServletRequest request) {
//Llamamos al delegate para obtener la lista de productos.
return carritoDelegate.getListaProducto();
}
}
Una vez programada la clase, se debe registrar en el fichero de beans correspondiente, en este caso,
como se trata de un Action, se registra en el fichero actions-beans.xml. Para ello se le da un
identificador mediante el atributo id. Un nombre de clase con el atributo class, y mediante el atributo
singleton, se especifica si se quiere que la clase sea un singleton o no (si no se especifica ese atributo,
por defecto, será un singleton).
<bean id="viewlistaproducto"
class="es.princast.sampleapp.web.action.GetListaProductoAction"
singleton="false">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
32 de
296
Para inyectar la dependencia se realiza mediante el elemento property, donde se establece un atributo
name, que coincide con el nombre asociado al setter, que se ha definido en la clase que se implementó
anteriormente.
En el contenido del elemento property, se hace referencia mediante ref al identificador (id) de otro
bean. Este bean puede estar definido, en ese mismo fichero o en cualquiera de la estructura comentada
anteriormente. En este caso, la definición es de un Delegate, por lo que estará definido en el fichero
delegate-beans.xml.
<bean id="carritoDelegate"
class="es.princast.sampleapp.web.delegate.CarritoDelegate">
<property name="carritoManager">
<ref bean="carritoManager"/>
</property>
<property name="formasPagoManager">
<ref bean="formasPagoManager"/>
</property>
<property name="agenciasManager">
<ref bean="agenciasManager"/>
</property>
</bean>
5.2. Estableciendo el datasource
La inversión de control, comienza desde la primera dependencia que se tiene. En este caso el
datasource, para ello se define en el fichero “datasource-beans.xml”, un bean que representa un
datasource JNDI, a continuación se muestra un ejemplo de definición del mismo (aplicación de
ejemplo “sampleapp”):
<!-- Configuración del DataSource mediante fichero de properties-->
<bean id="propertyConfigurerJDBC"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigur
er">
<property name="location">
<value>classpath:jdbc.properties</value>
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
33 de
296
<!-- JNDI Datasource -->
<jee:jndi-lookup id="dataSource" jndi-name="${jndi.datasource}"/>
En el caso de la aplicación de ejemplo, se ha definido en el fichero
“src/main/resources/jdbc.properties” el valor de “jndi.datasource”, tal y como se muestra ver a
continuación.
Datasource JNDI
jndi.datasource=java:comp/env/jdbc/carritoDS
Para realizar las pruebas unitarias, es necesario disponer de un datasource para realizar los test. En la
aplicación de ejemplo, se suministra un test sobre una clase DAO, que utiliza un datasource para test,
disponible en “src/test/resources/beans/datasourceTest-beans.xml”.
12 Path del fichero datasourceTest-beans.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
34 de
296
Un ejemplo de definición de datasource de test, es el siguiente:
<!-- DataSource para Test Unitarios -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<!-- Se necesita el transactionManager para el test -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
En el caso de la aplicación de ejemplo, se han definido en el fichero “src/test/resources/jdbctest.properties” el valor de “jdbc.driverClassName”, “jdbc.url”, “jdbc.username”, “jdbc.password”,
tal y como se muestra ver a continuación.
jdbc.driverClassName=org.gjt.mm.mysql.Driver
jdbc.url=jdbc:mysql://localhost/carrito
jdbc.username=xxxx
jdbc.password=xxxx
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
35 de
296
13 Path del fichero jdbc-test.properties
5.3. Enlazando con los DAOs
Una vez definido el datasource, se definen los DAOs, para ello se utiliza el fichero “dao-beans.xml”.
A continuación se muestra un ejemplo de definición:
<!-- iBatis DAOs
-->
<bean id="carritoDAO"
class="es.princast.sampleapp.business.dao.IBATISCarritoDAO">
<property name="sqlMapClient"><ref bean="sqlMapClient"/></property>
<property name="displayTagSize">
<ref bean="displayTagPageSize"/>
</property>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
36 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
</bean>
<bean id="formaPagoDAO"
class="es.princast.sampleapp.business.dao.IBATISFormaPagoDAO">
<property name="sqlMapClient">
<ref bean="sqlMapClient"/>
</property>
</bean>
<!-- JDBC DAOs -->
<bean id="carritoDAO"
class="es.princast.sampleapp.business.dao.MySQLCarritoDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="formaPagoDAO"
class="es.princast.sampleapp.business.dao.MySQLFormaPagoDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
5.4. Enlazando con los Manager
Para registrar los Managers como beans de Spring y enlazarlos los DAOs, se utiliza en el fichero
“manager-beans.xml”.
Hay que tener en cuenta, si el manager que se está definiendo, está sujeto a transacciones. A
continuación, se muestra la declaración de un Manager que no está sujeto a transacciones y que no
tiene ninguna dependencia con DAOs:
<!-- Este no esta sujeto a transacciones luego declaracion normal -->
<bean id="agenciasManager"
class="es.princast.sampleapp.business.manager.AgenciasManager">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
37 de
296
</bean>
<bean id="logoutConfigurable"
class="es.princast.sampleapp.business.manager.LogoutConfigurable">
</bean>
<bean id="displayTagPageSize"
class="es.princast.sampleapp.business.manager.DisplayTagSizeConfigurable">
</bean>
En el caso de estar sujeto a transacciones, la definición del bean es un poco más complicada, ya debe
heredar de una plantilla para transacciones. Esto se realiza mediante el atributo parent, donde se le
especifica el nombre de la plantilla, que estará definida en el fichero transaction-beans.xml.
La definición propiamente dicha de la clase Manager, se realiza dentro de la propiedad target, y se le
inyecta las dependencias normalmente. A continuación, se muestra la definición de un Manager sujeto
a manejo de transacciones.
<bean id="carritoManager" parent="transactionTemplate">
<property name="target">
<bean
class="es.princast.sampleapp.business.manager.CarritoManager">
<property name="carritoDAO">
<ref bean="carritoDAO"/>
</property>
</bean>
</property>
</bean>
<bean id="formasPagoManager"
class="es.princast.sampleapp.business.manager.FormasPagoManager">
<property name="formaPagoDAO">
<ref bean="formaPagoDAO"/>
</property>
</bean>
La dependencia se establece por medio de la definición de un setter, para cada campo dependiente en
la clase que representa al Manager.
public class CarritoManager {
...
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
38 de
296
protected CarritoDAO carritoDAO;
public void setCarritoDAO(CarritoDAO carritoDAO) {
this.carritoDAO = carritoDAO;
}
...
}
5.4.1. Gestión de transacciones
Desde el fichero “transaction-bean.xml” se controla la gestión de transacciones. Esta gestión se
realiza de forma declarativa, por lo que los Managers que hereden de estas plantillas de transacciones,
no tendrán que implementar código para la gestión de transacciones, ni conexiones.
Antes de la definición de la plantilla se establece un transactionManager sobre el datasource a utilizar.
Un ejemplo de definición es el siguiente:
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
Una vez declarado el “transactionManager”, se define una plantilla para el manejo de transacciones.
De esta plantilla se debe de heredar, en la definición de beans, los Manager que estén sujetos a
transacciones.
Se podrían definir varias plantillas, en función de las necesidades. Un ejemplo de plantilla para la
gestión de transacciones es el siguiente:
<bean id="transactionTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryB
ean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
39 de
296
<props>
<!--Los métodos que comiencen por get en los Manager serán
readOnly-->
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
Como se observa en el ejemplo de plantilla, se dispone de una property de nombre
transactionAttributes, que define las propiedades de la transacción. Las transacciones se definen a
nivel de método de un Manager, por lo que, cada ejecución de un método de un Manager establecería
una transacción.
Además se pueden establecer patrones, de forma que definiendo el patrón 'get*', las propiedades
establecidas para ese patrón, afectará a todos los métodos del Manager que comiencen por 'get'.
De esta manera definiendo las propiedades, 'PROPAGATION_REQUIRED,readOnly' se tendrá una
transacción por método, y además estará optimizada para sólo lectura.
El comportamiento por defecto, para la política de rollback, define que si se produce una excepción de
tipo Runtime durante la ejecución del método, se hará un rollback.
Algunas de las propiedades que se pueden establecer son:
•
•
•
•
PROPAGATION_LEVEL: Nivel de propagación. Por defecto se establece el nivel de
propagación a PROPAGATION_REQUIRED, esto significa que creará una nueva transacción,
sólo si se necesita.
ISOLATION_LEVEL: Nivel de aislamiento. Por defecto trendrá el valor
ISOLATION_DEFAULT.
readOnly: Optimización de sólo lectura. Se optimiza la transacción para las operaciones de sólo
lectura.
Lista de Excepciones: Establece la política de rollback o commit, al margen del
comportamiento por defecto. Por ejemplo, si se le añade la cadena '-MiExcepcion', se hará
rollback en caso de que dispare la excepción de nombre 'MiExcepcion', aunque el tipo de
excepción no sea Runtime. Si se añade la cadena '+OtraExcepcion', se hará commit aunque la
excepción sea Runtime.
Para más información sobre las propiedades disponibles consultar el manual de referencia de Spring.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
40 de
296
5.5. Enlazando con los Delegate
Para enlazar las definiciones de Managers, con las clases Delegate, se hace de manera similar a los
enlazados visto anteriormente, en este caso se realiza en el fichero delagate-beans.xml.
Un ejemplo de enlazado es el siguiente:
<bean id="carritoDelegate"
class="es.princast.sampleapp.web.delegate.CarritoDelegate">
<property name="carritoManager">
<ref bean="carritoManager"/>
</property>
<property name="formasPagoManager">
<ref bean="cachedFormasPagoManager"/>
</property>
<property name="agenciasManager">
<ref bean="agenciasManager"/>
</property>
</bean>
Se recuerda que la clase CarritoDelegate debe disponer de un setter para cada dependencia.
5.6. Enlazando con los Actions
Una vez enlazados los Delegates, se deben enlazar las Actions. Para ello se definen los beans en el
fichero action-beans.xml. Un ejemplo, de definición de beans para las Actions es el siguiente:
<bean id="carrito" class="es.princast.sampleapp.web.action.CarritoActions"
scope="prototype">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<!-- propiedad singleton="false" -->
<bean id="viewlistaproductopdf" singleton="false"
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
41 de
296
class="es.princast.sampleapp.web.action.report.ProductosPDFTableReportActio
n">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
En el caso de las Actions, si queremos que se cree una instancia por cada petición de struts,
estableceremos el atributo singleton="false”.
Una vez definidos los beans para las Actions deben ser referenciados desde el fichero “WEBINF/struts-config.xml”, la referencia se hará mediante el atributo type. Buscará primero por id de bean
definido en el fichero action-beans.xml, y si no encuentra ningún bean definido, tomará el nombre
como el de una clase.
Un ejemplo de Actions en struts-config.xml:
<!—- Se referencia al id de un bean definido en el fichero action-beans.xml
-->
<action path="/viewdetalleproducto" name="detalleProductoForm"
input="/index.jsp" type="viewdetalleproducto" scope="request"
validate="false">
<forward name="success" path="carrito.detalleprod" />
</action>
<!—- se tiene en cuenta el nombre de la clase -->
<action path="/viewcarrito" validate="false"
parameter="carrito.viewcarrito"
type="es.princast.framework.web.action.PrincastForwardAction"
scope="request">
</action>
Se observa que el atributo type tiene el valor type="viewdetalleproducto" que coincide con el id del
bean definido en action-beans.xml.
6. Capa de acceso a datos
Un componente básico del modelo es la capa de acceso a datos (generalmente, a bases de datos
relacionales). No está permitido el acceso a datos desde cualquier componente de la aplicación que no
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
42 de
296
pertenezca a esta capa (páginas JSP, Actions, etc.). La herramienta clave para la implementación de
esta capa es el patrón de diseño DAO (Data Access Object).
El principal objetivo es:
•
Abstraer al resto de la aplicación de los detalles de implementación del acceso a sistemas de
persistencia.
•
Homogeneizar el acceso a datos desde las capas superiores.
14 Ejemplo de capa de acceso a datos
6.1. Alternativas para implementar la capa de acceso a datos
Para realizar el acceso a datos se utilizará el patrón DAO (Data Access Object), openFWPA contempla
dos alternativas:
•
Clases proporcionadas por el FW-PA
o Interface PrincastDAO
o PrincastDAOHelper
o PropertiesTableDAO
o LookupPropertyBean
•
iBATIS (http://www.mybatis.org/)
OpenFWPA está configurado por defecto para trabajar con iBATIS, y por tanto en este manual de
configuración nos centraremos en esta alternativa.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
43 de
296
15 http://www.mybatis.org/
6.2. ¿Qué es iBATIS?
iBATIS es un framework (método de trabajo) de código abierto basado en capas desarrollado por
Apache Software Foundation, que se ocupa de la capa de Persistencia (se sitúa entre la lógica de
Negocio y la capa de la Base de Datos).
iBATIS asocia objetos de modelo (JavaBeans) con sentencias SQL o procedimientos almacenados
mediante ficheros descriptores XML, simplificando la utilización de bases de datos.
El 21 de Mayo de 2010 el equipo de desarrollo decidió continuar el proyecto en Google Code bajo la
nueva denominación MyBatis.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
44 de
296
6.2.1. iBATIS en openFWPA
Para comenzar se comentarán brevemente los componentes que se deben tener en cuenta al desarrollar
una aplicación J2EE con openFWPA utilizando iBATIS.
•
Value Object (nombreVO). Los objetos de datos han de implementar PrincastValueObject.
Como “BasePrincastVO” implementa esta interface, los nuevos objetos de datos deben
extender de la clase “BasePrincastVO” incluida en el core de openFWPA.
16 Diagrama de Value Objects
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
45 de
296
A continuación se muestra un ejemplo de un VO para la clase “FormaPagoVO”.
public class FormaPagoVO extends BasePrincastVO {
....
private int id;
....
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
....
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
46 de
296
17 Path de la clase FormaPagoVO
•
DAO (Data Access Object). Para realizar el acceso a datos se utilizará el patrón DAO (Data
Access Object). En primer lugar se debe definir una interface, con todos los métodos que se
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
47 de
296
deben implementar. Después se debe crear la implementación, que debe extender de
“PrincastSqlClientDAOSupport” para acceder a Base de Datos.
18 Path de la capa de acceso a datos en openFWPA
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
48 de
296
A continuación se muestra un ejemplo de una interface.
public interface FormaPagoDAO {
List getFormaPago();
}
Y de una implementación de dicha interface
public class IBATISFormaPagoDAO
extends PrincastSqlClientDAOSupport implements FormaPagoDAO {
// constantes para los identificadores de las consultas
private static String LISTA_FORMAPAGO = "listaFormaPago";
public List getFormaPago() {
return getPrincastSqlMapClientTemplate().queryForList(LISTA_FORMAPAGO,
null);
}
}
A continuación se mapean en el fichero “sqlMapConfig.xml” los campos de la tabla correspondiente
de la base de datos con los atributos equivalentes del VO, y se especifican las consultas a realizar en la
capa de acceso a datos. En cada una de ellas se indica que parámetros recibe y en que Mapping se va a
obtener el resultado (se le puede indicar que el resultado me lo devuelva en una tabla Hash).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
49 de
296
19 Path del fichero sqlMapConfig.xml
Es recomendable incluir en el “sqlMapConfig.xml” ficheros auxiliares para mantener organizada la
información, tal y como podemos ver en el siguiente ejemplo.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
50 de
296
Contenido del fichero “sqlMapConfig.xml”.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings />
<sqlMap resource="sqlMaps/FormaPagoDAO.xml" />
</sqlMapConfig>
Como podemos ver en el código anterior, se utiliza un fichero auxiliar para el mapeo de los atributos y
la especificación de las consultas “FormaPagoDAO”. A continuación se muestra el contenido del
fichero “FormaPagoDAO.xml”.
<sqlMap namespace="FormaPagoDAO">
<resultMap class="es.princast.sampleapp.business.vo.FormaPagoVO"
id="formaPagoMap">
<result property="id" column="id"/>
<result property="description" column="descripcion"/>
</resultMap>
<select id="listaFormaPago" resultMap="formaPagoMap">
SELECT * FROM formapago
</select>
</sqlMap>
El siguiente paso será las clases de los daos como beans de Spring en el fichero “dao-beans.xml”, tal y
como se vio en el apartado “3.2.3. Enlazando con los DAOs”.
Por ser un DAO que utiliza Ibatis a la hora de registrarlo como un bean de Spring hay que pasarle la
propiedad sqlMapClient que es una referencia al bean.
<bean id="formaPagoDAO"
class="es.princast.sampleapp.business.dao.IBATISFormaPagoDAO">
<property name="sqlMapClient">
<ref bean="sqlMapClient"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
51 de
296
</property>
</bean>
Que se definió previamente en el mismo fichero, tal y como se muestra a continuación:
<!-- SqlMap configuración para iBATIS Database Layer -->
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="configLocation">
<value>classpath:/sqlMaps/sqlMapConfig.xml</value>
</property>
</bean>
6.3. Pool de conexiones
Cuando trabajamos con java contra una base de datos, es habitual que se realice una conexión a base
de datos por cada operación que se quiera realizar.
Esto podría ser adecuado para una aplicación muy básica, pero en proyectos complejos es mejor
utilizar otras formas para evitar por ejemplo los siguientes problemas: :
Abrir una conexión, realizar cualquier operación con la base de datos y cerrar la conexión puede ser
lento. La apertura de las conexiones puede tardar más que la operación que queremos realizar. Es
mejor, por tanto, abrir una o más conexiones y mantenerlas abiertas.
Mantener una única conexión abierta compartida puede traernos problemas de concurrencia de hilos.
Si varios hilos intentan hacer una operación con la conexión sin sincronizarse entre ellos, puede haber
conflictos.
El esquema conexión-operación-desconexión visto anteriormente es válido, pero podría ser más
eficiente si no fuera necesario abrir las conexiones constantemente.
En vez de esta orientación hay otra alternativa: crear un pool de conexiones, es decir, mantener un
conjunto limitado de conexiones que se reutilizan constantemente para dar servicio a las diferentes
operaciones. Para realizar una operación contra la base de datos se solicita una conexión al conjunto de
conexiones disponibles, y cuando no la va a usar la devuelve al pool. De esta forma nos ahorramos el
consumo de tiempo de conexión y desconexión.
En openFWPA, el pool de conexiones está definido en el fichero “datasource-beans.xml”.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
52 de
296
20 Path del fichero datasource-beans.xml
A continuación podemos ver el contenido de este fichero.
<!-- Configuración del DataSource mediante fichero de properties-->
<bean id="propertyConfigurerJDBC"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigur
er">
<property name="location">
<value>classpath:jdbc.properties</value>
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
53 de
296
<!-- JNDI Datasource –>
<jee:jndi-lookup id="dataSource" jndi-name="${jndi.datasource}"/>
El primer bean representa la conexión por JDBC y el segundo representa la conexión por JNDI (Java
Naming and Directory Interface).
Puedes obtener más información sobre JNDI en la siguiente página de Oracle:
http://www.oracle.com/technetwork/java/jndi/index.html.
La variable ${jndi.datasource} está definida en el fichero “jdbc.properties”, y su contenido es:
#Datasource JNDI
jndi.datasource=java:comp/env/jdbc/carritoDS
21 Path del fichero jdbc.properties
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
54 de
296
Como hemos visto a través de los ejemplos anteriores, por defecto openFWPA está configurado para
que la conexión se realice utilizando JNDI.
6.3.1. Datasource en Apache Tomcat
Como hemos visto en el documento de instalación del entorno, openFWPA está configurado por
defecto para trabajar con Apache Tomcat. Por ese motivo, tenemos que definir en el fichero
“context.xml” ubicado en el directorio META-INF los datos de acceso a la base de datos.
22 Path del fichero context.xml
A continuación se muestra el contenido del fichero “context.xml”.
Context docBase="carrito" path="/carrito" reloadable="true"
source="org.eclipse.jst.j2ee.server:carrito">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
55 de
296
<!-<ResourceLink name="jdbc/carritoDS"
global="jdbc/carritoDS"
type="javax.sql.DataSource"/>
-->
<!-- mysql
-->
<Resource name="jdbc/carritoDS" auth="Container"
type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/carrito?autoReconnect=true"/>
<!-- postgresql
<Resource name="jdbc/carritoDS" auth="Container"
type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
username="carrito" password="carrito"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/carrito"/>
-->
</Context>
Como podemos comprobar, a pesar de que openFWPA trabaja por defecto con MySQL, en este
fichero se incluyen entre comentarios la configuración necesaria para trabajar con PostgreSQL
6.4. Pruebas unitarias
Es muy recomendable la implementación de pruebas unitarias, al menos para todos los componentes
críticos de la aplicación. Es también recomendable, en aplicaciones Web, implementar pruebas
unitarias para todos los objetos de acceso a datos (DAO).
Toda aplicación J2EE desarrollada utilizando openFWPA debería tener presente, en todo momento, la
realización de pruebas unitarias de todos sus componentes relevantes. De esta forma se tiene una
batería de pruebas que pueden ejecutarse en cualquier momento como pruebas de regresión. Debiera
disponerse de un proceso en el servidor que se encargue de lanzar tales pruebas un número
determinado de veces y genere un informe con los resultados de la ejecución de las pruebas.
Todo esto se ha tenido en cuenta a la hora de desarrollar opnFWPA y se proporciona una
infraestructura basada en JUnit (http://www.junit.org/) que se puede utilizar a tal efecto.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
56 de
296
23 http://junit.org/
6.4.1. Convenciones a seguir
A la hora de implementar las diferentes pruebas unitarias se recomienda que las clases sigan el
convenio de nombrado masivamente seguido que establece que éstas deben llamarse
<nombre_de_la_clase>Test.java.
En cuanto a la signatura de los métodos que implementen los diferentes casos de pruebas, se suele
emplear:
public void test<nombre_caso_prueba> () {};
JUnit reconoce como casos de prueba todos aquellos métodos que sigan esta convención de nombrado.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
57 de
296
6.4.2. Pruebas unitarias de objetos que acceden a bases de datos
Para una aplicación Web es muy recomendable realizar pruebas unitarias para todos los objetos de
acceso a bases de datos (DAOs), de esta forma se garantiza que el back-end de la aplicación está
correctamente implementado y se agiliza en muy buena medida el desarrollo de la capa Web.
Las pruebas unitarias de acceso a bases de datos, se realizan siempre fuera del contendor. Esto es
lógico ya que en un buen diseño nunca un componente de acceso a base de datos tendrá dependencias
respecto al contendor donde se ejecuta.
Para realizar pruebas de clases que deben acceder a una base de datos, se utilizará la clase de test
PrincastDatabaseTestCase o la clase AbstractTransactionalDataSourceSpringContextTests (la clase
anterior hereda de ésta).
Las pruebas unitarias de objetos que acceden a bases de datos, están basadas en el Framework Spring.
Spring puede simular el acceso a la base de datos utilizando transacciones serializables que son
canceladas una vez termina la prueba. Por este motivo, es importante que las tablas involucradas en las
pruebas que se implementan, dispongan de soporte para transacciones (por ejemplo, las tablas de tipo
MyISAM, por defecto en MySQL, no soportan transacciones, sin embargo las tablas de Oracle o las
tablas InnoDB de MySQL sí que las soportan).
El hecho de que este tipo de pruebas unitarias esté basado en Spring supone que:
•
•
•
Es necesario declarar los DataSources que se van a utilizar en un fichero de definición de
beans de Spring.
No es necesario controlar las transacciones que se realicen durante el test.
La clase de prueba es, a su vez, un bean de Spring. La clase de pruebas realizará autowiring por
tipo para todas sus propiedades setter. Es decir, para todos los setters que tenga la clase de
pruebas busca, en los ficheros de definición de beans, un bean que encaje en el tipo de la
propiedad y se lo asigna.
Atención
Es muy importante tener en cuenta que el autowiring de beans con la clase de test se realiza por
tipo. Si más de un bean encaja en el tipo de la propiedad puede producirse un error. El
DataSource a utilizar también se asigna a la clase de test utilizando autowiring, por lo tanto,
únicamente se puede declarar un DataSource en los ficheros de definición de beans.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
58 de
296
Para implementar tests extendiendo de la clase PrincastDatabaseTestCase o de la clase
AbstractTransactionalDataSourceSpringContextTests, se seguirán todas las normas y convenciones
definidas para implementar casos de prueba estándar (ver apartado “3.6.1. Convenciones a seguir”).
Si extendemos de “PrincastDatabaseTestCase” se debe implementar el método:
•
getDataSourceFile(), que devuelve el path donde se encuentra el fichero de definción de beans
en el que se declara el DataSource a utilizar. Por ejemplo:
protected String getDataSourceFile() {
return
"classpath*:/es/princast/framework/facilities/dao/datasourcebeans.xml";
}
La clase base “PrincastDatabaseTestCase” proporciona las siguientes utilidades:
•
logger. Como todos los tests, se dispone de un atributo, de nombre logger, que permite acceder
al log de la clase de prueba.
•
getDataSource(). Este método permite obtener la fuente de datos (DataSource) que conecta con
la base de datos. Este origen de datos se puede asignar, posteriormente, a los objetos que se
vayan a probar.
•
jdbcTemplate. La clase base para pruebas en base de datos dispone de un atributo, de la clase
org.springframework.jdbc.core.JdbcTemplate, que permite ejecutar, directamente consultas
contra la base de datos. Para más información sobre cómo usar esta clase, consúltese el manual
de referencia del Framework Spring.
•
onSetUpInTransaction(). Extendiendo este método, se pueden realizar todo tipo de
actualizaciones (inserciones, borrados, etc.) que sean necesarios para la posterior ejecución de
la prueba. Todas las actualizaciones que se realicen estarán disponibles, únicamente durante la
ejecución del test. No quedará rastro de estas operaciones en la base de datos.
Este método sustituye al fichero DataSet XML de dbUnit. Si se utiliza este método, y se quiere
utilizar también dbUnit, se debe hacer una llamada a super.onSetUpInTransaction().
•
onSetUpBeforeTransaction(). Este método es análogo al anterior con al diferencia de que las
actualizaciones realizadas en este método sí que son persistentes en la base de datos.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
59 de
296
Si por el contrario extendemos de “AbstractTransactionalDataSourceSpringContextTests” se debe
implementar el método:
•
getConfigLocations(), que devuelve un array con el path donde se encuentra el fichero de
definción de beans en el que se declara el DataSource a utilizar, y el path de los beans que se
han definido en la aplicación. Por ejemplo:
public String[] getConfigLocations() {
return new String[] { "classpath*:/beans/business/manager-beans.xml",
"classpath*:/beans/business/transaction-beans.xml",
"classpath*:/beans/business/dao-beans.xml",
"classpath*:/beans/business/search-beans.xml",
"classpath*:/beans/princast-init-scriptTest.xml",
"classpath*:/beans/datasourceTest-beans.xml" };
}
La clase base “AbstractTransactionalDataSourceSpringContextTests” proporciona las siguientes
utilidades:
•
logger. Como todos los tests, se dispone de un atributo, de nombre logger, que permite acceder
al log de la clase de prueba.
•
jdbcTemplate. La clase base para pruebas en base de datos dispone de un atributo, de la clase
org.springframework.jdbc.core.JdbcTemplate, que permite ejecutar, directamente consultas
contra la base de datos. Para más información sobre cómo usar esta clase, consúltese el manual
de referencia del Framework Spring.
•
jdbcTemplate.getDataSource(). En este caso tendremos que utilizar el método a través del
atributo comentado justo en el punto anterior. Al igual que sucede con la clase
“PrincastDatabaseTestCase”, este método permite obtener la fuente de datos (DataSource) que
conecta con la base de datos. Este origen de datos se puede asignar, posteriormente, a los
objetos que se vayan a probar.
•
onSetUpInTransaction(). Extendiendo este método, se pueden realizar todo tipo de
actualizaciones (inserciones, borrados, etc.) que sean necesarios para la posterior ejecución de
la prueba. Todas las actualizaciones que se realicen estarán disponibles, únicamente durante la
ejecución del test. No quedará rastro de estas operaciones en la base de datos.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
Estado
Definitivo
Documento
Manual de Configuración
Página
60 de
296
onSetUpBeforeTransaction(). Este método es análogo al anterior con lA diferencia de que las
actualizaciones realizadas en este método sí que son persistentes en la base de datos.
6.4.2.1. Pruebas unitarias de DAOs
Por habitual, un caso especial de las pruebas unitarias que acceden a bases de datos, es el de las
pruebas unitarias de DAOs.
Los objetos DAO a probar se deben declarar en un fichero de definición de beans de Spring. La
ubicación de este ficho se proporcionará extendiendo el método “getDaoFile()” en el caso de la
extender de la clase “PrincastDatabaseTestCase”, y el método “getConfigLocations()” si extendemos
de la clase “AbstractTransactionalDataSourceSpringContextTests”, como ya comentamos
anteriormente.
Para obtener instancias de los DAOs a probar, la clase de pruebas debe definir un método setter para
cada uno de ellos. La clase base utilizada se encargará de asignar a estas propiedades los DAOs,
declarados en el fichero de definción de beans, cuyo tipo sea compatible (autowiring por tipo).
Es importante tener en consideración que, si más de un bean es compatible con el tipo de una
propiedad del test, se puede producir un error.
A continuación vamos a ver una clase de prueba de ejemplo para un DAO, utilizando la clase base
“AbstractTransactionalDataSourceSpringContextTests”.
public class CarritoDAOTest
extends AbstractTransactionalDataSourceSpringContextTests {
// DAO a probar
protected CarritoDAO carritoDAO;
// la dependencia de inyecta automáticamente por el tipo de clase
public void setCarritoDAO(CarritoDAO carritoDAO) {
this.carritoDAO = carritoDAO;
}
public String[] getConfigLocations() {
return new String[] {
"classpath*:/beans/business/manager-beans.xml",
"classpath*:/beans/business/transaction-beans.xml",
"classpath*:/beans/business/dao-beans.xml",
"classpath*:/beans/business/search-beans.xml",
"classpath*:/beans/princast-init-scriptTest.xml",
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
61 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
"classpath*:/beans/datasourceTest-beans.xml" };
}
// tareas que se realizan antes de los test
public void onSetUpInTransaction() {
// se borra lo que hay y se insertan los datos de test
// se recuerda que la transaccion se hara rollback por lo que no
// afecta al contenido, siempre y cuando la tabla sea de tipo
InnoDB
jdbcTemplate.execute("delete from producto");
jdbcTemplate.execute("insert
into
values(1,'test1','test1','test1',1)");
jdbcTemplate.execute("insert
into
values(2,'test2','test2','test2',2)");
jdbcTemplate.execute("insert
into
values(3,'test3','test3','test3',2)");
}
producto
producto
producto
public void testGetProductos() {
jdbcTemplate.getDataSource();
logger.info("Iniciado testGetProductos");
assertNotNull(carritoDAO);
List list = carritoDAO.getListaProducto();
assertTrue(list.size() == 3);
logger.info("Lista de productos 3 ");
logger.info("Finalizado testGetProductos");
}
public void testGetDetalle() {
logger.info("Iniciado testGetDetalle");
assertNotNull(carritoDAO);
ProductoVO producto = carritoDAO.getDetalleProducto("1");
assertTrue(producto.getName().equals("test1"));
logger.info("Finalizado testGetDetalle");
}
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
62 de
296
Con solamente implementar el método setCarritoDAO(), al ejecutar el test se asignará
automáticamente cualquier bean de la clase CarritoDAO.
En el método getConfigLocations() se debe definir la ubicación del fichero de definición de beans
donde se declaran los DAOs. En este caso, nos afectan directamente “/beans/business/dao-beans.xml”
y “/beans/business/manager-beans.xml”, porque en el “dao-beans.xml” se hace referencia a un bean
definido en el “manager-beans.xml” (displayTagPageSize).
El contenido del fichero “dao-beans.xml” es el siguiente:
<!-- SqlMap configuración para iBATIS Database Layer -->
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="configLocation">
<value>classpath:/sqlMaps/sqlMapConfig.xml</value>
</property>
</bean>
<!-- iBatis DAOs -->
<bean id="carritoDAO"
class="es.princast.sampleapp.business.dao.IBATISCarritoDAO">
<property name="sqlMapClient"><ref bean="sqlMapClient"/></property>
<property name="displayTagSize">
<ref bean="displayTagPageSize"/>
</property>
</bean>
<bean id="formaPagoDAO"
class="es.princast.sampleapp.business.dao.IBATISFormaPagoDAO">
<property name="sqlMapClient"><ref bean="sqlMapClient"/></property>
</bean>
En el método getConfigLocations() también se define la ubicación del fichero de declaración de beans
donde se especifica el DataSource a utilizar. En este ejemplo, el fichero se llama
“/beans/datasourceTest-beans.xml”, y su contenido es el que sigue:
<beans>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
63 de
296
<!-- DataSource para Test -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean>
<!-- Se necesita el transactionManager para el test -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
</beans>
Todas las operaciones realizadas sobre la base de datos en este método serán únicamente visibles a lo
largo del test (si el tipo de nuestra tabla, suponiendo que trabajemos con MySQL, es innoDB).
Finalmente, se puede realizar el test normalmente utilizando los beans declarados en los ficheros
correspondientes.
Atención
El test de ejemplo que se ha comentado se puede encontrar, junto con un test para la capa
“Manager”, dentro de la aplicación de ejemplo (sampleapp) incluida en openFWPA.
6.4.2.2. Más información sobre la implementación de pruebas unitarias
Dado que los diferentes tipos de pruebas unitarias que se han presentado con anterioridad están
basados en proyectos de terceros, la mejor forma de conseguir información detallada de los mismos es
acudiendo a los sitios Web de estos.
Por ello, a continuación se presentan los enlaces a las guías de desarrollo de cada uno de los proyectos:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
64 de
296
Proyecto JUnit [ http://junit.sourceforge.net/]
Proyecto StrutsTestCase [http://jtestcase.sourceforge.net]
Proyecto DbUnit [http://dbunit.sourceforge.net/howto.html]
7. Capa de negocio
Es importante disponer de un buen diseño técnico antes de programar la lógica de negocio. En esta
área intervienen dos tipos de objetos:
•
•
Business Delegates
Business Managers
Los objetos “Delegate” se encargarán de crear y gestionar los objetos de lógica de negocio y
proporcionarán un interfaz, para la aplicación Web, de los métodos de negocio.
Los objetos "Manager", se encargarán de implementar la propia lógica de negocio.
7.1. Business Managers
En esta capa se implementa toda la lógica de negocio, dando soporte a los procesos de negocio
asociados, como por ejemplo hacer una transacción bancaria.
Si requiere acceder a datos en una base de datos o en otro sistema, se apoya en la capa de acceso a
datos comentada en el apartado anterior.
Además oculta toda la complejidad a la capa superior que se verá en el siguiente apartado.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
65 de
296
24 Path del directorio Manager
Como ya vimos en el apartado “5.4. Enlazando con los Manager”, las clases asociadas a la capa de
negocio “Manager” se registran como beans de Spring en el fichero manager-beans.xml.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
66 de
296
25 Path del fichero manager-beans.xml
7.1.1. Prueba unitaria sobre la capa Manager
En este apartado vamos a comentar ver la clase de prueba “CarritoManagerTest.java”, que utiliza la
clase base “AbstractTransactionalDataSourceSpringContextTests”, y que se incluye dentro de la
aplicación de ejemplo “sampleapp” de openFWPA.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
67 de
296
26 Path de la clase de prueba CaritoManagerTest.java
A continuación se muestra el código de la clase “CarritoManagerTest”:
public class CarritoManagerTest extends
AbstractTransactionalDataSourceSpringContextTests {
private CarritoManager carritoManager;
public CarritoManagerTest() {
setAutowireMode(AUTOWIRE_BY_NAME);
setDefaultRollback(false);
}
public void setCarritoManager(CarritoManager carritoManager) {
this.carritoManager = carritoManager;
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
68 de
296
// fichero donde esta el datasource de test
public String[] getConfigLocations() {
return new String[] {
"classpath*:/beans/business/manager-beans.xml",
"classpath*:/beans/business/transaction-beans.xml",
"classpath*:/beans/business/dao-beans.xml",
"classpath*:/beans/business/search-beans.xml",
"classpath*:/beans/princast-init-scriptTest.xml",
"classpath*:/beans/datasourceTest-beans.xml" };
}
public void testFindProductosPorNombre() {
List todos = carritoManager.getListaProducto();
List productos =
carritoManager.findProductosPorNombre("Producto");
Assert.assertTrue(productos.size() > 0);
}
}
Con solamente implementar el método setCarritoManager(), al ejecutar el test se asignará
automáticamente cualquier bean de la clase CarritoManager.
En el método getConfigLocations()se define la ubicación del fichero de declaración de beans donde se
especifica el DataSource a utilizar “datasourceTest-beans.xml”, así como la ubicación de los ficheros
de definición de beans donde se declaran los Managers.
A continuación se muestra el contenido del fichero “datasourceTest-beans.xml”:
<beans>
<!-- DataSource para Test -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
69 de
296
<value>${jdbc.driverClassName}</value>
</property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean>
<!-- Se necesita el transactionManager para el test -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
</beans>
Respecto a los ficheros que incluyen la definición de los beans donde se declaran los Managers,
aunque el método “getConfigLocations” de la clase “CarritoManagerTest” haga referencia a varios
ficheros, en este caso concreto nos afectan únicamente “manager-beans.xml” y “dao-beans.xml”, ya
que como podremos ver en el siguiente ejemplo (contenido del fichero “manager-beans.xml”), los
beans “carritoManager” y “formasPagoManager” hacen referencia a “carritoDAO” y
“formasPagoDAO” respectivamente, definidos en el fichero “dao-beans.xml”.
A continuación se muestra el contenido del fichero “manager-beans.xml” es el siguiente:
<!-Para que estén sujetos a transacciones tienen que tener
parent="transactionTemplate" y la property "target" apuntando a la
clase de esta manera obtienen y cierran la conexión automáticamente
-->
<bean id="carritoManager" parent="transactionTemplate">
<property name="target">
<bean class="es.princast.sampleapp.business.manager.CarritoManager">
<property name="carritoDAO"><ref bean="carritoDAO"/></property>
</bean>
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
70 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<bean id="formasPagoManager"
class="es.princast.sampleapp.business.manager.FormasPagoManager">
<property name="formaPagoDAO"><ref bean="formaPagoDAO"/></property>
</bean>
<!-- Este no esta sujeto a transacciones luego declaración normal -->
<bean id="agenciasManager"
class="es.princast.sampleapp.business.manager.AgenciasManager">
</bean>
<bean id="logoutConfigurable"
class="es.princast.sampleapp.business.manager.LogoutConfigurable">
</bean>
<bean id="displayTagPageSize"
class="es.princast.sampleapp.business.manager.DisplayTagSizeConfigurable">
</bean>
Por último, recordar que las clases “CarritoManager” y “FormasPagoManager” tiene definidos los
setters “setCarritoDAO” y “setFormaPagoDAO” respectivamente, que utilizará Spring para inyectar
los correspondientes beans,
A continuación se muestra parte del contenido de la clase “CarritoManager”.
public class CarritoManager {
...
protected CarritoDAO carritoDAO;
public void setCarritoDAO(CarritoDAO carritoDAO) {
this.carritoDAO = carritoDAO;
}
...
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
71 de
296
7.2. Business Delegate
Esta capa se encargarán de crear y gestionar los objetos de lógica de negocio, reducir el acoplamiento
entre los clientes de la capa de presentación y los servicios de negocio, y proporcionarán un interfaz,
para la aplicación Web, de los métodos de negocio.
Además, esta capa oculta los detalles de la implementación de todos los servicios de negocio, como
por ejemplo los detalles de una búsqueda.
27 Estructura de la capa Business Delegate
Utilizando esta estructura, se puede modificar la implementación del servicio sin que sea necesario
modificar el resto de la aplicación. Un ejemplo de implementación puede verse en la aplicación de
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
72 de
296
ejemplo (sampleapp). En ningún caso la lógica de negocio ha de tener dependencias con el protocolo
http (como por ejemplo hacer uso de la sesión), ya que sus servicios han de poder reutilizarse desde
cualquier otro entorno (como Web Services, JMS, etc.). Las únicas dependencias al protocolo concreto
de acceso han de estar en las acciones (View Adapters y Actions).
28 Path del directorio Delegate
Como se comentó brevemente en el apartado “5.4. Enlazando con los Delegate”, las clases asociadas
a la capa de negocio (Delegate) se registran como beans de Spring en el fichero delegate-beans.xml.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
73 de
296
29 Path del fichero manager-beans.xml
A continuación se mostrará el contenido del fichero “delegate-beans.xml”, donde podremos ver que el
bean “carritoDelegate” está referenciando a tres beans de la capa de Manager.
<!-- Declaracion de los delegates -->
<bean id="carritoDelegate"
class="es.princast.sampleapp.web.delegate.CarritoDelegate">
<property name="carritoManager">
<ref bean="carritoManager"/>
</property>
<property name="formasPagoManager">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
74 de
296
<ref bean="cachedFormasPagoManager"/>
</property>
<property name="agenciasManager">
<ref bean="agenciasManager"/>
</property>
</bean>
Tanto “carritoManager” como “agenciasManager” están definidos en el fichero “managerbeans.xml”, mientras que “cachedFormasPagoManager” se encuentra en el fichero “cachebeans.xml”, desde el que se hace referencia a “formasPagoManager” como podemos ver a
continuación:
...
<bean id="cachedFormasPagoManager"
parent="abstractCarritoCacheProxyFactoryBean">
<property name="target" ref="formasPagoManager" />
</bean>
...
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
75 de
296
30 Path del fichero cache-beans.xml
Para terminar con la capa Delegate, se muestra parte del contenido de la clase “CarritoDelegate”,
donde podremos comprobar que se han definido los setters correspondientes para la inyección de las
dependencias.
public class CarritoDelegate {
// Dependencias inyectadas /beans/web/delegates-beans.xml
private CarritoManager carritoManager;
private FormasPagoManager formasPagoManager;
private AgenciasManager agenciasManager;
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
76 de
296
// set para la injeccion de dependencias
public void setAgenciasManager(AgenciasManager agenciasManager) {
this.agenciasManager = agenciasManager;
}
// set para la injeccion de dependencias
public void setCarritoManager(CarritoManager carritoManager) {
this.carritoManager = carritoManager;
}
// set para la injeccion de dependencias
public void setFormasPagoManager(FormasPagoManager formasPagoManager)
{
this.formasPagoManager = formasPagoManager;
}
...
}
8. Controlador
OpenFWPA se basa en el Framework de Struts, un proyecto de la Apache Software Foundation
orientado a la construcción de aplicaciones Web, que implementa la arquitectura Modelo 2 (MVC).
El núcleo del Framework Struts es una capa de control flexible basada en tecnologías estándar como
servlets, JavaBeans, ResourceBundles y XML, así como varios paquetes del proyecto Jakarta
Commons. (http://jakarta.apache.org/commons).
La figura siguiente muestra como es el ciclo petición-accion-jsp del Framework Struts:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
77 de
296
31 Ciclo petición-acción-jsp de Struts
Para obtener información más detallada sobre Struts consultar la página http://struts.apache.org/.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
78 de
296
32 http://struts.apache.org/
Para la implementación de aplicaciones Web, utilizando el openFWPA, es necesario definir
correctamente el fichero web.xml, tal y como veremos a continuación.
8.1. web.xml
El fichero web.xml es el núcleo de las aplicaciones Web basadas en Struts, y por tanto también lo es de
openFWPA.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
79 de
296
33 Path del fichero web.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
80 de
296
Tal y como se ha hecho en los apartados anteriores, tomaremos como ejemplo el fichero “web.xml” de
la aplicación de ejemplo (sampleapp) para comentar las distintas secciones que se incluyen en este
fichero.
El primer bloque que nos encontramos es “display-name”, que es un elemento opcional y se utiliza
para especificar el nombre que tendrá la aplicación Web, y que en el caso de la aplicación de ejemplo
es “carrito”.
<display-name>carrito</display-name>
El siguiente conjunto de elementos hacen referencia al arranque e inicialización de la aplicación. Se
trata de la variable de contexto que indica la ubicación del fichero de arranque, que como ya vimos
anteriormente, es el “princast-init-script.xml”.
<context-param>
<param-name>INIT.SCRIPT.FILE</param-name>
<param-value>/WEB-INF/princast-init-script.xml</param-value>
</context-param>
El siguiente bloque que se encuentra es el referente a la configuración de filtros, como podemos ver en
el código mostrado a continuación. Esta sección (filter) define, además del nombre del filtro, la clase
que actualizará como filtro (normalmente estas clases deben extender de “PrincastFilter”) y sus
atributos de inicialización.
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>
es.princast.framework.web.filter.security.corp.PrincastSecurityFilter
</filter-class>
</filter>
<filter>
<filter-name>NavigationFilter</filter-name>
<filter-class>
es.princast.framework.web.filter.navigation.NavigationFilter
</filter-class>
</filter>
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
81 de
296
org.tuckey.web.filters.urlrewrite.UrlRewriteFilter
</filter-class>
<init-param>
<param-name>logLevel</param-name>
<param-value>WARN</param-value>
</init-param>
</filter>
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>
es.princast.sampleapp.web.filter.LoginFilter
</filter-class>
</filter>
El siguiente bloque es “filter-mapping”, y se utilizará para mapear los filtros definidos anteriormente
bien con un patrón de URL o con un Servlet. Es importante tener en cuenta que la sección “filtermapping” no puede ser definida antes que la sección “filter” dentro del fichero web.xml.
Este bloque tiene tres propiedades que comentaremos brevemente a continuación.
•
<filter-name>: Hace referencia al nombre (filter-name) del filtro definido en la sección anterior
“filter” que se mapeará con un patrón de URL o con un Servlet.
•
<url-pattern>: Describe el patrón utilizado para resolver la URL en que se mapeará el filtro.
Ejemplos de patrones son “/*” o “/action/*”.
•
<servlet-name>: Hace referencia al nombre del Servet que, tras recibir una petición, provocará
la ejecución del filtro. Este campo debe utilizarse en el caso de que no se haya introducido un
patrón para la URL.
A continuación vemos el bloque “filter-mapping” incluido en el web.xml de la aplicación de ejemplo
(sampleapp) de openFWPA.
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>NavigationFilter</filter-name>
<url-pattern>/action/*</url-pattern>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
82 de
296
</filter-mapping>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
El bloque “listener” recibe notificaciones al producirse varios tipos de eventos, como por ejemplo al
arrancar una aplicaciónción, o al crear/eliminar una sesión.
Todos los “listener” se definen de la misma manera, ya que existe un único elemento llamado
“<listener-class>”, donde se registra el nombre de la clase que responderá al evento (estas clases
deben implementar la interfaz adecuada en función del tipo de evento al que quieran responder), tal y
como podemos ver a continuación.
<listener>
<listener-class>
es.princast.framework.web.startup.PrincastStartupListener
</listener-class>
</listener>
El bloque “servlet” contiene la declaración de los Servlets específicos de la aplicación y sus
parámetros de configuración.
A continuación comentaremos brevemente los elementos más comunes que se pueden incluir en este
bloque.
•
<servlet-name>: Define el alias que tendrá el Servlet disponible en este bloque, y que se
utilizará en otro bloque para referenciar a dicho Servlet.
•
<servlet-class>: Define la clase del Servlet.
•
<jsp-file>: Define la ruta relativa (respecto al directorio raíz) de la página JSP dentro de la
aplicación Web .Este campo debe utilizarse en el caso de que no se haya introducido la clase
del Servlet (servlet-class).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
83 de
296
•
<init-param>: Elemento opcional que define los parámetros de inicialización del Servlet (pares
clave-valor).
•
<load-on-startup>: Elemento opcional que sirve para inicializar el Servlet al arrancar el
servidor.
o En caso de existir, su contenido debe ser un número entero positivo que especificará el
orden en que el Servlet será cargado (un Servlet con este atributo a 1 se cargará antes
que un Servlet con este atributo a 2).
o En caso de no existir, o tener un valor negativo, el servidor cargará el Servlet en el
orden que considere oportuno.
A continuación vemos el bloque “servlet” incluido en el “web.xml” de la aplicación de ejemplo
(sampleapp) de openFWPA.
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>DEBUG</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>carrito</servlet-name>
<servlet-class>
es.princast.framework.web.action.PrincastActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
84 de
296
<param-name>validating</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>definitions-config</param-name>
<param-value>/WEB-INF/tiles-defs.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Al igual que sucedía con el bloque “filter”, los Servlets también deben ser mapeados. Para esto se
utilizará el bloque “servlet-mapping”, aunque a diferencia del bloque “filter-mapping”, los Servlets
únicamente se pueden mapear a través de un patrón de URL.
<servlet-mapping>
<servlet-name>carrito</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
El bloque “welcome-file-list” contiene una lista con las páginas de inicio de la aplicación, de forma
que si se realiza una petición al directorio raíz de nuestra aplicación, el servidor revisa analiza esta
sección para intentar mostrar la página de inicio configurada (por ejemplo podemos especificar dos
páginas, “index.html” y “default.html”, de forma que primero se intenta mostrar la página
“index.html” y en caso de no existir, se intenta mostrar la página “default.html”).
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
El bloque “error-page” define el mapeo de los errores (a través de códigos de error <error-code> o de
tipos de Excepción <exception-type>) producidos en la aplicación, con el recurso procesará este
problema.
Hay que tener en cuenta que no se pueden mostrar juntos en el mismo bloque “error-page” los
elementos “error-code” y “exception-type” (debe aparecer únicamente uno de los dos).
<error-page>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
85 de
296
<error-code>404</error-code>
<location>/pages/404Error.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/pages/unknownError.jsp</location>
</error-page>
<error-page>
<error-code>400</error-code>
<location>/pages/400Error.jsp</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/pages/unknownError.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/pages/unknownError.jsp</location>
</error-page>
<error-page>
<error-code>501</error-code>
<location>/pages/unknownError.jsp</location>
</error-page>
<error-page>
<error-code>502</error-code>
<location>/pages/unknownError.jsp</location>
</error-page>
<error-page>
<error-code>503</error-code>
<location>/pages/unknownError.jsp</location>
</error-page>
El bloque “taglib” define las librerías de etiquetas JSP utilizadas en la aplicación, de forma que
posteriormente en las páginas JSP se puede referencia una librería a través del elemento “taglib-uri”
definido para una librería de etiquetas.
<taglib>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
86 de
296
<taglib-uri>/WEB-INF/tld/princast</taglib-uri>
<taglib-location>/WEB-INF/tld/princast.tld</taglib-location>
</taglib>
Para terminar con el análisis del fichero “web.xml” disponible en la aplicación de ejemplo de
openFWPA (sampleapp), veremos el bloque “resource-ref”, que se utiliza para definir recursos
externos que se utilizarán en la aplicación Web, como por ejemplo una conexión con una base de
datos.
<resource-ref>
<res-ref-name>jdbc/carritoDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
Si lo deseas, puedes obtener más información sobre el
http://docs.oracle.com/cd/E13222_01/wls/docs81/webapp/web_xml.html.
fichero
web.xml
en
8.2. Declaración de las Actions
Las aplicaciones desarrolladas con openFWPA, están basadas en el Framework Spring. Para poder
inyectar dependencias en las Actions de las aplicaciones, al igual que vimos con las capas anteriores,
deben estar definidas como beans de Spring.
En concreto, las definiciones de Actions se realizarán en el fichero “beans/web/action-beans.xml”,
ubicado en el CLASSPATH, tal y como podemos ver en la siguiente imagen.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
87 de
296
34 Path del fichero action-beans.xml
A continuación vemos el contenido del fichero “action-beans.xml” perteneciente a la aplicación de
ejemplo “sampleapp”.
<bean id="logout" scope="prototype"
class="es.princast.sampleapp.web.action.LogoutAction">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
<property name="logoutConfigurable">
<ref bean="logoutConfigurable" />
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
88 de
296
<bean id="carrito" scope="prototype"
class="es.princast.sampleapp.web.action.CarritoActions">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<bean id="viewdetalleproducto" scope="prototype"
class="es.princast.sampleapp.web.action.GetDetalleProductoAction">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<bean id="viewlistaproducto"
class="es.princast.sampleapp.web.action.GetListaProductoAction"
scope="prototype">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<bean id="viewperfil" scope="prototype"
class="es.princast.sampleapp.web.action.GetPerfilAction" >
</bean>
<bean id="confirmar" scope="prototype"
class="es.princast.sampleapp.web.action.ConfirmarAction" >
<property name="formasPagoHelper">
<ref bean="formasPagoHelper" />
</property>
</bean>
<bean id="envio" scope="prototype"
class="es.princast.sampleapp.web.action.SolicitudEnvioAction" >
</bean>
<bean id="confirmpedido" scope="prototype"
class="es.princast.sampleapp.web.action.ConfirmPedidoAction" >
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
89 de
296
<bean id="viewlistaproductopdf" scope="prototype"
class="es.princast.sampleapp.web.action.report.ProductosPDFReportAction" >
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<bean id="viewlistaproductoxml" scope="prototype"
class="es.princast.sampleapp.web.action.xml.ProductosRSSAction">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<bean id="busquedaProductos" scope="prototype"
class="es.princast.sampleapp.web.action.BusquedaProductos">
<property name="carritoDelegate">
<ref bean="carritoDelegate" />
</property>
</bean>
<bean id="formasPagoHelper"
class="es.princast.sampleapp.web.action.FormasPagoHelper">
<property name="delegateCarrito">
<ref bean="carritoDelegate" />
</property>
</bean>
Mientras que las Actions (clases) se declaran en el fichero “action-beans.xml”, todos los aspectos
relativos a la navegación (forwards), mappings, formularios, etc. se han de declarar en el fichero
“struts-config.xml” (se verá en el apartado “8.5. Mapeo en el fichero struts-config.xml”).
De todas formas, en esta sección adelantamos que en la sección <action-mappings> del fichero
“struts-config.xml”, se debe indicar el identificador (id) del bean que implementa la lógica de la
Action, utilizando el atributo "type". Si el valor de este atributo es el identificador de un bean (de la
clase Action), se tomará dicho bean para procesar las peticiones. Si el valor del atributo “type” es el
nombre de una clase (una Action), se instanciará normalmente.
A continuación vemos un ejemplo del mapeo en el fichero “struts-config.xml” de las Actions definidas
más arriba como beans de Spring.
<action-mappings>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
90 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
...
<action path="/login" type="login" scope="request" validate="false"
input="/pages/login.jsp">
<forward name="success" path="/action/viewperfil" redirect="true" />
<forward name="failure" path="/action/login" redirect="true" />
</action>
<action path="/logout" type="logout" scope="request">
<forward name="success" path="/action/login" redirect="true" />
</action>
...
</action-mappings>
Atención
Para poder realizar este tipo de mapeos es necesario utilizar como controlador en el fichero
“struts-config.xml” (Controller) la clase PrincastRequestProcessor.
<controller
processorClass="es.princast.framework.web.action.PrincastRequestProcessor"
/>
8.3. Jerarquía de Actions
OpenFWPA se basa en el Framework de Struts, siendo el Servet controlador una especialización del
“ActionServlet” del Framework de Struts.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
91 de
296
OpenFWPA se proporciona un conjunto de Actions de Struts. Estas Actions definen un nuevo ciclo de
ejecución diferente del existente en las Actions típicas de Struts que se verá un poco más adelante. Las
aplicaciones que utilicen openFWPA deben obligatoriamente, obligatoriamente extender las Actions
del Framework
A continuación se muestra la jerarquía de clases definidas en openFWPA para las Actions.
Actio
PrincastAction
n
PrincastPDFReportActio
PrincastDispatchActio
PrincastListActio
n
PrincastParameterActio
n
custom:
PrincastCustomDispatchActio
PrincastExistAttributeActio
n
PrincastForwardActio
n
custom:
PrincastCRUDActio
:
custom:
PrincastCRUDFormActio
PrincastRemoveAttributeActio
n
35 Jerarquía de Actions
Dentro de openFWPA, las “Actions” estarán disponibles en el directorio “action”, tal y como se
muestra en la siguiente imagen.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
92 de
296
36 Path de las Actions
8.3.1. Clase PrincastAction
La clase base de la jerarquía es PrincastAction. Es una clase abstracta que implementa una máquina de
estados de la que podrán hacer uso el resto de Actions. Define métodos que deben ser sobrescritos por
las Actions de la aplicación. Estos métodos sobrescritos serán invocados por el Framework para dar
respuesta a una solicitud de un cliente, y en un orden preestablecido.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
93 de
296
Este orden se presenta como un esquema de la máquina de estados:
Llamada la método execute()
PreProcess
findFailure
[Sí
] Hay errores?
[No
]
findAler
t
[Sí]
Hay mensajes?
[No
]
excepcion
executeLogic
catchException
postProcess
findFailure
[Si
] Hay errores?
[No
]
findAler
t
[Si
]Hay mensajes?
[No
]
findSuccess
37 Maquinaria de Estados de PrincastAction
Cada uno de los métodos que aparecen en la figura anterior tiene un cometido en particular.
Este cometido es el siguiente:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
94 de
296
•
preProcess (). Se emplea para comprobar las precondiciones que debe cumplir la
PrincastAction. En caso de que no se cumpla alguna precondición se debe dejar un registro de
ello mediante la creación de un error o un mensaje, dependiendo de la gravedad del mismo. Al
dejar constancia de la incidencia se redireccionará el flujo de ejecución hacia una página de
error o a una de alerta, invocándose findFailure() y findAlert(), respectivamente.
•
executeActionLogic (). Implementa la lógica de negocio de la PrincastAction. Éste será el
método sobrescrito de forma obligatoria por todas las acciones que hereden de PrincastAction.
•
catchException(). Se encarga del tratamiento de cualquier excepción que se pueda lanzar
durante la ejecución de la lógica de negocio de la PrincastAction. Si no se quiere que la
excepción sea lanzada de nuevo debe notificarse su tratamiento mediante la llamada al método
unsetException(). De esta forma se entenderá que todo el tratamiento necesario ya ha sido
llevado a cabo y la excepción no será elevada.
•
postProcess(). Se emplea para comprobar las poscondiciones que debe cumplir la
PrincastAction. En caso de que no se cumpla alguna poscondición se debe dejar constancia de
ello mediante la creación de un error o un mensaje. Al dejar constancia de la incidencia se
redireccionará el flujo de ejecución hacia una página de error o a una de alerta, invocándose
findFailure() y findAlert(), respectivamente.
•
findFailure(). Redirecciona a una página de error. Por defecto, la redirección se hace a lo que
se indique en el atributo input de la Action. En caso de que este atributo no sea definido se
intentará hacer la redirección a un forward llamado “failure”.
•
findAlert(). Redirecciona a una página de alerta en la que se muestra un mensaje informativo.
Por defecto la redirección se hace a un forward llamado “warning”.
•
findSuccess(). Redirecciona a la página de éxito, es decir, a aquella a la que se debería ir si la
ejecución de la acción no tiene ningún error. Por defecto se redirecciona a un forward llamado
“success”.
8.3.1.1. Creando un error en una PrincastAction
OpenFWPA posee soporte integrado a la gestión de errores para usuario. Por error se entiende
cualquier situación anómala en la aplicación, sea por un fallo del sistema o por datos incorrectos
suministrados por el usuario. Los errores que no son tratados por las aplicaciones se muestran al
usuario final.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
95 de
296
A continuación se muestra un ejemplo de creación de un error:
protected void preProcess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
java.util.List error = new java.util.ArrayList();
error.add(“error.general”);
saveErrors(error);
};
Para crear un error, se debe crear una instancia de java.util.List a la que se le añadirán hasta cinco
elementos. El primero de estos elementos es la clave asociada al mensaje de error en el fichero de
recursos. En caso de que el mensaje de error sea una simple cadena de caracteres (como ocurre en el
ejemplo) bastará con un solo parámetro. En caso de que el mensaje lleve parámetros de la forma
{0},{1},{2},{3}, un posible mensaje sería:
error.general=Ha ocurrido un error de tipo {0} a las {1} horas en {2} con
usuario {3}
En este caso, la creación del error sería como sigue:
java.util.List error = new java.util.ArrayList();
error.add(“error.general”);
error.add(“GRAVE”); // Parámetro {0}
error.add(“15:30”); // Parámetro {1}
error.add(“Gestión de usuarios”); // Parámetro {2}
error.add(“Administrador”) // Parámetro {3}
saveErrors(error);
El usuario de la aplicación vería el siguiente mensaje:
Ha ocurrido un error de tipo GRAVE a las 15:30 horas en Gestión de usuarios
con usuario Administrador
8.3.1.2. Creando un mensaje de advertencia en una PrincastAction
La forma de crear un mensaje de advertencia es similar al de la creación de un mensaje de error, con la
salvedad de que en lugar de llamar al método saveErrors(List) se ha de invocar el método
saveMessages(List).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
96 de
296
8.3.1.3. Modificando una redirección
En el curso de tratamiento de una petición, puede ser necesario redirigir la petición a otro Servet.
PrincastAction proporciona una implementación por defecto para las redirecciones que pueden tener
lugar durante la ejecución de una petición a una acción. Los métodos que se encargan de estas
redirecciones son:
•
findSuccess(). Redirecciona a un forward etiquetado “success”.
•
findFailure(). Redirecciona a lo que se indique en el atributo input del elemento <action>
correspondiente o a un forward etiquetado “failure” en caso de que no se defina el atributo
input.
•
findAlert(). Redirecciona a un forward etiquetado “warning”.
Todos ellos siguen la misma signatura:
ActionForward find<redireccion> (ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response);
La forma de modificar la redirección de estos métodos es devolviendo una instancia diferente del
ActionForward. Por ejemplo, imaginemos que cuando la ejecución de la PrincastAction tenga éxito,
deseamos que se nos redireccione a un forward etiquetado como “ok”. En este caso, deberíamos
sobrescribir el método findSuccess() como se muestra a continuación:
ActionForward findSuccess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
return mapping.findForward(“ok”);
};
Como se puede apreciar en el ejemplo anterior, la cuestión es obtener del mapping (o crear indicando
el path) un ActionForward a donde deseamos redireccionar la repuesta.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
97 de
296
ActionForward findSuccess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
return new ActionForward("ok", "/action/test?method=ok", true);
};
8.3.1.4. Almacenamiento interno de una Action
Las Actions de Struts no son thread-safe, por tanto, no es correcto utilizar atributos de instancia para
compartir información entre los distintos métodos del ciclo de vida de una Action.
En las ocasiones en que fuera indispensable utilizar un atributo de instancia, se recomienda utilizar el
almacenamiento interno de la Action. Este almacén es un mapa de parámetros thread-local, cuyo
ámbito se limita a los métodos del ciclo de vida de la Action (preProcess(), executeActionLogic(),
catchException() y postProcess()).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
98 de
296
38 Almacenamiento interno de las Actions
Para acceder y manipular este almacenamiento, la PrincastAction dispone de los siguientes métodos:
•
deleteActionParameter( nombre ): Borra del almacén el parámetro especificado.
•
getActionParameter( nombre ): Obtiene del almacén el parámetro cuyo nombre se especifica.
•
getActionParameters( nombre ): Obtiene un iterador con los nombres de todos los parámetros
del almacén.
•
setActionParameter( nombre , valor ): Almacena un parámetro identificándolo con el nombre
dado.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
99 de
296
A continuación se muestra un ejemplo de uso de este almacén:
public class MyAction extends PrincastAction {
public MyAction(){
setActionParameter("param1", "value1");
}
protected void preProcess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
setActionParameter("param2", "value2");
}
protected void executeActionLogic(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
String param1 = (String) getActionParameter("param1");
String param2 = (String) getActionParameter("param2");
...
}
}
En la Action del ejemplo anterior, MyAction se han sobrescrito dos métodos del ciclo de vida de la
Action:
• preProcess()
• executeActionLogic().
En el método preProcess(), se establece el valor de un parámetro “param2”, asignándole la cadena
“value2”.
Por otro lado, en el constructor, se establece un valor para el parámetro “param1”. En el método
executeActionLogic(), se recuperan los valores de ambos parámetros. Recuérdese que únicamente los
métodos del ciclo de vida de la ejecución de la Action tienen visibilidad del almacén. Por este motivo,
en el método executeActionLogic(), la variable param2 tomará el valor “value2”, mientras que la
variable param1 tendrá como valor “null”.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
100 de
296
8.3.1.5. Interrupción de la maquinaria de estados de la Action
En algunas ocasiones es necesario interrumpir el proceso de la maquinaria de estados de la Action sin
redirigir a un estado de error. Para interrumpir la ejecución de la Action, basta con disparar una
excepción de tipo ActionProcessInterruption.
En el siguiente apartado se verá un uso práctico de esta excepción:
8.3.1.5.1. Paginación sin reejecución de la lógica de negocio
El problema es el siguiente: utilizando la librería Display Tag, cada vez que se produzca un
movimiento de página, se solicita una nueva ejecución de la Action que genera el listado, suponiendo
esto la reejecución de la lógica de negocio completa (con acceso a datos incluido).
La solución a este problema es la que sigue:
•
Almacenar siempre las listas de bean a mostrar por el Display Tag en el scope session.
•
En la etiqueta del Display Tag, en el atributo “requestUri”, añadir a la URL de la Action un
parámetro GET (que no entre en conflicto con alguno que ya utilice la Action).
<display:table name="sessionScope.ListaProductoKey" align="center"
id="listProd" pagesize="3" export="false" sort="page"
requestURI="../../action/viewlistaproducto?paginate=true">
•
Extender el método preProcess(). En este método se detectará la existencia del parámetro
definido y, en tal caso, se disparará una ActionProcessInterruption.
protected void preProcess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
if (request.getParameter("paginate") != null) {
throw new ActionProcessInterruption();
}
}
•
Otra opción es utilizar una de las Actions que ya vienen con esta funcionalidad implementada,
como son “PrincastCRUDAction” y “PrincastListAction”.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
101 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
8.3.2. Diferentes tipos de PrincastAction
Además de la clase base PrincastAction, en openFWPA se proporcionan otros tipos de Actions. Por un
lado están PrincastDispatchAction y PrincastCRUDAction, una generalización de la anterior, y por
otro una serie de implementaciones concretas de la PrincastAction tratada en el punto anterior que
facilitan el desarrollo de funcionalidades recurrentes en aplicaciones de gestión.
8.3.2.1. Implementaciones concretas
Existen varias clases que tienen una funcionalidad determinada y que pueden ser reutilizadas tal y
como están. Estas son:
•
•
•
•
PrincastExistAttributeAction
PrincastRemoveAttributeAction
PrincastForwardAction
PrincastParameterAction
A continuación veremos más en detalle cada una de estas cuatro opciones.
8.3.2.1.1. PrincastExistAttributeAction
Esta clase se encarga de verificar la existencia de un atributo en alguno de los scopes o ámbitos
(request, session o application) de la aplicación Web. En la propiedad “parameter” del <actionmapping> se indicará el scope y el nombre del atributo a buscar, separados por ";". Por ejemplo:
parameter="application;HOURS". Si se quiere buscar el atributo en cualquier scope se utilizará un *.
Por ejemplo:
parameter="*;HOURS". Si no se especifica alguno de los dos parámetros, se produce un error.
8.3.2.1.2. PrincastRemoveAttributeAction
Esta clase trata de eliminar un atributo dentro de uno de los ámbitos posibles (application, request,
session). Si el atributo existe devuelve el control a un ActionForward etiquetado con “success” y, sino,
a uno etiquetado con “failure”.
Tanto el ámbito como el atributo se pasan en la propiedad parameter de ActionMapping separados por
";" (parameter="application;HORAS").
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
102 de
296
Para indicar que la búsqueda se realice en todos los ámbitos, el primer parámetro debe ser un asterisco
("*") en lugar del nombre de un ámbito (parameter="*;HORAS"). El atributo sólo será eliminado del
primer contexto en el que sea localizado.
8.3.2.1.3. PrincastForwardAction
Acción que redirecciona a la URI relativa al contexto especificada por la propiedad parameter del
ActionMapping. Esta clase puede ser usada para integrar la aplicación con otra lógica de negocio de
otros componentes implementados como Servlets o páginas JSP, pero manteniendo la funcionalidad
del Servlet controlador de Struts (como el procesado de form beans).
Para configurar una PrincastAction de este tipo en el fichero struts-config.xml es necesario crear una
etiqueta como ésta:
<action path="/guardaSuscripcion" type="
es.princast.framework.web.action.PrincastForwardAction"
name="suscripcionForm" scope="request" input="/
suscripcion.jsp" parameter="/path/a/servlet"/>
Que redireccionará el control a la URI relativa al contexto /path/a/servlet .
8.3.2.1.4. PrincastParameterAction
Esta Action busca un parámetro en la request llamado dispatch y usa su valor para recuperar un
forward local. Una vez conseguido este forward busca un segundo parámetro en la request cuyo
nombre debe ser especificado en la propiedad parameter del ActionMapping. Este valor se concatena
con el valor de la propiedad path del forward obtenido con anterioridad. La URI resultante es la que se
usa para hacer la redirección.
Un ejemplo de la declaración de una PrincastParameterAction de este tipo es:
<action path="/menu/busca"
type="es.princast.framework.web.action.PrincastParameterAction"
name="menuForm"
validate="false" parameter="keyValue">
<forward name="titulo" path="/do/busca/Titulo?titulo=" />
<forward name="autor" path="/do/busca/Autor?autor=" />
<forward name="contenido" path="/do/busca/Contenido?contenido=" />
</action>
Un fragmento de una página JSP que hiciera uso de esto podría ser:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
103 de
296
<html:form action="menu/busca">
Busca artículos por :
<html:select property="dispatch">
<html:option value="titulo">Titulo</html:option>
<html:option value="autor">Autor</html:option>
<html:option value="contenido">Contenido</html:option>
</html:select>
<html:text property="keyValue" />
<html:submit>Enviar</html:submit>
</html:form>
Si el usuario elige Contenido y escribe Java en el campo de texto, el navegador enviará:
dispatch=contenido keyValue=Java. Con esta información la PrincastParameterAction busca el
forward contenido y concatena el valor de keyValue al path del forward, quedando algo del estilo:
/do/busca/Contenido?contenido=Java
En los forwards definidos dentro del mapping de la PrincastParameterAction es posible incluir
parámetros almacenados en la request utilizando la notación ${<nombre del parámetro>}. La
PrincastParameterAction buscará, en el path (definido en el forward) la cadena "${<parámetro>}" y
la sustituirá por “<parámetro>=<valor de parámetro>". Si, por ejemplo, el valor del parámetro
"Titulo" es "Rambo" y se define la siguiente forward: <forward name=”titulo”
path=”/do/busca?${Titulo}” />. La PrincastParameterAction dirigirá a la siguiente URL:
/do/busca?Titulo=Rambo.
8.3.2.2. Actions Compuestas (Dispatch)
En muchas ocasiones interesa tener juntas aquellas acciones que se encargan de tareas relacionadas.
Los métodos que se encargan de la ejecución de tales tareas son encapsulados en una misma clase.
Para estos casos están pensadas las acciones que se presentan en este apartado:
•
•
PrincastDispatchAction
PrincastCRUDAction.
8.3.2.2.1. PrincastDispatchAction
Esta clase es una especialización de la PrincastAction. Mantiene la misma estructura de máquina de
estados que su clase padre pero se puede decir que cada una de las acciones que encapsula dispone de
su propia máquina de estados.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
104 de
296
Si por ejemplo queremos encapsular juntas las acciones “update” e “insert” tendríamos:
updatePreProcess,
updateExecuteActionLogic,
etc.
y
también
insertPreProcess,
insertExecuteActionLogic, etc.
A pesar de que cada acción pueda tener su propia máquina de estados, puede interesar que las acciones
compartan determinada funcionalidad.
Para estos casos están los métodos defaultPreProcess, defaultExecuteActionLogic, etc.
¿Cómo identificar los métodos a ejecutar?
A la hora de seleccionar los métodos a ejecutar la PrincastDispatchAction hace uso del valor que se le
pasa en el parámetro parameter del ActionMapping asociado. Si lo que queremos es ejecutar los
métodos de la máquina de estados asociada a la acción “update”, entonces este parámetro debe ser
<action-mapping …… parameter="method" ….. />, donde el valor del parámetro method, será update.
Si no se da implementación a alguno de los métodos update<estado_máquina>, por ejemplo
updatePreProcess(), la PrincastDispatchAction ejecutará el método defaultPreProcess(). De igual
modo ocurre con el resto de métodos.
Es posible desacoplar el valor del parámetro del nombre del método. Se pueden establecer mapeos
{valor_de_parameter, nombre_de_método} extendiendo el método getMethodKey() de la clase
PrincastDispatchAction.
La PrincastDispatchAction permite, por defecto, una salida de éxito (success), otra de error (error)
para cada método de la Action. Por convenio, en la PrincastDispatchAction, la salida de éxito de un
método será un forward cuyo nombre será el mismo que la clave del método. El forward de error
equivaldrá al nombre del método concatenado con la cadena “-failure”. Para el forward de advertencia
se concatenará la cadena “-warning” al nombre del método.
<action path="/customDispatchAction" name="aForm" parameter="method"
type="customDispatchActionBean" validate="false" scope="session">
<forward name="method1" path="success.path" />
<forward name="method1-failure" path="failure.form" />
<forward name="method2" path="success.dos.path" />
<forward name="failure" path="failure.path" />
</action>
En el ejemplo superior, se está mapeando una Action de tipo PrincastDispatch con dos métodos:
method1 y method2. Cuando se ejecute con éxito el método method1, se redireccionará al path:
“success.path”. Si hay algún error, la redirección se realizará al path: “failure.form”. Por el contrario,
cuando se ejecute el método method2, en caso de éxito la redirección se hará al path:
“success.dos.path” y cuando se produzca un error, el path de redirección será: “failure.path” (ya que,
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
105 de
296
aunque no ha sido definido un forward de error específico, se ha definido el forward de error por
defecto: “failure”).
39 Esquema de la PrincastDispatchAction del ejemplo
En ocasiones, es necesario que una DispatchAction tenga mayor control sobre las redirecciones
(forwards) que debe realizar para cada uno de los métodos de dispatch. Al igual que ocurre con otros
métodos de la Action (executeActionLogic(), catchException(), etc.) es posible redefinir los métodos
de redirección (findSuccess(), findAlert() y findFailure()). El sistema es exactamente el mismo: prefijar
cada método con la clave (MethodKey). Por ejemplo: method1FindSuccess(), method2FindFailure(),
etc.
A continuación se muestra el código de un ejemplo de un PrincastDispatchAction, disponible en la
aplicación de ejemplo “sampleapp”.
public class BusquedaProductos extends PrincastDispatchAction {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
106 de
296
/**
* El delegate que implementa la lógica para el acceso a los productos
*/
protected CarritoDelegate carritoDelegate;
//inyeccion de dependencia (/beans/web/action-beans.xml)
/**
* Asigna el delegate a utilizar para acceder a los productos
*/
public void setCarritoDelegate(CarritoDelegate carritoDelegate) {
this.carritoDelegate = carritoDelegate;
}
/**
* Por defecto, se realizará la búsqueda por nombre
*/
protected void defaultExecuteActionLogic(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
//Inicializamos el radio para que tenga valor por defecto "Por
Nombre"
BusquedaProductosForm bpf = (BusquedaProductosForm) form;
bpf.setDispatch("porNombre");
}
/**
* Realiza al búsqueda de productos por nombre
*/
public void porNombreExecuteActionLogic(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response){
BusquedaProductosForm bpf = (BusquedaProductosForm) form;
BusquedaEstandarVO busquedaEstandar = new BusquedaEstandarVO();
busquedaEstandar.setNombre(bpf.getValorCriterio());
defaultActionlogic(request, busquedaEstandar);
}
/**
* Lanza la búsqueda de productos por descripción
*/
public void porDescripcionExecuteActionLogic(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response){
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
107 de
296
BusquedaProductosForm bpf = (BusquedaProductosForm) form;
BusquedaEstandarVO busquedaEstandar = new BusquedaEstandarVO();
busquedaEstandar.setDescripcion(bpf.getValorCriterio());
defaultActionlogic(request, busquedaEstandar);
}
private void defaultActionlogic(HttpServletRequest request,
BusquedaEstandarVO busquedaEstandar){
/* Puede ser List o PaginatedList. */
Object listaRetorno = null;
/* Paginación. */
BuscadorPaginacionHelper paginacionHelper =
new BuscadorPaginacionHelper();
busquedaEstandar =
paginacionHelper.paginacionOrdenacionColumna(request,
busquedaEstandar);
busquedaEstandar =
paginacionHelper.paginacionOrdenacionDireccion(request,
busquedaEstandar);
busquedaEstandar
busquedaEstandar);
=
paginacionHelper.paginacionPagina(request,
listaRetorno =
carritoDelegate.getListaProductoPaginada(busquedaEstandar);
Integer numElementos =
carritoDelegate.getListaProductoCount(busquedaEstandar);
paginacionHelper.setNumeroElementosTotales(listaRetorno,
numElementos);
//Devolvemos la lista de productos.
request.setAttribute(RequestKeys.LISTA_PRODUCTOS, listaRetorno);
}
protected void catchException(Exception e, ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
108 de
296
//En este método se debe tratar la excepción.
//Generalemente, se debe redireccionar a una página de error.
unsetException(request);
logger.error("Se
productos.");
ha
disparado
una
excepción
buscando
los
}
}
8.3.2.2.2. PrincastLookupDispatchAction
La clase PrincastLookupDispatchAction permite implementar un tipo especial de Dispatch Actions
para formularios con más de un botón (submit). Es este escenario, el botón que se utilice para el envío
del formulario (submit) será quien determine el método que se ejecutará en la Action.
Todas las actions lookup deben manejar formularios que extiendan la clase LookupDispatchForm, ya
que será esta clase quien se encargue de gestionar las correspondencias entre los botones del
formulario y los claves para seleccionar los métodos de la Action.
Para extender LookupDispatchForm se debe implementar el método getButtonKeys(), devolviendo un
array que contendrá las posibles claves que se contemplan para seleccionar el método a ejecutar. Por
otro lado, el formulario maneja otro array (buttons), del mismo tamaño, con una posición reservada
para cada botón.
Al enviarse el formulario, el array buttons, tendrá todos sus campos nulos, salvo el correspondiente al
botón utilizado para el envío (submit). Para seleccionar el método a ejecutar, se utilizará la clave
almacenada, en el array de claves, en la misma posición que el botón activo.
En el ejemplo que se muestra a continuación, se presenta un formulario con tres botones "Aceptar",
"Volver" y "Cancelar". Cada uno de estos botones ejecuta un método distinto:
•
•
•
"foo1" para "Aceptar"
"foo2" para "Volver"
"foo3" para "Cancelar"
public class FooLookupForm extends LookupDispatchForm {
public String[] getButtonKeys() {
return new String[]{"foo1", "foo2", "foo3"};
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
109 de
296
}
En el ActionForm, basta con ordenar los botones y asignarle una clave a cada uno: foo1, foo2 y foo3.
public class FooLookupAction extends PrincastLookupDispatchAction {
protected void foo1ExecuteActionLogic(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
//Implementar logica de negocio
}
protected void foo2ExecuteActionLogic(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
//Implementar logica de negocio
}
protected void foo3ExecuteActionLogic(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
//Implementar logica de negocio
}
}
Las PrincastLookupDispatchAction, desde el punto de vista de su implementación son exactamente
iguales que las PrincastDispatchAction habituales.
<html:form action="test">
<html:submit property="buttons[0]" value="Aceptar"/>
<html:submit property="buttons[1]" value="Volver"/>
<html:submit property="buttons[2]" value="Cancelar"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
110 de
296
</html:form>
En la JSP cada botón submit se debe asignar, por orden, a una entrada del array "buttons".
8.3.2.2.3. PrincastCRUDAction
Esta Action está pensada para la gestión del ciclo de vida de entidades del modelo de la aplicación.
Esta dos Action define los métodos del ciclo de vida de una entidad:
•
•
•
•
•
•
new. Este método debe precargar los campos necesarios para mostrar el formulario de creación
de una nueva entidad.
retrieve. Este método permitirá recuperar una entidad.
list. Este método debe obtener listados de entidades.
delete. Permite borrar una entidad.
update. Permite actualizar los datos de una entidad.
create. Este método servirá para inserter nuevas entidades.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
111 de
296
40 Ejemplo de implementación ArticuloCRUDAction
Atención
Para poder utilizar correctamente este tipo de Actions es necesario mapearlas dos veces en el
fichero struts-config.xml. Uno de los mapeos tendrá la validación de formularios desactivada
(validate = true) y se utilizará para solicitar los métodos que no requieren un formulario: new,
retrieve, list y delete. El otro mapeo tendrá la validación activada y se utilizará para los
métodos que sí requieren formulario: update y create.
<action
path="/productosAction"
type="productosActionBean"
input="facturas.listaProductos"
validate="false"
scope="request"
name="productoForm">
<forward name="list" path="facturas.listaProductos"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
112 de
296
<forward name="retrieve" path="facturas.listaProductos"/>
<forward name="new" path="facturas.listaProductos"/>
<forward name="delete" path="facturas.listaProductos"/>
</action>
<action
path="/productosFormAction"
type="productosActionBean"
input="facturas.listaProductos"
validate="true"
scope="request"
name="productoForm">
<forward name="create" path="facturas.listaProductos"/>
<forward name="update" path="facturas.listaProductos"/>
</action>
Estas Action también soportan, además, paginación sin necesidad de reejecutar la lógica de negocio.
Basta con incluir en la request el parámetro “paginate”. En el caso de esta Action, al contrario que la
PrincastListAction, hay que registrar el objeto que se devuelve para listar, explícitamente en la session.
8.3.2.2.3.1. Validación de Formularios en acciones compuestas
La validación de formularios, en el Framework Struts, redirecciona de forma automática, en caso de
error, a una página de “input” definida en el mapeo de la action (en el fichero struts-config.xml). Este
sistema tiene una limitación y esta es que las Actions compuestas (DispatchAction) solamente pueden
definir una única página de “input” para todos sus métodos.
OpenFWPA permite solucionar esta limitación del Framework Struts. Para ello, basta con seguir los
siguientes pasos:
•
Utilizar el controlador PrincastRequestProcessor. Para ello, es necesario incluir la siguiente
definición de controlador en el fichero struts-config.xml:
<!-- Para poner multiples input -->
<controller
processorClass="es.princast.framework.web.action.PrincastRequestProcessor"
/>
•
En el mapeo de la action compuesta (DispatchAction) que tiene más de una entrada, dejar la
definición de input vacía.
•
Para cada método de la Action, definir un forward utilizando el siguiente convenio de
nombrado: “<nombre del metodo>Input”.
<action
path="/productosFormAction"
type="productosFormAction"
parameter="method" validate="true" scope="request" name="productoForm">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
<forward
<forward
<forward
<forward
Estado
Definitivo
Documento
Manual de Configuración
Página
113 de
296
name="create" path="/action/productosAction?method=list"/>
name="update" path="/action/productosAction?method=list"/>
name="createInput" path="facturas.addProducto"/>
name="updateInput" path="facturas.detalleProducto"/>
...
8.3.2.2.4. Actions para Listados
Un subconjunto especial de Actions son aquellas que no tienen ninguna lógica de negocio especial. Su
único objetivo es obtener un conjunto de objetos para ser mostrados. En función de si el listado se
mostrará en una página HTML o en un PDF, se utilizará la PrincastListAction o la
PrincastPDFReportAction.
41 Esquema de las Actions para los listados
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
114 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
8.3.2.2.4.1. PrincastListAction
Esta Action permite realizar paginación sin necesidad de reejecutar la lógica de negocio (problema del
Display Tag). Por tanto, si una Action tiene únicamente como propósito obtener un listado, se puede
utilizar la PrincastListAction. No hace falta sobrescribir ningún método del ciclo de vida de esta
Action, basta con implementar el método getContentList() y devolver el objeto (o colección de
objetos) que serán mostrados.
El objeto devuelto quedará registrado en sesión, bajo la clave que se especifique en el atributo
parameter, en el mapeo de ese action, en el fichero struts-config.xml. Esa clave será utilizada por el
Display Tag.
En caso de que no se especifique ningún valor para el atributo parameter se disparará una excepción
de tipo PrincastActionProcessException.
A continuación vemos parte del código que tendríamos que incluir en la correspondiente tabla:
requestURI="../../action/MiAction?paginate=true“
8.3.2.2.4.2. PrincastPDFReportAction
Esta Action permite obtener un listado en formato PDF utilizando las utilidades para generación de
informes de openFWPA. Para implementar una “Report Action”, basta con redefinir el método
getReport(), devolviendo un objeto proveedor de contenido PDF (PDFProvider), por ejemplo, un
objeto PrincastReport o PrincastMultiReport.
Habitualmente, los informes compilados (en formato .jasper) se almacenan juntos en una misma
carpeta. Para facilitar la carga de los ficheros “.jasper”, la clase PrincastPDFReportAction
implementa el método loadReport() que devuelve el InputStream correspondiente al fichero del
informe. Este método, supone que todos los informes se encuentran en la misma carpeta (por defecto:
/WEB-INF/reports). Para buscar los informes en una carpeta distinta, se debe sobrescribir el método
getRelativePathToReportFolder().
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
115 de
296
42 Path de la carpeta reports configurada por defecto
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
116 de
296
43 Esquema para la clase PrincastPDFReportAction
8.3.2.2.4.3. PrincastDispatchPDFReportAction
Este Action es la versión dispatch de la PrincastPDFReportAction, permite definir varios métodos
para obtener el PDFProvider, por ejemplo, si el parámetro pasado al Action es myMethod se ejecutaría
el método myMethodGetReport. Para más información, la Sección ”8.3.2.2. Actions Compuestas
(Dispatch)”.
8.3.2.2.4.4. PrincastXMLAction
Este Action permite servir contenido XML. Para servir una respuesta XML, basta con implementar el
método getXMLProvider, que retorna un proveedor de contenido XML.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
117 de
296
A continuación se muestra un ejemplo de una clase disponible en la aplicación de ejemplo que
extiende de la clase “PrincastXMLAction”:
public class ProductosRSSAction extends PrincastXMLAction {
/**
* Path de la plantilla velocity a utilizar para generar el contenido RSS
*/
protected static String TEMPLATE_NAME =
"es/princast/sampleapp/web/action/xml/productosRSS.vm";
/**
* El delegate que se va a utilizar para acceder a la lista de productos
*/
protected CarritoDelegate carritoDelegate;
/**
* Obtiene el delegate a utilizar para acceder a la lista de productos
*/
public CarritoDelegate getCarritoDelegate() {
return this.carritoDelegate;
}
/**
* Asigna un objeto delegate para permitir el acceso a la lista de
* productos
*/
public void setCarritoDelegate(CarritoDelegate carritoDelegate) {
this.carritoDelegate = carritoDelegate;
}
protected XMLProvider getXMLProvider(HttpServletRequest request,
HttpServletResponse response, ActionForm form, ActionMapping mapping) {
// se crea un velocity provider
PrincastVelocityXMLProvider vp =
new PrincastVelocityXMLProvider(TEMPLATE_NAME);
// se añade la lista de productos a la url
vp.put("listaProducto", this.carritoDelegate.getListaProducto());
// se añade la url de sindicacion
vp.put("url",request.getRequestURL().toString());
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
118 de
296
// por último se retorna el provider
return vp;
}
protected void catchException(Exception e, ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
//En este método se debe tratar la excepción.
//Generalemente, se debe redireccionar a una página de error.
unsetException(request);
this.logger.error("Se
listado de productos.");
ha
disparado
una
excepción
obteniendo
el
}
}
El proveedor de contenido XML, será una clase que implemente el interfaz XMLProvider, el cual,
obliga implementar el método writeXML(Writer writer), donde simplemente se escribirá el XML, a
servir, como podemos ver en el siguiente ejemplo:
/**
* Provider que permite escribir contenido XML, generable mediante
* plantillas Velocity
*/
public class PrincastVelocityXMLProvider extends PrincastVelocityProvider
implements XMLProvider{
public PrincastVelocityXMLProvider(String templateName) {
super(templateName);
}
/**
* Método que vuelca el contenido generado por Velocity al writer que
* se le pasa como parámetro
*/
public void writeXML(Writer writer) {
merge(writer);
}
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
119 de
296
8.3.2.2.4.5. PrincastDispatchXMLAction
Este Action es la versión dispatch de la PrincastXMLAction, permite definir varios métodos para
obtener el XMLProvider, por ejemplo, si el parámetro pasado al Action es myMethod se ejecutaría el
método myMethodGetXMLProvider. Para más información, la Sección ”8.3.2.2. Actions Compuestas
(Dispatch)”.
8.4. Action Forms
OpenFWPA dispone de una clase base para el desarrollo de los beans de formulario. Se trata de la
clase PrincastActionForm. Entre las propiedades destacables de esta clase se encuentran:
•
mutable. Para evitar que una PrincastActionForm sea rellenada de forma automática al hacer
un forward entre diferentes acciones, establezca el valor de mutable a true y asegúrese de que
todos los setters comprueban el valor de dicha propiedad (if (isMutable()) this.field = field;).
•
locale. propiedad de la clase Locale. Si la instancia de la form es mutable, se le asigna la locale
de sesión de Struts siempre que se llame a reset(). Para actualizar el locale de la sesión debe
usarse putSessionLocale().
La ubicación de los beans en openFWPA es, tal y como podemos ver en la siguiente imagen, el
directorio “form”:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
120 de
296
44 Path de la carpeta form
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
121 de
296
De la misma manera que en el Framework de Struts, el mapeo de las Actions Forms se sigue haciendo
en el fichero “struts-config.xml”, tal y como veremos en la sección “8.5. Mapeo en el fichero strutsconfig.xml”. De todas formas, a continuación mostramos un breve ejemplo de cómo se deben mapear
los beans en el fichero “struts-config.xml”.
<form-beans>
<form-bean name="confirmForm"
type="es.princast.sampleapp.web.form.ConfirmForm" />
<form-bean name="busquedaProductosForm"
type="es.princast.sampleapp.web.form.BusquedaProductosForm" />
<form-bean name="carritoForm"
type="es.princast.sampleapp.web.form.CarritoForm" />
<form-bean name="detalleProductoForm" dynamic="true"
type="es.princast.framework.web.form.PrincastDynaActionForm">
<form-property name="detalle"
type="es.princast.sampleapp.business.vo.ProductoVO" />
</form-bean>
<form-bean name="perfilForm" dynamic="true"
type="es.princast.framework.web.form.PrincastDynaActionForm">
<form-property name="perfil"
type="es.princast.sampleapp.business.vo.UserVO" />
</form-bean>
</form-beans>
Clase base para el desarrollo de los beans de formulario es “PrincastActionForms”. En cuanto a los
métodos disponibles::
•
setSessionLocale(Locale). Establece el atributo locale.
•
getSessionLocale(). Devuelve el atributo locale.
•
setMutable(boolean). Establece el valor del atributo mutable.
•
isMutable(). Devuelve el valor del atributo mutable.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
122 de
296
•
reset(ActionMapping, HttpServletRequest). Las subclases que deseen resetear el valor de sus
atributos deben comprobar el valor de éste atributo (if (isMutable()) ...).
•
resetSessionLocale(HttpServletRequest). Cambia el atributo locale al valor que tenga el objeto
locale almacenado en la sesión e la petición en curso bajo la clave Globals.LOCALE_KEY.
•
putSessionLocale(HttpServletRequest). Cambia el atributo Globals.LOCALE_KEY de la sesión
por el atributo locale o por el Locale por defecto si el atributo locale es null.
•
getLocaleDisplay(). Devuelve el Locale del usuario o el Locale por defecto.
•
setLocaleDisplay(String). Cambia el atributo locale a un código de lenguaje ISO dado. Recibe
como atributo un String con el código del país.
•
isBlank(String). Comprueba si el String que se le pasa es null o la cadena vacía.
•
describe(). Devuelve un Map con las propiedades de esta PrincastActionForm. Se usa el
método PropertyUtils.describe(). Sobrescriba el método si considera que alguna propiedad no
debería ser mostrada de este modo, o si un nombre de una propiedad debería ser cambiado.
Este método devuelve las propiedades públicas.
•
set(PrincastValueObject). Rellena las propiedades de la clase con las del PrincastValueObject
que se le pasa como parámetro. Se proporciona una implementación vacía de este método para
que sea sobrescrito.
•
populate(PrincastValueObject). Permite cargar los datos del formulario sobre un Value Object.
Este método recibe como parámetro el Value Object sobre el que se van a cargar los datos.
Devuelve una referencia al objeto que contiene todos los datos del formulario.
Para la definición de ActionForms dinámicos, se incluye en openFWPA una clase base:
PrincastDynaActionForm. Se incluye además una clase base para los formularios que van a ser
utilizados por dispatch actions: PrincastDispatchActionForm. Este tipo de formularios incluyen un
campo (method) para seleccionar el método de dispatch que se ejecutará para procesarlo. Las clases
para la implementación de formularios se encuentran en el paquete: es.princast.framework.web.form.
La clase LookupDispatchForm permite disponer de formularios con más de un botón de submit. Para
obtener más información acerca de este tipo de forms, véase el apartado “8.3.2.2.2.
PrincastLookupDispatchAction”.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
123 de
296
A continuación se muestra un ejemplo de una clase que extiende de PrincastDispatchActionForm,
disponible en la aplicación de ejemplo de openFWPA (sampleapp).
public class BusquedaProductosForm extends PrincastDispatchActionForm {
private static final long serialVersionUID = -4890101581101937298L;
/**
* Almacena el criterio de busqueda a utilizar
*/
protected String dispatch;
/**
* Clave para la busqueda
*/
protected String valorCriterio;
/**
* Constructor del formulario
*/
public BusquedaProductosForm() {
this.dispatch = "porNombre";
}
public String getDispatch() {
return dispatch;
}
public void setDispatch(String dispatch) {
this.dispatch = dispatch;
}
public String getValorCriterio() {
return valorCriterio;
}
public void setValorCriterio(String valorCriterio) {
this.valorCriterio = valorCriterio;
}
public void reset(ActionMapping mapping, HttpServletRequest request){
this.valorCriterio = "";
}
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
124 de
296
8.4.1. Validación de formularios
OpenFWPA incorpora un sistema de validación de formularios que se utiliza definiendo una serie de
reglas de validación en un fichero XML (WEB-INF/validator-rules.xml). En este fichero están
definidas las reglas de validación (campos obligatorios, rangos de valores, fechas, direcciones de email, etc.). Se pueden añadir a este fichero nuevas reglas de validación definidas por el programador.
A continuación se muestra parte del contenido del fichero “validator-rules.xml” dentro de la aplicación
de ejemplo (sampleapp):
...
<validator name="required"
classname="org.apache.struts.validator.FieldChecks"
method="validateRequired"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
msg="errors.required"/>
<validator name="requiredif"
classname="org.apache.struts.validator.FieldChecks"
method="validateRequiredIf"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
msg="errors.required"/>
...
Para mapear los campos de un formulario (PrincastActionForm), con las reglas de validación, se
utiliza el fichero “WEB-INF/validation.xml”. A continuación se muestra un ejemplo del fichero
incluido en la aplicación de ejemplo (sampleapp):
<form-validation>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
125 de
296
<formset>
<form name="confirmForm">
<field property="fecha" depends="required,date" page="1">
<arg0 key="label.fecha"/>
<var>
<var-name>datePattern</var-name>
<var-value>dd/MM/yyyy</var-value>
</var>
</field>
<field property="formaPago" depends="required" page="1">
<arg0 key="label.formaPago"/>
</field>
<field property="nombre" depends="required" page="2">
<arg0 key="label.name"/>
</field>
<field property="apellido1" depends="required" page="2">
<arg0 key="label.apellido1"/>
</field>
<field property="apellido2" depends="required" page="2">
<arg0 key="label.apellido2"/>
</field>
<field property="direccion" depends="required" page="2">
<arg0 key="label.direccion"/>
</field>
<field property="cp" depends="required" page="2">
<arg0 key="label.cp"/>
</field>
<field property="provincia" depends="required" page="2">
<arg0 key="label.provincia"/>
</field>
</form>
</formset>
</form-validation>
Se valida una PrincastActionForm de nombre confirmForm con dos campos: fecha y formaPago. En
ambos casos los campos son obligatorios, y además se indica que el primero es una fecha. Mediante
arg0 se indica qué cadena de texto del fichero ApplicationResources.properties se utilizará para
construir el mensaje de error en el caso de que la validación no sea satisfactoria. En este caso son dos
cadenas que contienen el nombre de los campos que completarán los mensajes de error para cada una
de las reglas de validación que también se encuentran en dicho fichero. Además, en el caso de la
validación de fechas se necesita un parámetro adicional indicando el patrón que se utilizará para
validar la fecha.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
126 de
296
Para mostrar los errores de validación en el cliente se necesita incluir en las páginas JSP el tag
<ui:errors/> definido en la tld princast-ui.tld. Para más información sobre las reglas de validación y
su utilización, consultar la guía del validador de Struts disponible en la dirección
http://struts.apache.org/1.2.4/userGuide/dev_validator.html.
45 http://struts.apache.org/1.2.4/userGuide/dev_validator.html
8.4.1.1. Validaciones de openFWPA
Además de las validaciones incluidas en el Struts Validator, para facilitar algunas de las validaciones
más habituales, se incluyen en la distribución de openFWPA algunas reglas de validación:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
127 de
296
•
twofields. Dados dos campos, verifica que sean iguales. El nombre segundo campos se debe
especificar, en el fichero validation.xml, utilizando una variable de nombre: “secondProperty”.
Si no se realiza correctamente la validación, se mostrará el mensaje de error declarado, en
ApplicationRespurces.properties, bajo la clave: errors.twofields.
•
twofiedsdistinct. Dados dos campos, verifica que sean diferentes. El nombre segundo campos
se debe especificar, en el fichero validation.xml, utilizando una variable de nombre:
“secondProperty”. Si no se realiza correctamente la validación, se mostrará el mensaje de error
declarado, en ApplicationRespurces.properties, bajo la clave: errors.twofields.distinct.
•
notEmptyArray. Dado un campo compuesto (array), verifica que no sea nulo. Si no se realiza
correctamente la validación, se mostrará el mensaje de error declarado, en
ApplicationRespurces. properties, bajo la clave: errors.notEmptyArray.
•
nif. Valida el formato de un NIF o NIE. Si no se realiza correctamente la validación, se
mostrará el mensaje de error declarado, en ApplicationRespurces.properties, bajo la clave:
errors.nif.
•
cif. Valida el formato de un CIF (Código de Identificación Fiscal). Si no se realiza
correctamente la validación, se mostrará el mensaje de error declarado, en
ApplicationRespurces. properties, bajo la clave: errors.cif.
•
nie. Valida el formato de un NIE (Número de Identificación de Extranjero). Si no se realiza
correctamente la validación, se mostrará el mensaje de error declarado, en
ApplicationRespurces.properties, bajo la clave: errors.nie.
•
nifOrNie. Valida que un campo se ajuste al formato de un NIF o un NIE (cualquiera de los dos
es válido). Si no se realiza correctamente la validación, se mostrará el mensaje de error
declarado, en ApplicationRespurces.properties, bajo la clave: errors.nifOrNie.
•
datesMinor. Dadas dos fechas, valida que la primera sea menor estricta que la segunda. El
nombre del campo de la segunda fecha se debe especificar, en el fichero validation.xml,
utilizando una variable de nombre: “secondDate”. Si no se realiza correctamente la validación,
se mostrará el mensaje de error declarado, en ApplicationRespurces.properties, bajo la clave:
errors.dates.minor.
•
datesMinorOrEqual. Dadas dos fechas, valida que la primera sea menor o igual que la segunda.
El nombre del campo de la segunda fecha se debe especificar, en el fichero validation.xml,
utilizando una variable de nombre: “secondDate”. Si no se realiza correctamente la validación,
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
128 de
296
se mostrará el mensaje de error declarado, en ApplicationRespurces.properties, bajo la clave:
errors.dates.minorOrEqual.
•
datesEqual. Dadas dos fechas, valida que sean iguales. El nombre del campo de la segunda
fecha se debe especificar, en el fichero validation.xml, utilizando una variable de nombre:
"secondDate". Si no se realiza correctamente la validación, se mostrará el mensaje de error
declarado, en ApplicationRespurces.properties, bajo la clave: errors.dates.equal.
•
datesMajor. Dadas dos fechas, valida que la primera sea mayor estricta que la segunda. El
nombre del campo de la segunda fecha se debe especificar, en el fichero validation.xml,
utilizando una variable de nombre: "secondDate". Si no se realiza correctamente la validación,
se mostrará el mensaje de error declarado, en ApplicationRespurces.properties, bajo la clave:
errors.dates.major.
•
datesMajorOrEqual. Dadas dos fechas, valida que la primera sea mayor o igual que la segunda.
El nombre del campo de la segunda fecha se debe especificar, en el fichero validation.xml,
utilizando una variable de nombre: "secondDate". Si no se realiza correctamente la validación,
se mostrará el mensaje de error declarado, en ApplicationRespurces.properties, bajo la clave:
errors.dates.majorOrEqual.
8.4.1.2. Implementación de validadores
Para implementar nuevos validadores "ad-hoc" para formularios específicos de las aplicaciones, se
deben seguir los siguientes pasos:
•
Implementar una clase de validación. Se debe implementar una clase de utilidad que contenga,
como métodos estáticos, los métodos de validación. Estos métodos deben tener la siguiente
signatura:
public static boolean <nombreValidacion>(Object bean, ValidatorAction va,
Field field, ActionErrors errors, HttpServletRequest request)
El parámetro bean será el formulario a validar y el parámetro field, la definición del campo
(obtenida del fichero validation.xml).
Para facilitar la implementación de validadores, se ha incluido en openFWPA la clase base
AbstractValidator que puede ser extendida implementando el método validate(). Esta clase
sigue el patrón Template Method, es decir, implementa la lógica estándar para el proceso de los
campos y de los errores en la validación, quedando a las subclases la responsabilidad de
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
129 de
296
implementar la lógica concreta de validación. Un ejemplo concreto de cómo crear una clase de
validadores, utilizando AbstractValidators es:
public class FieldValidations {
...
public static final String SECOND_PROPERTY = "secondProperty";
...
public static boolean validateTwoFields(Object bean, ValidatorAction va,
Field field, ActionMessages errors, HttpServletRequest request) {
return new AbstractValidator() {
public boolean validate(Object bean, ValidatorAction va,
Field field, ActionMessages errors, HttpServletRequest request){
FormAccessor accessor = new FormAccessor(bean);
String value = accessor.getFieldAsString(field);
String sProperty2 = field.getVarValue(SECOND_PROPERTY);
String value2 = accessor.getFieldAsString(sProperty2);
if (!GenericValidator.isBlankOrNull(value)) {
try {
if(FieldComparatorValidatorHelper.distinct(value, value2)) {
throw new ValidatorException();
} // try
} catch (Exception e) {
logger.warn("Error en la validacion : " + value + " y " +
value2 + " no son iguales o no se han podido comparar");
processException(errors, field, request, va, e);
return false;
} //catch
} // if
return true;
} // validate
}.validate(bean, va, field, errors, request);
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
130 de
296
}
...
•
Registrar el validador. Una vez implementados los métodos de validación, se deben registrar
en el fichero validation-rules.xml (como cualquier otro validador de Struts).
<validator name="nif"
classname="es.princast.framework.web.validator.ids.IFValidations"
method="validateNIF"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
javax.servlet.http.HttpServletRequest"
depends="required"
msg="errors.nif" >
</validator>
8.5. Mapeo en el fichero struts-config.xml
De la misma manera que en el Framework de Struts, el mapeo de las actions se sigue haciendo en el
fichero struts-config.xml (fichero que contiene información sobre la configuración de Struts).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
131 de
296
46 Path del fichero struts-config.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
132 de
296
Tal y como se ha hecho en los apartados anteriores, tomaremos como ejemplo el fichero “strutsconfig.xml” de la aplicación de ejemplo (sampleapp) para comentar las distintas secciones que se
incluyen en este fichero.
El primer bloque que nos encontramos es “form-beans” (opcional). Aquí se definen los beans de
formulario:
•
Clases que heredan de es.princast.framework.web.action.PrincastActionForm, y que sirven
para almacenar las propiedades introducidas en formularios enviados mediante peticiones Http.
Estos formularios serán utilizados por las acciones.
•
Clases que heredan de es.princast.framework.web.action.PrincastDynaActionForm. Sirven
para definir un bean de formulario a través del fichero de configuración sin tener que escribir
una clase para ello. Sus propiedades son visibles con métodos get y set de la misma forma que
un bean convencional.
<form-beans>
<!— PrincastActionForm -->
<form-bean name="confirmForm"
type="es.princast.sampleapp.web.form.ConfirmForm" />
<form-bean name="busquedaProductosForm"
type="es.princast.sampleapp.web.form.BusquedaProductosForm" />
<form-bean name="carritoForm"
type="es.princast.sampleapp.web.form.CarritoForm" />
<!— PrincastDynaActionForm -->
<form-bean name="detalleProductoForm" dynamic="true"
type="es.princast.framework.web.form.PrincastDynaActionForm">
<form-property name="detalle"
type="es.princast.sampleapp.business.vo.ProductoVO" />
</form-bean>
<form-bean name="perfilForm" dynamic="true"
type="es.princast.framework.web.form.PrincastDynaActionForm">
<form-property name="perfil"
type="es.princast.sampleapp.business.vo.UserVO" />
</form-bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
133 de
296
</form-beans>
El siguiente conjunto de elementos “global-exceptions”, se utilizan para tratar excepciones que no han
sido tratadas en la Action.
En el siguiente ejemplo se indica que las excepciones no capturadas del tipo
Java.langException, sean reenviadas a la página indicada en el atributo path (en este caso se trata de
una definition “carrito.error” disponible en el fichero “tiles-defs.xml”). El mensaje de error que se
mostrará en la página de error con el tag <html:errors/>, estará en el fichero de recursos
(ApplicationResources.properties) con la clave cuyo valor se indique en el atributo key, que en este
caso es “global.princastexception”. Mediante el atributo handler se especifica qué manejador de
errores se utilizará para tratar la excepción. En este caso se trata del manejador por defecto de Struts
(que en el método execute no realiza nada), pero podría definirse un manejador que heredase de él y
sobrescribiese el método execute.
Se recomienda utilizar el método catchException() de las acciones para tratar las excepciones y no
recurrir a excepciones globales.
<global-exceptions>
<exception key="global.princastexception" type="java.lang.Exception"
path="carrito.error" handler="org.apache.struts.action.ExceptionHandler" />
</global-exceptions>
Se recomienda utilizar el método catchException() de las acciones para tratar las excepciones y no
recurrir a excepciones globales.
<global-exceptions>
<exception key="global.princastexception" type="java.lang.Exception"
path="carrito.error" handler="org.apache.struts.action.ExceptionHandler" />
</global-exceptions>
El siguiente bloque “global-forwards” representa los ActionForwards (asociaciones entre nombres
lógicos y URIs) disponibles para todas las acciones. Cuando una acción finaliza, devuelve un
ActionForward o null. Si la acción no devuelve null, el ActionServlet redirige el control al path que sea
devuelto por la ActionForward.
<global-forwards>
<forward name="welcome" path="/action/viewperfil" />
<forward name="avisolegal" path="/action/avisolegal" />
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
134 de
296
<forward name="clearCarrito" path="/action/carrito?method=clear" />
</global-forwards>
En la “action-mappings” sección se definen los mapeos de las acciones que manejará la aplicación.
Los parámetros comunes a los diferentes tipos de acciones existentes son:
•
path. Path relativo al módulo de la acción, comenzando por el carácter /, y sin la extensión del
nombre de archivo si se utiliza ésta para el mapeo (por ejemplo, para un mapeo del tipo
accion.do, el path sería /accion).
•
type. Nombre de la clase, totalmente calificado, de la acción que procesará las peticiones para
este mapeo. El atributo no es válido si se especifican los atributos forward o include.
•
scope. El contexto (request o session) que se utiliza para acceder a los beans de formulario.
•
validate. (def. true) Poner a true si el método validate del bean de formulario debe ser llamado
antes de llamar a este mapeo.
A continuación se comentarán de forma más detallada los distintos tipos de acciones que maneja el
Framework.
•
PrincastAction. Clase abstracta de la que deben heredar todas las acciones de openFWPA. A
continuación se muestra un ejemplo de mapeo:
<action path="/login"
type="es.princast.framework.carrito.actions.LoginAction" scope="request"
validate="false" input="carrito.login">
<forward name="success" path="/action/viewperfil" redirect="true" />
<forward name="failure" path="/action/login" redirect="true" />
</action>
La acción lleva anidadas dos ActionForwards a los que se redirigirá en función de que la acción
se haya ejecutado con éxito o no. La sintaxis es similar a la de las Global forwards. En el caso
de no encontrar la Forward que devuelve el método execute de la acción local a la propia
acción, se buscará la misma a nivel global. Es necesario que a ámbito local o global haya
definidos dos forwards success y failure.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
135 de
296
Una acción también puede llevar anidadas excepciones. La sintaxis es la misma que la de las
Global Exceptions. En el caso de no tener mapeada una excepción local a la acción, se
intentaría buscar a nivel global.
•
PrincastDispatchAction. Encapsula diferentes métodos de ejecución de una acción en una
misma clase. Para ello, se especifica en el atributo parameter del mapeo de la acción en el
fichero struts-config.xml, el nombre del parámetro cuyo valor será el nombre del método que
ejecutará la acción.
El siguiente ejemplo muestra el mapeo de una acción que hereda de PrincastDispatchAction.
La acción ejecutará el método cuyo nombre se le pase en el parámetro method.
<action path="/carrito" parameter="method"
type="es.princast.framework.carrito.actions.CarritoActions"
scope="request" input="carrito.viewcarrito" validate="false">
<forward name="success" path="carrito.viewcarrito" redirect="true" />
</action>
•
PrincastCRUDAction hereda de la PrincastDispatchAction. Está pensada para manejar métodos
de creado, consulta, actualizado y borrado (New, Create, Retrieve, List, Update y Delete). Los
posibles nombres de los métodos a ejecutar están definidos como constantes en la propia clase:
CREATE_KEY: cuyo valor es create
RETRIEVE_KEY: cuyo valor es retrieve
UPDATE_KEY: cuyo valor es update
DELETE_KEY: cuyo valor es delete
NEW_KEY: cuyo valor es new
LIST_KEY: cuyo valor es list
•
PrincastForwardAction. Redirecciona a la URI relativa al contexto que se especifique en la
propiedad parameter del mapeo de la acción. Un ejemplo de utilización de una acción de este
tipo es el siguiente:
<action
path="/welcome"
parameter="carrito.login"
scope="request"
validate="false"
type="es.princast.framework.web.action.PrincastForwardAction"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
136 de
296
La acción redirecciona a la definición de nombre carrito.login.
•
PrincastParameterAction. Busca un parámetro en la request de nombre dispatch y lo usa para
obtener un ActionForward. Una vez conseguido esto, va en busca de un segundo parámetro en
la request cuyo nombre debe ser especificado en la propiedad parameter del mapeo de la
acción. Este valor se concatena con la URI obtenida de la propiedad path del ActionForward
que se buscó con el valor del parámetro dispatch, y se redirecciona a la URI resultante.
•
PrincastExistsAttributeAction. Verifica la existencia de un atributo en alguno de los ámbitos
posibles (request, session o application). En la propiedad parameter del mapeo de la acción se
le indicará el ámbito y el nombre del atributo a buscar siguiendo la siguiente sintaxis:
Parameter=”ambito;ATRIBUTO”. Si se quiere buscar en cualquier ámbito, se especificará el
valor *.
Si no se especifica alguno de los dos parámetros se produce un error.
parameter="application;HOURS"
parameter="*;HOURS"
•
PrincastRemoveAttributeAction. Trata de eliminar un atributo en alguno de los ámbitos
posibles (request, session o application). Si el atributo existe devuelve el control a un
ActionForward instanciado con Tokens.SUCCESS y sino con uno instanciado con
Tokens.FAILURE. La sintaxis es idéntica a la de la PrincastExistsAttributeAction.
En el siguiente bloque es “controller”, donde se configura el controlador (RequestProcessor).
Se
recomienda
utilizar
los
controladores
proporcionados
por
openFWPA
(PrincastTilesRequestProcessor o PrincastRequestProcessor).
A continuación podemos ver el contenido de esta sección dentro del fichero “strutsconfig.xml” disponible en el proyecto de ejemplo “sampleapp”.
<action-mappings>
<action path="/avisolegal" parameter="carrito.aviso_legal"
type="es.princast.framework.web.action.PrincastForwardAction"
scope="request" validate="false">
</action>
<action path="/viewlistaproductopdffwd"
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
137 de
296
type="es.princast.framework.web.action.PrincastForwardAction"
parameter="/action/viewlistaproductopdf"/>
<action path="/logout" type="logout" scope="request">
<forward name="success" path="/action/viewperfil" redirect="true" />
</action>
<action path="/viewcarrito" parameter="carrito.viewcarrito"
type="es.princast.framework.web.action.PrincastForwardAction"
scope="request" validate="false">
</action>
<action path="/carrito" name="carritoForm" type="carrito"
scope="request" input="carrito.viewcarrito" validate="false"
parameter="method">
<forward name="success" path="MenuVerCarrito" redirect="true" />
</action>
<action path="/viewdetalleproducto" name="detalleProductoForm"
input="/index.jsp" type="viewdetalleproducto" scope="request"
validate="false">
<forward name="success" path="carrito.detalleprod" />
</action>
<action path="/viewlistaproducto" input="carrito.listaprod"
type="viewlistaproducto"
scope="request" validate="false" name="busquedaProductosForm">
<forward name="success" path="carrito.listaprod" />
</action>
<action path="/viewperfil" name="perfilForm" input="/index.jsp"
type="viewperfil" scope="request" validate="false">
<forward name="success" path="carrito.viewperfil" />
</action>
<action path="/confirmar" name="confirmForm" type="confirmar"
validate="false" scope="session" input="carrito.viewcarrito">
<forward name="success" path="carrito.confirmpedido"/>
</action>
<action path="/envio" name="confirmForm" type="envio" validate="true"
scope="session" input="carrito.confirmpedido">
<forward name="success" path="carrito.envio"/>
</action>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
138 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<action path="/confirmpedido" name="confirmForm" type="confirmpedido"
validate="true" scope="session" input="carrito.envio">
<forward name="success" path="carrito.confirmado"/>
</action>
<action path="/viewlistaproductopdf" type="viewlistaproductopdf"
validate="false" scope="request" />
<action path="/viewlistaproductoxml" type="viewlistaproductoxml"
alidate="false" scope="request" />
<action path="/buscarProdParameter"
name="busquedaProductosForm"
type="es.princast.framework.web.action.PrincastParameterAction"
scope="request"
validate="true"
input="carrito.buscarprod"
parameter="valorCriterio">
<forward name="porNombre"
path="/action/busquedaProductos?method=porNombre" />
<forward name="porDescripcion"
path="/action/busquedaProductos?method=porDescripcion" />
</action>
<action path="/busquedaProductos"
name="busquedaProductosForm"
type="busquedaProductos"
scope="request"
validate="false"
parameter="method">
<forward name="default" path="carrito.buscarprod" />
<forward name="porNombre" path="carrito.listaprod" />
<forward name="porDescripcion" path="carrito.listaprod" />
</action>
</action-mappings>
El uso de este controlador permite añadir alguna funcionalidad extra que no implementa el controlador
por defecto (por ejemplo, múltiples “input” por action, forwards a entradas de menú, etc.).
<controller
processorClass="es.princast.framework.web.action.PrincastRequestProcessor"
/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
139 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
El uso de este RequestProcessor limita los posibles mapeos que se pueden hacer sobre el ActionServlet
(ver a continuación). Las Actions únicamente se pueden mapear a un path del tipo: “/path/*”. No se
permiten mapeos del tipo: “/path/*.do”.
La sección “message-resources” indica que fichero contiene los mensajes que mostrará la aplicación.
En este caso se trata del ApplicationResources.properties del paquete resources.
<message-resources parameter="resources.ApplicationResources" />
En la sección “plug-in”se indica que plug-ins va a utilizar la aplicación. En primer lugar se indica que
se utilizará el validador de Struts, y que las reglas de validación se encuentran en validator-rules.xml y
los mapeos entre los formularios y las reglas en validation.xml.
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml, /WEB-INF/validation.xml" />
</plug-in>
A continuación se indica que se utilizara tiles, y que las definitions se describirán en el fichero tilesdefs.xml.
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config"
value="/WEB-INF/tiles-defs.xml" />
<set-property property="moduleAware" value="true" />
<set-property property="definitions-parser-validate" value="true" />
</plug-in>
En tercer llugar se indica que se utilizara el Struts Menu y que su configuración residirá en el fichero
“menu-config.xml”.
<plug-in className="net.sf.navigator.menu.MenuPlugIn">
<set-property property="menuConfig"
value="/WEB-INF/menu-config.xml"/>
</plug-in>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
140 de
296
Y por último se carga el plug-in de Spring dentro de la configuración de Struts.
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="classpath://beans/**/*-beans.xml"/>
</plug-in>.
Si lo deseas, puedes obtener más información
http://struts.apache.org/1.x/userGuide/configuration.html.
sobre
el
fichero
web.xml
en
9. La vista
Esta capa se encarga de mostrar las entidades del modelo al usuario. En openFWPA, se implementa
esta capa sobre la tecnología JSP.
En esta capa, no debería incluirse lógica de negocio. Por este motivo se recomienda utilizar librerías de
etiquetas, que permiten una separación clara entre presentación y lógica de negocio. Es importante
recordar que openFWPA se basa en el Framework de Struts, un proyecto de la Apache Software
Foundation orientado a la construcción de aplicaciones Web, que implementa la arquitectura Modelo 2
(MVC).
9.1. Hojas de estilo (CSS)
Las aplicaciones J2EE desarrolladas utilizando openFWPA, como por ejemplo la aplicación de
ejemplo (sampleapp), centralizan el aspecto en hojas de estilo (CSS), lo que nos permite modificar el
aspecto de manera centralizada.
Estas hojas de estilo permiten separar las instrucciones de formateo (posición, color, tamaño, etc) del
código HTML generado por la aplicación. Esto ofrece una mayor sencillez al desarrollo y una mayor
adaptabilidad al cambio - en caso de ocurrir cambio de imagen corporativa, se minimiza el ámbito del
cambio unas pocas hojas de estilo.
9.1.1. Hojas de estilo en la aplicación de ejemplo
La aplicación ejemplo (sampleapp) maneja 6 hojas de estilos. Debe tomarse esta implementación
como referencia de posicionamiento y formateo de textos, bloques, párrafos, etc. En general, se
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
141 de
296
prohíbe el uso de directrices de estilo dentro del código HTML. Cualquier estilo o posicionamiento de
bloques deberá ir contenido en una hoja de estilos.
Las hojas de estilo manejadas por la aplicación de ejemplo son:
•
general.css. Establece los estilos para los elementos más comunes de una página HTML
(enlaces, tablas, celdas, párrafos, listas, textos…)
•
position.css. Define el posicionamiento de los bloques <div> dentro de la página. La estructura
de una página se ha definido en base a bloques, de los cuales no todos tienen porque aparecer,
según las necesidades de página. Para más información, véase los apartados correspondientes a
los layouts tiles.
•
princast-ui.css. CSS para el estilo de los componentes de las etiquetas princast para las
páginas.
•
tabs.css. Hoja de estilos para el tabbed menu.
•
displaytag.css. Hoja de estilos exclusiva para el aspecto de las tablas generadas por el tag
displaytag. El displaytag genera listas paginadas.
•
carrito.css. Hoja de estilo para la ubicación y formato de componentes específicos de la
aplicación de ejemplo.
Estas hojas de estilo están ubicadas en “pages/css”, tal y como se puede ver en la siguiente imagen.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
142 de
296
47 Path del directorio CSS donde se almacenan las hojas de estilo
Las hojas de estilo son enlazadas a través de la página head.jsp. En caso de necesitar nuevas hojas de
estilo, se utilizará este componente para hacerlo, de forma que esta tarea quede totalmente
centralizada. El código actual de la página head.jsp es:
<%@ page errorPage="/pages/errorEnJSP.jsp" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"
%>
<html:xhtml />
<meta http-equiv="Content-type" content="text/html; charset=ISO-8859-1" />
<!-- Css basicas -->
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
143 de
296
<link rel="stylesheet" type="text/css" href="../../css/general.css" />
<link rel="stylesheet" type="text/css" href="../../css/position.css" />
<link rel="stylesheet" type="text/css" href="../../css/princast-ui.css" />
<!-- Css para el menú Tabs -->
<link rel="stylesheet" type="text/css" href="../../css/tabs.css" />
<!-- Css para los listados -->
<link rel="stylesheet" type="text/css" href="../../css/displaytag.css" />
<!-- Css especifica de la aplicacion -->
<link rel="stylesheet" type="text/css" href="../../css/carrito.css" />
Según lo expuesto, el código de las páginas JSP debe reducirse al mínimo imprescindible, obteniendo
así un código mucho más claro y mantenible.
Ejemplo: código JSP del cuerpo de una página de la aplicación sampleapp:
<%@
<%@
%>
<%@
%>
<%@
%>
<%@
<%@
page errorPage="/pages/errorEnJSP.jsp" %>
taglib uri="http://jakarta.apache.org/struts/tags-bean"
taglib
uri="http://jakarta.apache.org/struts/tags-html"
prefix="bean"
prefix="html"
taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic"
taglib uri="http://displaytag.sf.net" prefix="display" %>
taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
<html:xhtml />
<div id="cuerpo">
<ui:errors/>
<ui:box bodyId="productos_box">
<ui:box-caption headingLevel="1">
<bean:message key="productos.box.caption" />
</ui:box-caption>
<display:table
name="listaProductos"
id="listProd"
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
144 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
export="false"
requestURI="../../../action/viewlistaproducto"
summary="Listado de productos"
>
<display:column titleKey="productos.column.name"
sortProperty="nombre" sortable="true" >
<bean:define id="nombreProducto" name="listProd"
property="name" toScope="page"/>
<html:link action="/viewdetalleproducto" paramId="id"
paramName="listProd" paramProperty="id"
title="<%=\"Visualice el detalle de \" + nombreProducto%>">
<bean:write name="listProd" property="name" />
</html:link>
</display:column>
<display:column titleKey="productos.column.description"
property="description" />
<display:column titleKey="productos.column.basePrice"
sortProperty="precio" property="basePrice" sortable="true"
headerClass="sortable"/>
<display:column>
<bean:define id="url" name="listProd"
property="smallImageURL" />
<bean:define id="nombre" name="listProd"
property="name" toScope="page"/>
<html:img styleClass="imagen_producto"
src="<%=url.toString()%>"
alt="<%=\"Imágen de \" + nombre%>"/>
</display:column>
</display:table>
</ui:box>
<html:img styleClass="carrito_image" src="../../images/productos.jpg"
alt=""/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
145 de
296
<span id="pdf_link">
<html:link styleClass="enlace_imagen enlace_pdf"
action="/viewlistaproductopdf" titleKey="productos.descargaPDF.title">
<bean:message key="productos.descargaPDF"/>
</html:link>
</span>
</div>
El código anterior responde a la forma en que se construye un cuerpo de página. No se ha utilizado en
ningún caso directrices de estilo o posicionamiento dentro de este código, y en esta forma resulta más
claro, donde se atiende únicamente a lo que debe mostrar la página y no a como y dónde debe
mostrarlo.
9.2. Composición de las páginas JSP (vistas)
OpenFWPA dispone de plantillas para componer la vista. Para ello hace uso del Framework Tiles ™,
el cual permite realizar definiciones (definitions) de páginas ensamblando tiles (término que podría
traducirse como azulejo, es decir, son como piezas de un puzzle). Las definitions se describen en el
fichero tiles-defs.xml, y cada una de ellas sigue un layout o plantilla (contienen conjuntos de tiles).
A continuación se muestra el contenido del fichero “tiles-defs.xml”.
<tiles-definitions>
<definition name="princast.complexLayout"
path="/pages/tiles/layouts/ComplexLayout.jsp" >
<put name="head" value="../head.jsp" />
<put name="cabecera" value="../cabecera.jsp" />
<put name="barra_estado" value="../barra_estado.jsp" />
<put name="menu" value="../menu.jsp" />
<put name="barra_navegacion" value="../barra_navegacion.jsp" />
<put name="cuerpo" value="../cuerpo.jsp" />
<put name="pie_pagina" value="../pie_pagina.jsp" />
<put name="standards" value="../standards_compliant.jsp" />
</definition>
<definition name="princast.simpleLayout"
path="/pages/tiles/layouts/SimpleLayout.jsp">
<put name="head" value="../head.jsp" />
<put name="cabecera" value="../cabecera.jsp" />
<put name="cuerpo" value="../cuerpo.jsp" />
<put name="pie_pagina" value="../pie_pagina.jsp" />
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
146 de
296
<put name="standards" value="../standards_compliant.jsp" />
</definition>
<definition name="princast.menu" path="/pages/tiles/menu.jsp">
<put name="displayer" value="PrincastTabbedMenu"/>
</definition>
<definition name="princast.submenu" path="/pages/tiles/menu.jsp">
<put name="displayer" value="PrincastTabbedSubmenu"/>
</definition>
<definition name="princast.applicationLayout"
path="/pages/tiles/layouts/ApplicationLayout.jsp">
<put name="head" value="../head.jsp" />
<put name="cabecera" value="../cabecera.jsp" />
<put name="menu" value="../menu.jsp"/>
<put name="barra_navegacion" value="../barra_navegacion.jsp" />
<put name="cuerpo" value="../cuerpo.jsp" />
<put name="submenu" value="../submenu.jsp"/>
<put name="pie_pagina" value="../pie_pagina.jsp" />
<put name="standards" value="../standards_compliant.jsp" />
</definition>
<definition name="carrito.aviso_legal"
extends="princast.simpleLayout">
<put name="title" value="Aviso legal" />
<put name="cuerpo" value="../aviso_legal.jsp" />
</definition>
<definition name="carrito.error" extends="princast.simpleLayout">
<put name="title" value="Error" />
<put name="cuerpo" value="../error.jsp" />
<put name="pie_pagina" value="../pagina_vacia.jsp" />
</definition>
<definition name="carrito.viewperfil"
extends="princast.applicationLayout">
<put name="title" value="Información sobre el usuario" />
<put name="cuerpo" value="../cuerpo_perfil.jsp" />
</definition>
<definition name="carrito.listaprod"
extends="princast.applicationLayout">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
147 de
296
<put name="title" value="Lista de productos" />
<put name="cuerpo" value="../cuerpo_listaprod.jsp" />
</definition>
<definition name="carrito.buscarprod"
extends="princast.applicationLayout">
<put name="title" value="Buscador de productos" />
<put name="cuerpo" value="../cuerpo_buscarprod.jsp" />
</definition>
<definition name="carrito.detalleprod"
extends="princast.applicationLayout">
<put name="title" value="Detalle de producto" />
<put name="cuerpo" value="../cuerpo_detalleprod.jsp" />
</definition>
<definition name="carrito.viewcarrito"
extends="princast.applicationLayout">
<put name="title" value="Contenido del carrito" />
<put name="cuerpo" value="../cuerpo_carrito.jsp" />
</definition>
<definition name="carrito.confirmpedido"
extends="princast.applicationLayout">
<put name="title" value="Confirmar pedido" />
<put name="cuerpo" value="../cuerpo_confirm.jsp" />
<put name="calendar" value="../use_calendar.jsp" />
</definition>
<definition name="carrito.envio"
extends="princast.applicationLayout">
<put name="title" value="Datos envío" />
<put name="cuerpo" value="../cuerpo_envio.jsp" />
</definition>
<definition name="carrito.confirmado"
extends="princast.applicationLayout">
<put name="title" value="Pedido confirmado" />
<put name="cuerpo" value="../cuerpo_confirmado.jsp" />
</definition>
</tiles-definitions>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
148 de
296
En el atributo path se indica que plantilla o layout sigue la definition. En cada elemento put mediante
el atributo value se indica la página que se insertará dentro de la tile indicada en el atributo name.
Es posible especificar definitions que hereden de otras, de tal forma que solo se modifiquen las páginas
de cada una de las tiles que se deseen. Para ello se utiliza el atributo extends, como podemos ver por
ejemplo en la última definición que hereda de la princast.applicationLayout, y solo se diferencia
de esta en la tile: cuerpo.
En la siguiente imagen se muestra la ruta del fichero “WEB-INF/tiles-defs.xml”, donde se incluyen las
definiciones anteriores.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
149 de
296
48 Path del fichero tiles-defs.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
150 de
296
Las plantillas utilizadas en las definiciones anteriores se encuentran disponibles en pages/tiles/layouts,
y en la aplicación de ejemplo existen tres:
•
ComplexLayout.jsp. Layout que sigue el formato de las páginas. Esta es de la forma:
___________________________________
|<cabecera>
|
|__________________________________|
|<barra_navegacion>
|
|__________________________________|
|<barra_estado>
|
|__________________________________|
|<menu>|
|
|
|
|
|
|
<cuerpo>
|
|
|
|
|
|
|
|______ |___________________________|
|<pie_pagina>
|
|__________________________________|
El atributo head para envolver la etiqueta <head> del documento HTML hace más
sencillo extender un layout y, a su vez, poder emplear diferentes hojas de estilo.
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ page errorPage="/pages/errorEnJSP.jsp" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"
%>
<html:html locale="es" xhtml="true" lang="es">
<head>
<html:base />
<title>
<tiles:getAsString name="title" ignore="true"/> <bean:message key="welcome.title"/>
</title>
<tiles:insert attribute="head" ignore="true" />
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
151 de
296
</head>
<body>
<div id="contenedor">
<!-- Cabecera de la pagina -->
<tiles:insert attribute="cabecera" ignore="true" />
<!-- Barra de estado -->
<tiles:insert attribute="barra_estado" ignore="true" />
<!-- Barra de navegacion -->
<tiles:insert attribute="barra_navegacion" ignore="true" />
<!-- Menu de navegacion -->
<tiles:insert attribute="menu" ignore="true" />
<!-- Cuerpo principal de la página -->
<tiles:insert attribute="cuerpo" ignore="true" />
<!-- Pie de página -->
<tiles:insert attribute="pie_pagina" ignore="true" />
</div>
<tiles:insert attribute="standards" ignore="true" />
</body>
</html:html>
•
SimpleLayout.jsp. Layout más sencillo para mostrar, por ejemplo, paginas como las del aviso
legal.
____________________________________
|<cabecera>
|
|_________________________________ |
|
|
|
<cuerpo>
|
|
|
|__________________________________|
|<pie_pagina>
|
|__________________________________|
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
152 de
296
<%@ page errorPage="/pages/errorEnJSP.jsp" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"
%>
<html:html locale="es" xhtml="true" lang="es">
<head>
<html:base />
<title>
<tiles:getAsString name="title" ignore="true"/> <bean:message key="welcome.title"/>
</title>
<tiles:insert attribute="head" ignore="true" />
</head>
<body>
<div id="contenedor">
<!-- Cabecera de la pagina -->
<tiles:insert attribute="cabecera" ignore="true" />
<!-- Cuerpo de la pagina -->
<tiles:insert attribute="cuerpo" ignore="true"/>
<!-- Pie de página -->
<tiles:insert attribute="pie_pagina" ignore="true" />
</div>
<tiles:insert attribute="standards" ignore="true" />
</body>
</html:html>
•
ApplicationLayout.jsp. Layout para aplicaciones.
______________________________________
| <cabecera>
|
|_____________________________________|
| <barra_estado>
|
|_____________________________________|
|<barra_navegacion>
|
|_____________________________________|
| <cuerpo_pagina>
|
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
153 de
296
| _____________________________
|
| | <tabs>
|
|
| |_____________________________|
|
| |<cuerpo>
|
|
| |
|
|
| |
|
|
| |
|
|
| |_____________________________|
|
|_____________________________________|
|<pie_pagina>
|
|_____________________________________|
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ page errorPage="/pages/errorEnJSP.jsp" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"
%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"
%>
<html:html locale="es" xhtml="true" lang="es">
<head>
<html:base />
<title>
<tiles:getAsString name="title" ignore="true"/> <bean:message key="welcome.title"/>
</title>
<tiles:insert attribute="head" ignore="true" />
</head>
<body>
<div id="contenedor">
<tiles:insert attribute="cabecera" ignore="true"/>
<!-- Cuerpo de la pagina -->
<a name="contenido"></a>
<div id="cuerpo_pagina">
<div id="contenido_cuerpo">
<!-- Menu de navegacion (principal) -->
<tiles:insert attribute="menu" ignore="true" />
<!-- Submenu de navegacion -->
<tiles:insert attribute="submenu" ignore="true" />
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
154 de
296
<div id="pie_submenu"></div>
<!-- Barra de navegacion -->
<tiles:insert attribute="barra_navegacion" ignore="true" />
<div id="contenido_tab">
<!-- Cuerpo del tab -->
<div id="cuerpo_tab">
<!-- Cuerpo principal de la página -->
<tiles:insert attribute="cuerpo" ignore="true" />
</div>
</div> <!-- Del contenido del cuerpo -->
</div> <!-- del cuerpo -->
<!-- Pie de página -->
<tiles:insert attribute="pie_pagina" ignore="true" />
</div>
<tiles:insert attribute="standards" ignore="true" />
</body>
</html:html>
Para más información sobre tiles consultar el manual de referencia disponible en la dirección
http://struts.apache.org/1.x/struts-tiles/.
9.3. Pantalla de error
Existen dos páginas de error llamadas todas ellas error.jsp.
•
•
La alojada bajo el directorio de tiles de la aplicación, tiene el look & feel de las tiles vistas
anteriormente.
La que esta bajo el directorio pages tiene un aspecto más general y se usará cuando no se desee
redireccionar a una tile.
La aplicación redirigirá el flujo hacia la página cuando ocurra una excepción global no tratada en
ningún objeto Action. El mapeo de las excepciones globales hacia esta página se realiza en el
descriptor struts-config.xml, mediante la etiqueta:
<global-exceptions>
<exception key="global.princastexception"
type="java.lang.Exception"
path="carrito.error"
handler="org.apache.struts.action.ExceptionHandler" />
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
155 de
296
</global-exceptions>
El path carrito.error que aparece es una definición de Tiles que incluye a la página error.jsp.
<definition name="carrito.error" extends="princast.simpleLayout">
<put name="title" value="Error" />
<put name="cuerpo" value="../error.jsp" />
<put name="pie_pagina" value="../pagina_vacia.jsp" />
</definition>
Dependiendo del tratamiento interno que se le dé a la excepción en su construcción, es posible obtener
la traza completa (stack trace) de la excepción que ha originado la visualización de la página de
errores. Como ejemplo se ha introducido un error en una consulta con la base de datos MySQL local
contra la que la aplicación de ejemplo trabaja. El resultado es el siguiente:
49 Ejemplo de traza del error simulado en la aplicación de ejemplo
Además se han añadido páginas de error para los errores de solicitud de páginas HTML, más comunes,
como por ejemplo error 403 o 404. Se incluye también una pantalla de error para las páginas JSP que
oculta los errores al usuario, pero el desarrollador los puede ver en un comentario HTML, en el código
fuente de la página.
9.4. Tablas de paginación
Para la creación de tablas se hace uso de la librería Display Tag (http://displaytag.sourceforge.net/).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
156 de
296
Ilustración 50: http://displaytag.sourceforge.net/1.2/
Esta librería construye una tabla con funcionalidades de paginación, ordenación, etc. a partir de una
colección de datos. Display Tag ofrece un conjunto de etiquetas personalizadas (jsp custom tags) que
automáticamente se encargan de renderizar la vista. Los datos que mostrará la tabla se buscan en una
colección de objetos que puede estar en cualquiera de los ámbitos JSP:
•
•
•
•
pageScope. En el ámbito de página.
requestScope. En el ámbito de request (ámbito por defecto).
sessionScope. En el ámbito de sesión.
applicationScope. En el ámbito de aplicación.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
157 de
296
Los tipos de colecciones que soporta son:
•
•
•
•
•
•
•
Collection
Enumeration
Map (los valores se muestran en una fila)
Dictionary (los valores se muestran en una fila)
Array
Iterator
Object con un método iterator()
Cualquier otro objeto se mostrará en una única fila.
A continuación se muestra un ejemplo de utilización extraído de la aplicación de ejemplo (sampleapp):
...
<%@ taglib uri="http://displaytag.sf.net" prefix="display" %>
...
<display:table
name="listaProductos"
id="listProd"
export="false"
requestURI="../../../action/viewlistaproducto"
summary="Listado de productos">
<display:column titleKey="productos.column.name"
sortProperty="nombre" sortable="true" >
<bean:define id="nombreProducto" name="listProd"
property="name" toScope="page"/>
<html:link action="/viewdetalleproducto" paramId="id"
paramName="listProd" paramProperty="id"
title="<%=\"Visualice el detalle de \" + nombreProducto%>">
<bean:write name="listProd" property="name" />
</html:link>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
158 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
</display:column>
<display:column titleKey="productos.column.description"
property="description" />
<display:column titleKey="productos.column.basePrice"
sortProperty="precio" property="basePrice" sortable="true"
headerClass="sortable"/>
<display:column>
<bean:define id="url" name="listProd"
property="smallImageURL" />
<bean:define id="nombre" name="listProd"
property="name" toScope="page"/>
<html:img styleClass="imagen_producto"
src="<%=url.toString()%>"
alt="<%=\"Imágen de \" + nombre%>"/>
</display:column>
</display:table>
Se utiliza un atributo registrado en la sesión con la clave “listaProductos”, que contiene una lista de
objetos de tipo ProductoVO (es un ValueObject)., que tienen una serie de propiedades que nos
permitirán recuperar la información y mostrarlas en las columnas de la tabla, como podemos ver en el
ejemplo anterior con el atributo “property”.
El atributo titleKey nos permite asignar un nombre a la columna. En este caso se está utilizando la
clave
"productos.column.name",
que
se
puede
encontrar
en
el
fichero
“ApplicationResources.properties” (comentado ya en los apartados anteriores), y que contiene el valor
“Nombre”.
A continuación se muestras los métodos setter de la clase ProductoVO, disponible en la aplicación de
ejemplo.
public class ProductoVO extends BasePrincastVO {
private static final long serialVersionUID = 3257006553293731123L;
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
159 de
296
...
public int getId() {
return id;
}
...
public String getDescription() {
return description;
}
...
public String getName() {
return name;
}
...
public String getSmallImageURL() {
return smallImageURL;
}
...
public double getBasePrice() {
return basePrice;
}
}
En cada iteración por la lista se tiene acceso al elemento actual mediante la referencia “listProd”
especificada con el atributo “id” de la etiqueta “display:table”.
Para cada registro se mostrarán las columnas:
•
•
•
•
Nombre, que además será un enlace a la ficha detalle del producto.
Descripción
Precio
Imagen del producto
El usuario puede ordenar la tabla por nombre de producto o por precio, con sólo pulsar sobre el
nombre de la columna (especificado mediante el atributo “sortable” de la “display:columna”).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
160 de
296
51 Ejemplo de listado de productos de la aplicación de ejemplo
Se puede especificar que el contenido de determinadas columnas vaya a una acción (Action). En este
caso se ha hecho con la columna nombre del producto. También es necesario indicarle que Action es la
que muestra la tabla para que funcione la ordenación.
Los estilos por defecto que se utilizarán en la tabla están contenidos en la hoja de estilos
displaytag.css. También pueden personalizarse los estilos mediante los atributos headerClass y
styleClass, como se puede ver en el ejemplo anterior.
Otro recurso importante para la generación de tablas con Display Tag es el fichero de propiedades
displaytag.properties, almacenado en la carpeta resources.
52 Path del fichero displaytag.properties
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
161 de
296
Este fichero indicará al motor de generación de las tablas de Display Tag diversos parámetros de
configuración y literales de salida de la tabla. También es posible indicar desde este fichero los
nombres de los estilos CSS que tomarán los elementos de la tabla.
Para más información consultar el propio fichero displaytag.properties en el proyecto Display Tag en
http://displaytag.sourceforge.net/displaytag.pdf).
9.5. Creación de menús
9.5.1. Información general
La creación de los menús para las aplicaciones desarrolladas a partir de openFWPA se realizará a
través del plugin de Struts denominado Struts-menu. Puede consultarse toda la información referente al
proyecto Struts-menu en http://struts-menu.sourceforge.net/.
Struts-menu está formado por una librería de clases, una biblioteca de tags y algunos recursos
suplementarios, que permiten crear menús en las páginas Web de forma declarativa (mediante un
descriptor XML).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
162 de
296
53 http://struts-menu.sourceforge.net/
Puede integrarse con el sistema de seguridad gestionado por los contenedores Web (usuarios y roles), y
admite la posibilidad de personalizar la presentación de los menús a través de objetos llamados
Displayers. La release 2.2 no se integra con Tiles, aunque esto no significa que no se puedan usar
conjuntamente Tiles y Struts-menu, como se muestra en las aplicaciones de ejemplo. En la
documentación ofrecida por la versión 2.2 de Struts-menu se apunta como una posible extensión futura
la integración con Tiles, de forma que se puedan leer definiciones de menús desde el fichero tilesconfig.xml. Esto reduciría ligeramente la complejidad del mantenimiento, al no tener entonces que
gestionar el fichero descriptor de strusmenu, denominado menu-config.xml
En cuanto a seguridad, está totalmente integrado con el sistema de autenticación/autorización en el
contenedor Web. Se pueden indicar los roles a los que se les permite el acceso a las opciones del
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
163 de
296
menú. El Framework de generación del menú no presentará en la vista las opciones del menú a las que
un usuario no tenga acceso (según el rol de este usuario). Esta es una estrategia recomendable a la hora
de generar menús dinámicos en relación a los permisos de usuario.
9.5.2. Definir los menús
La definición de los menús que se renderizarán en las aplicaciones desarrolladas se realizará a través
de un fichero descriptor XML “menu-config.xml”, que seguirá estará disponible en el directorio
“WEB-INF”, tal y como podemos ver en la siguiente imagen:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
164 de
296
54 Path del fichero menu-config.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
165 de
296
A continuación se muestra el contenido del fichero “menu-config.xml” incluido en la aplicación de
ejemplo “sampleapp”.
<?xml version="1.0" encoding="UTF-8" ?>
<MenuConfig>
<Displayers>
<Displayer
name="PrincastTabbedMenu"
type="es.princast.framework.web.view.menu.PrincastTabbedMenuDisplayer"/>
<Displayer
name="PrincastTabbedSubmenu"
type="es.princast.framework.web.view.menu.PrincastTabbedSubmenuDisplayer"/>
</Displayers>
<Menus>
<Menu name="MenuIntegrado" title="Menu integrado"
action="/viewperfil">
<Item name="miPerfil" title="Mi perfil" action="/viewperfil"/>
<Item name="listaProductos" title="Lista productos"
roles="Citizen,REGISTERED" action="/viewlistaproducto"/>
<Item name="buscarProductos" title="Buscar productos"
roles="Citizen,REGISTERED" action="/busquedaProductos"/>
<Item name="verCarrito" title="Ver carrito"
roles="Citizen,REGISTERED" action="/viewcarrito"/>
</Menu>
<Menu
name="MenuMiPerfil"
action="/viewperfil"></Menu>
title="Mi
perfil"
<Menu name="MenuListaProductos" title="Lista
productos" roles="Citizen,REGISTERED"
action="/viewlistaproducto"></Menu>
<Menu name="MenuBuscarProductos" title="Buscar productos"
roles="Citizen,REGISTERED" action="/busquedaProductos"></Menu>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
166 de
296
<Menu name="MenuVerCarrito" title="Ver carrito"
roles="Citizen,REGISTERED" action="/viewcarrito"></Menu>
</Menus>
</MenuConfig>
Se pueden observar dos zonas de elementos principales: los displayers y los menus.
En la sección Displayers se incluyen los diferentes tipos de renderización que podríamos usar para
presentar los menús en pantalla. La versión 2.2 de Struts Menu provee de 8 tipos diferentes, cada una
de ellas ofreciendo sus particularidades en cuanto a visualización y recursos exigidos, como pueden ser
hojas de estilos, ficheros properties o ficheros de scripts js para la configuración de los menús.
<Displayers>
<Displayer name="DropDown"
type="net.sf.navigator.displayer.DropDownMenuDisplayer"/>
<Displayer name="Simple"
type="net.sf.navigator.displayer.SimpleMenuDisplayer"/>
<Displayer name="CoolMenu"
type="net.sf.navigator.displayer.CoolMenuDisplayer"/>
<Displayer name="CoolMenu4"
type="net.sf.navigator.displayer.CoolMenuDisplayer4"/>
<Displayer name="MenuForm"
type="net.sf.navigator.example.PermissionsFormMenuDisplayer"/>
<Displayer name="ListMenu"
type="net.sf.navigator.displayer.ListMenuDisplayer"/>
<Displayer name="TabbedMenu"
type="net.sf.navigator.displayer.TabbedMenuDisplayer"/>
<Displayer name="Velocity"
type="net.sf.navigator.displayer.VelocityMenuDisplayer"/>
<Displayer name="PrincastTabbedMenu"
type="es.princast.framework.web.view.menu.PrincastTabbedMenuDisplayer
"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
167 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<Displayer name="PrincastTabbedSubmenu"
type="es.princast.framework.web.view.menu.PrincastTabbedSubmenuDispla
yer"/>
<Displayer name="Velocity"
type="net.sf.navigator.displayer.VelocityMenuDisplayer"/>
</Displayers>
Además de los 8 Displayers incluidos en la distribución de Struts-menu, openFWPA proporciona dos
displayers más: PrincastTabbedMenuDisplayer y PrincastTabbedSubmenuDisplayer, que se
explicarán con más detalle en el apartado siguiente.
En la sección Menus se definirán los menús realmente. Se creará un elemento Menu por cada menú
que se necesite mostrar. Cada menú puede tener una serie de opciones, los Item. A su vez cada item
podría tener subitems, y así sucesivamente, definiendo el árbol del menú personalizado, como se
muestra en el siguiente ejemplo:
<Menu name="MenuUnoPB" title="Ejemplo de uso Struts-menu">
<Item name="GrupoINI" title="Opciones comunes">
<Item name="enlace1" title="Ir al Home" page="/Welcome.do"
toolTip="Ir a la página inicial de la aplicación" />
<Item name="enlace2" title="Loging contra Base de Datos"
page="/LogonBD.do" toolTip="Logearse a través de BD" />
</Item>
</Menu>
9.5.3. Displayers específicos de openFWPA
Como se indicaba en el apartado anterior se han incluido en openFWPA dos nuevos Displayers:
• PrincastTabbedMenuDisplayer
• PrincastTabbed-SubmenuDisplayer
El objetivo de estos nuevos displayers es doble: por un lado, se pretende disponer de un menú que se
integre/adapte fácilmente en el nuevo L&F de la aplicación desarrollada con openFWPA, y por otro, el
objetivo es eliminar la necesidad de utilizar tecnologías de cliente como JavaScript y Cookies. Estos
dos displayers deben utilizarse conjuntamente para renderizar un único menú.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
168 de
296
PrincastTabbedMenuDisplayer. Se utilizará para generar el código HTML correspondiente al
menú de primer nivel (en forma de “tabs”).
PrincastTabbedSubmenuDisplayer. Se utilizará para generar el código del submenu (en forma
de lista horizontal de botones).
El displayer de openFWPA (PrincastMenuDisplayer) únicamente soporta un nivel de anidamiento de
menús.
Para que el código HTML generado sea compatible con el estándar XHTML, los caracteres '&' de las
URLs deben sustituirse por la entidad XML &.
A continuación se muestra una captura de pantalla de la aplicación de ejemplo del carrito (sampleapp),
y produce la siguiente vista del menú, en caso de que se muestren todos los menús y en el orden.
55 Ejemplo de menú en la aplicación de ejemplo sampleapp
9.5.4. Enlaces en los menús
El valor que los enlaces del menú pueden adquirir se determina mediante alguno de los siguientes 4
atributos (para los tag <Item> y <Menu>) y con la prioridad indicada:
•
location: página JSP o URL
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
169 de
296
page: página JSP.
forward: nombre de algún elemento Forward de Struts (definido en struts-config.xml)
action: nombre de algún elemento Action de Struts (definido en struts-config.xml)
Como norma general, se establecerá el uso de action de forma que Struts tome el control de todas las
peticiones de página, o forward en todo caso (por ejemplo para enlazar elementos global-forward de
Struts).
Se “prohíbe” el uso de location o page para llamar directamente a páginas JSP. Es estrictamente
obligatorio seguir el ciclo de petición de Struts, dado que openFWPA instrumentalizará todas las
peticiones para ofrecer información de ayuda, control y auditoría de la aplicación en tiempo real a
técnicos de sistemas y desarrolladores. Si Struts no toma el control de la petición, los resultados no
responderían a lo que realmente se espera, y serían engañosos para la toma de decisiones (memoria
disponible, tiempos de respuesta, sobrecarga de la aplicación, etc).
Para más información sobre enlaces en los menús, dirigirse a la distribución de Struts-menu 2.0
(versión 2.3) y estudiar el ejemplo de menu-config.xml que provee, donde se podrá ver como se
emplean las cuatro posibilidades anteriores.
9.5.5. Integración de Struts-menu con una aplicación Struts
Los pasos necesarios para integrar strus-menu en una aplicación Struts son:
•
Añadir la librería struts-menu en el pom.xml del proyecto. En este caso, como podemos ver en
el código de ejemplo anterior, ya se ha incluido en el “core” de openFWPA, por lo que no
sería necesario incluirla nuevamente.
<dependency>
<groupId>struts-menu</groupId>
<artifactId>struts-menu</artifactId>
<version>2.4.3</version>
<exclusions>
<exclusion>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</exclusion>
<exclusion>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
</exclusion>
</exclusions>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
170 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
</dependency>
•
Añadir el plug-in de struts-menu al fichero descriptor struts-config.xml
<plug-in className="net.sf.navigator.menu.MenuPlugIn">
<set-property
property="menuConfig"
value="/WEB-INF/menuconfig.xml"/>
</plug-in>
•
Crear el descriptor XML de las definiciones de menús, menu-config.xml y posicionarlo bajo el
directorio /WEB-INF. Se puede tomar como referencia la aplicación ejemplo de Stuts-menu o
cualquiera de los descriptores XML del menú de las aplicaciones ejemplo de openFWPA
(sampleapp y blankapp).
•
En las páginas donde se vayan a crear menús, añadir la declaración de la librería de tags.
<%@ taglib uri="http://struts-menu.sf.net/tag" prefix="menu" %>
•
Añadir el código para renderizar el menú en la página JSP. Ejemplo página
“pages/tiles/menu.jsp”:
<menu:useMenuDisplayer name='PrincastTabbedMenu'
bundle="org.apache.struts.action.MESSAGE" permissions="rolesAdapter">
<menu:displayMenu name="MenuIntegrado"/>
<menu:displayMenu name="MenuMiPerfil"/>
<menu:displayMenu name="MenuListaProductos"/>
<menu:displayMenu name="MenuBuscarProductos"/>
<menu:displayMenu name="MenuVerCarrito"/>
</menu:useMenuDisplayer>
•
Añadir el código para renderizar los submenús. Aunque no haya submenús, esta definición
debería realizarse igualmente con el objetivo de facilitar la adición de entradas de submenú.
Este código, se añadirá a la página JSP en el lugar donde se desea que aparezca el submenú. Es
importante que las entradas declaradas para el menú y el submenú sean las mismas. Ejemplo
página “pages/tiles/submenu.jsp”:
<menu:useMenuDisplayer name='PrincastTabbedSubmenu'
bundle="org.apache.struts.action.MESSAGE" permissions="rolesAdapter">
<menu:displayMenu name="MenuIntegrado"/>
<menu:displayMenu name="MenuMiPerfil"/>
<menu:displayMenu name="MenuListaProductos"/>
<menu:displayMenu name="MenuVerCarrito"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
171 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
</menu:useMenuDisplayer>
•
Copiar la biblioteca de tags struts-menu.tld en “/WEB-INF/tld”, o struts-menu-el.tld si se
pretende usar Lenguaje de Expresiones (EL).
9.5.6. La librería de tags struts-menu-el.tld
Se utilizará la versión EL de la librería de tags en las aplicaciones construidas sobre openFWPA, con el
objetivo de utilizar lenguaje de expresiones para construir enlaces con parámetros dinámicos que
puedan ser manejados por el proceso de petición de páginas.
9.5.7. Uso de la librería de tags en la página menu.jsp
En las aplicaciones ejemplo que se incluyen en openFWPA únicamente se maneja el menú en las
páginas “menu.jsp” y “submenu.jsp”. Esto tiene que ver con el hecho de uso de Tiles como motor de
renderizado de la vista (ver la sección dedicada a este punto) y la existencia de un menú único para
todas las posibles vistas. Ejemplo página “pages/tiles/menu.jsp”:
<%@
<%@
%>
<%@
%>
<%@
%>
<%@
%>
<%@
<%@
page errorPage="/pages/errorEnJSP.jsp" %>
taglib uri="http://jakarta.apache.org/struts/tags-bean"
taglib
uri="http://jakarta.apache.org/struts/tags-html"
prefix="bean"
prefix="html"
taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic"
taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"
taglib uri="http://struts-menu.sf.net/tag" prefix="menu" %>
taglib uri="/WEB-INF/tld/princast-date.tld" prefix="date" %>
<html:xhtml />
<!-- GENERACION DE MENU Strus-menu 2.0 (version 3) -->
<menu:useMenuDisplayer name='PrincastTabbedSubmenu'
bundle="org.apache.struts.action.MESSAGE" permissions="rolesAdapter">
<menu:displayMenu name="MenuIntegrado"/>
<menu:displayMenu name="MenuMiPerfil"/>
<menu:displayMenu name="MenuListaProductos"/>
<menu:displayMenu name="MenuVerCarrito"/>
</menu:useMenuDisplayer>
<div id="fecha">
<date:date />
</div>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
172 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<!-- FIN GENERACION DE MENU Strus-menu 2.0 (version 3) -->
En el script se puede observar lo siguiente:
•
•
•
Uso del TLD struts-menu-el.tld
Uso del displayer TabbedPrincastMenu
Renderizado
de
6
menús:
MeniIntegrado,
MenuPerfil,
MenuListaProductos,
MenuBuscarProductos, MenuVerCarrito. Todos ellos se han definido previamente en el
fichero XML menu-config.xml.
Además de la página menú.jsp, se debe definir la página submenu.jsp para renderizar los menús de
segundo nivel. Esta página, será similar a la página menú.jsp, con la diferencia del displayer a utilizar.
<%@ page errorPage="/pages/errorEnJSP.jsp" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"
%>
<%@ taglib uri="http://struts-menu.sf.net/tag" prefix="menu" %>
<html:xhtml />
<!-- GENERACION DE MENU Strus-menu 2.0 (version 3) -->
<menu:useMenuDisplayer name='PrincastTabbedMenu'
bundle="org.apache.struts.action.MESSAGE" permissions="rolesAdapter">
<menu:displayMenu name="MenuIntegrado"/>
<menu:displayMenu name="MenuMiPerfil"/>
<menu:displayMenu name="MenuListaProductos"/>
<menu:displayMenu name="MenuBuscarProductos"/>
<menu:displayMenu name="MenuVerCarrito"/>
</menu:useMenuDisplayer>
<!-- FIN GENERACION DE MENU Strus-menu 2.0 (version 3) -->
9.5.8. Recursos utilizados por el displayer PrincastTabbedMenu
Este displayer utiliza dos hojas de estilo (general.css y tabs.css). Los PrincastMenuDisplayers son
objetos configurables (es decir, implementan el interface ConfigurationListener) y, por lo tanto,
pueden ser configurados utilizando el sistema de configuración de openFWPA.
El nombre del contexto de configuración utilizado por los displayers incluidos en openFWPA, es
“MENU.CONTEXT”. Los atributos configurables de los displayers incluidos se definen en la clase
MenuConfigurationKeys, disponible en el core de openFWPA, como se puede ver a continuación:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
173 de
296
/**
* Constante que indica el nombre del parámetro GET por el que se especifica
* el nombre del menu activo
*/
public static final String MENU_ITEM_GET_PARAM = "MENU.ITEM.GET.PARAM";
/**
* Constante que indica el nombre del parámetro GET por el que se especifica
* el nombre del menu activo
*/
public static String SUBMENU_ITEM_GET_PARAM = "SUBMENU.ITEM.GET.PARAM";
/**
* Constante que indica el nombre del identificador CSS que da estilo a la
* lista del menu
*/
public static String CSS_MENU_UL_ID = "CSS.MENU.UL.ID";
/**
* Constante que indica el nombre de la clase CSS que da estilo al item
* activo del menu
*/
public static String CSS_MENU_ACTIVE_CLASS = "CSS.MENU.ACTIVE.CLASS";
/**
* Constante que indica el nombre de la clase CSS que da estilo al Link del
* item activo del menu
*/
public
static
String
CSS_MENU_CURRENT_LINK_CLASS=
"CSS.MENU.CURRENT.LINK.CLASS";
/**
* Constante que indica el nombre del identificador CSS que da estilo a todo
* el DIV donde se encierra el menu
*/
public static String CSS_MENU_DIV_ID = "CSS.MENU.DIV.ID";
/**
* Constante que indica el nombre del identificador CSS que da estilo a la
* lista del submenu
*/
public static String CSS_SUBMENU_UL_ID = "CSS.SUBMENU.UL.ID";
/**
* Constante que indica el nombre de la clase CSS que da estilo al item
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
174 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
* activo del submenu
*/
public static String CSS_SUBMENU_ACTIVE_CLASS = "CSS.SUBMENU.ACTIVE.CLASS";
/**
* Constante que indica el nombre de la clase CSS que da estilo al Link del
* item activo del submenu
*/
public
static
String
CSS_SUBMENU_CURRENT_LINK_CLASS=
"CSS.SUBMENU.CURRENT.LINK.CLASS";
/**
* Constante que indica el nombre del identificador CSS que da estilo al DIV
* donde se encierra el submenu
*/
public static String CSS_SUBMENU_DIV_ID = "CSS.SUBMENU.DIV.ID";
/**
* Constante que indica el nombre del menu que se mostrará por defecto
*/
public static String DEFAULT_MENU = "DEFAULT.MENU";
/**
* Constante que indica el nombre del submenu que se mostrará por defecto
* (si procede)
*/
public static String DEFAULT_SUBMENU = "DEFAULT.SUBMENU";
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
175 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
9.5.9. Forwards a entradas de menú
Si se utilizan los displayers proporcionados por el openFWPA (PrincastTabbedMenuDisplayer y
subclases), es posible realizar “forwards” a entradas de menú. Si un forward de Struts, ya sea global, o
definido en el mapping de una Action tiene como “path” el nombre de una entrada de menú, el
Request Processor será capaz de redireccionar al usuario al recurso (página, action, etc) asociado con
dicha entrada. Las definiciones siguientes pertenecen al fichero menu-config.xml:
<Menu name="MenuIntegrado" title="Menu integrado" action="/login">
<Item name="miPerfil" title="Mi perfil" action="/viewperfil"/>
<Item name="listaProductos" title="Lista productos"
roles="Citizen,REGISTERED" action="/viewlistaproducto"/>
<Item name="listaProductosPDF" title="Lista productos en PDF"
roles="Citizen,REGISTERED" action="/viewlistaproductopdf"/>
<Item name="verCarrito" title="Ver carrito"
roles="Citizen,REGISTERED" action="/viewcarrito"/>
<Item name="salir" title="Salir" action="/logout"/>
</Menu>
<Menu name="MenuVerCarrito" title="Ver carrito" roles="Citizen,REGISTERED"
action="/viewcarrito">
</Menu>
Definir un forward a una entrada de menú es tan sencillo como sigue:
<action path="/carrito"
type="es.princast.framework.carrito.web.actions.CarritoActions"
scope="request"
input="carrito.viewcarrito" validate="false" parameter="method">
<forward name="success" path="MenuVerCarrito" redirect="true" />
</action>
También es posible que un forward realice una redirección a una entrada de submenú (menú de
segundo nivel), para ello, el path del forward deberá estar compuesto del nombre de la entrada de
primer nivel y del nombre de la entrada del submenu separados por el carácter “.” (punto):
•
<entrada de menú>.<entrada de submenu>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
176 de
296
Un ejemplo es la siguiente definición:
<action path="/carrito"
type="es.princast.framework.carrito.web.actions.CarritoActions"
scope="request"
input="carrito.viewcarrito" validate="false" parameter="method">
<forward name="success" path="MenuIntegrado.verCarrito"
redirect="true" />
</action>
Para poder realizar forwards a entradas de menú, es necesario utilizar (definiéndolo como
“controller” en el fichero struts-config.xml) el request processor: PrincastTilesRequestProcessor.
<controller
processorClass="es.princast.framework.web.action.PrincastTilesRequestProces
sor" />
9.5.10. Enlaces con parámetros dinámicos
Es posible aumentar las posibilidades de los enlaces generados por struts-menu, añadiendo parámetros
por querystring. Además se puede utilizar el lenguaje EL (Lenguaje de Expresiones) de JSTL para
acceder a datos más cómodamente, como por ejemplo Beans almacenados en la sesión.
Como ejemplo, sirva el siguiente scriptlet, donde se genera un Item de menú cuyo enlace dirigirá la
aplicación hacia el Action de struts infoUsuario definido en struts-config.xml, y le añadirá un
parámetro idUsu cuyo valor será tomado de un Bean llamado user (posiblemente almacenado en el
ámbito de session) que tiene una propiedad llamada idusuario. Como consecuencia de todo esto,
finalmente se genera una URL que pudiera tener la siguiente forma:
http://localhost:8082/plantillaStruts/infoUsuario.do?idUsu=1234
<Item name="seeThisUser"
title="Ver usuario conectado"
toolTip="Editar la información del usuario actualmente conectado"
action="infoUsuario?idUsu=${user.idusuario}" />
9.6. Internacionalización
OpenFWPA tiene soporte para la internacionalización de aplicaciones. El fichero
ApplicationResources.properties contiene los mensajes del idioma por defecto. El fichero
ApplicationResources_xx.properties contendrá los mismos mensajes pero en el idioma cuyo código
ISO sea xx (por ejemplo ApplicationResources_en.properties para el inglés).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Para
más
información
sobre
los
códigos
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Locale.html.
de
idioma
Página
177 de
296
consultar
Para mostrar los mensajes en la vista puede utilizarse el tag <bean:message
key=”clave.del.mensaje”>, donde clave.del.mensaje es la clave en el fichero properties del mensaje a
mostrar.
9.7. View Helpers, View Adapters, Acciones
Se encargan de realizar operaciones sobre la capa de lógica de negocio y devuelven los resultados a la
vista. La mejor forma de realizar la comunicación entre estas dos capas es la utilización del patrón de
diseño Data Transfer Object, también llamado Value Object.
Habitualmente, la vista recibirá la información del modelo en forma de Value Objects, pero no
conocerá como se han creado. Para ello se recomienda utilizar el patrón Business Interface. Este patrón
consiste en escribir un interfaz con los métodos de negocio de las entidades (en la capa de negocio), y
posee la ventaja de:
•
•
Independizar las operaciones de su implementación
Permitir la reutilización de las operaciones entre distintas presentaciones (interfaz Web, interfaz
Web services, etc).
Todos los Value Objects han de implementar la interfaz PrincastValueObject.
Un tipo muy habitual de acciones son aquellas que proveerán a la vista de un conjunto de objetos
(Value Objects) que serán mostrados en forma de lista. OpenFWPA, contiene una clase de ayuda
(ListViewHelper) para facilitar esta tarea. La clase ListViewHelper permite obtener listados y ponerlos
a disposición de la aplicación a través de la session (HttpSession). Para obtener el listado a mostrar, se
utilizan proveedores de contenido (interface ListContentProvider). Un proveedor de contenido es
cualquier objeto (un DAO, un Business Delegate, etc) que pueda proporcionar una lista de Value
Objects a la vista.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
178 de
296
56 List View Helper
En el diagrama anterior “List View Helper” se puede ver la estructura de las clases explicadas en el
párrafo anterior. Existen dos formas de utilizar la clase ListViewHelper:
•
Dinámica. Es más adecuada cuando se espera que el ListViewHelper vaya a tener un elevado
nivel de demanda. Esta forma de uso requiere crear una instancia de la clase ListViewHelper
pasando, al constructor, el ListContentProvider que se va a utilizar cada vez que se le solicite
un listado. Una vez creada la instancia se podrá utilizar siempre ese objeto.
ListViewHelper helper = new ListViewHelper(new ExampleDAO());
//El helper se puede meter en la session para tenerlo disponible.
request.getSession(true).setAttribute(“listHelper”, helper);
helper.loadDataInSession(“listado”, request, null);
Para ejecutar la carga del listado, se utilizará el método loadDataInSession(), que recibe como
parámetros: el nombre del atributo de la session donde se dejará el listado, el objeto request del
cual se puede obtener la instancia de la session (HttpSession) donde guardará la lista y un array
de objetos que contiene los parámetros que puedan ser necesarios para obtener el listado.
•
Estática. Esta forma es similar a la anterior. No es necesario crear una instancia de la clase
ListViewHelper, basta con llamar a la versión estática (static) del método loadDataInSession(),
pasándole los mismos parámetros que a la versión dinámica más la instancia del
ListContetnProvider que se utilizará para generar la lista.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
ListViewHelper.loadDataInSession(new
null);
Estado
Definitivo
Documento
Manual de Configuración
ExampleDAO(),
“listado”,
Página
179 de
296
request,
El código de los dos ejemplos es equivalente.
9.8. Accesibilidad
Un aspecto que se ha tenido en cuenta en openFWPA es el de la accesibilidad. Podemos definir la
accesibilidad como la posibilidad de que un sitio o servicio Web pueda ser visitado y utilizado de
forma satisfactoria por el mayor número posible de personas, independientemente de sus propias
limitaciones o de las derivadas de su entorno.
Para tener en cuenta la accesibilidad en openFWPA se han tenido en cuenta las ‘Directrices de
Accesibilidad para el Contenido Web 1.0’. (WCAG 1.0) [http://www.w3.org/TR/WCAG10/].
Las Pautas de Accesibilidad al Contenido Web están formadas por 14 pautas generales divididas en un
total de 65 puntos de verificación. Cada punto de verificación tiene asignada una prioridad (1, 2 o 3)
que indica cómo afecta a la accesibilidad de un sitio Web si dicho punto de verificación no se cumple.
Existen tres niveles de adecuación (A, AA y AAA) que indican el grado de cumplimiento de los puntos
de verificación por un determinado sitio Web.
Tanto en el nuevo modelo de etiquetas para el diseño de interfaces de usuario como en las aplicaciones
distribuidas en openFWPA (appBlank, sampleApp), se ha intentado satisfacer un nivel de adecuación
AA [http://www.w3.org/WAI/WCAG1AA-Conformance].
El punto de verificación 3.2 de la prioridad 2 de las Directrices de Accesibilidad para el Contenido
Web 1.0 (WCAG 1.0) [http://www.w3.org/TR/WCAG10/] indica que se deben desarrollar documentos
que estén validados por las gramáticas formales publicadas.
Todo el código de las aplicaciones distribuidas con la openFWPA están escritos siguiendo una
gramática formal (identificados mediante !DOCTYPE) y validados con el servicio de validación
[http://validator.w3.org/] proporcionado por el W3C [http://www.w3.org/]. En el desarrollo de
cualquier aplicación desarrollada utilizando openFWPA, se recomienda validar las páginas JSP con
alguna herramienta disponible que verifique que la gramática formal utilizada es correcta.
57 Servicio de validación de gramáticas
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
180 de
296
Las aplicaciones distribuidas con openFWPA se han desarrollado utilizando la gramática XHTML 1.0
con el DTD "Strict". Esta gramática da prioridad a la estructura frente a la presentación. Por lo tanto
todo lo referente a la maquetación y presentación se debe incluir en las hojas de estilo.
En openFWPA todas las hojas de estilos propias han sido validadas con el servicio de validación de
CSS [http://jigsaw.w3.org/css-validator/] proporcionado por el W3C [http://www.w3.org/]. De la
misma forma que se recomienda validar la gramática utilizada, también se recomienda validar las
hojas de estilo.
58 Servicio de validación de hojas de estilo
OpenFWPA también recomienda el uso de alguna herramienta de evaluación automática para
comprobar:
•
Sintaxis de las páginas, tanto del código HTML como de las hojas de estilo, para verificar que
están bien formadas y son válidas.
•
Accesibilidad. Estas herramientas permiten identificar algunos de los problemas de
accesibilidad del código HTML (nivel de adecuación)
Existen varias herramientas de evaluación automática. De entre todas ellas, openFWPA recomienda la
herramienta
TAW
[http://www.tawdis.net/],
desarrollada
por
la
Fundación
CTIC
[http://www.fundacionctic.org/].
59 TAW – Herramienta de evaluación automática
9.9. Librería de etiquetas para el diseño de interfaces de usuario (UI)
OpenFWPA incorpora una librería de etiquetas para simplificar el desarrollo de la vista. Estas
etiquetas se encuentran en diferentes ficheros TLD.
•
•
princast-date.tld. Definición de las etiquetas para renderizar calendarios y fechas.
princast-navigation.tld. Definición de las etiquetas para renderizar la barra de navegación.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
181 de
296
princast-ui.tld. Definición de las etiquetas para renderizar componentes gráficos en general.
princast-util.tld. Definición de las etiquetas de propósito general o de utilidad.
Estas librerías de etiquetas se almacenan en el directorio “WEB-INF/tld”, tal y como se puede ver en
la siguiente imagen:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
182 de
296
60 Path del directorio TLD
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
183 de
296
9.9.1. Selección de fechas y calendarios
No está permitida la introducción de fechas a mano. Es obligatorio utilizar etiquetas específicas para la
selección de fechas. En la librería de tags princast-date.tld, incluida en openFWPA, se proporcionan
etiquetas para facilitar la labor de introducción de fechas por parte del usuario final de las aplicaciones.
9.9.1.1. Etiqueta <date:calendar/>
La etiqueta <date:calendar/> muestra un calendario desplegable. Para utilizar esta etiqueta debemos
incluir el fichero princast-date.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-date.tld" prefix="date" %>
En el siguiente ejemplo se muestra un ejemplo básico de uso de la etiqueta <date:calendar/>.
<date:calendar image="../../images/calendario/popcalendar.gif"
componentId="fechaPedido" format="dd/mm/yyyy" />
A continuación se verán todos los atributos correspondientes a la etiqueta <date:calendar/>.
•
•
•
•
•
•
•
•
•
•
•
language. Atributo opcional. Idioma en el que se mostrará el calendario. Por defecto 'es'.
enablePast. Atributo opcional. Booleano para indicar si que permite seleccionar una fecha
anterior a la actual.
enableFuture. Atributo opcional. Booleano para indicar si que permite seleccionar una fecha
posterior a la actual.
fixedX. Atributo opcional. Coordenada X en la que se mostrará el calendario.
fixedY Atributo opcional. Coordenada Y en la que se mostrará el calendario.
Image. Atributo opcional. Ruta de la imagen que sirve de icono para desplegar el calendario
(por defecto 'popcalendar.gif').
imageId. Atributo opcional. Identificador de la imagen que se pulsará para mostrar el
calendario (por defecto 'calgif').
altText. Atributo opcional. "alt" de la imagen que se pulsará para mostrar el calendario (por
defecto 'Desplegar calendario').
componentId. Atributo obligatorio. Identificador del campo de formulario que guardará el valor
de la fecha seleccionada en el calendario.
format. Atributo obligatorio. Patrón con el formato en el se devolverá la fecha, como por
ejemplo “dd/mm/yyyy”.
formatCssClass. Atributo opcional. Clase CSS que se aplicará al texto que muestra el formato
de fecha.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
184 de
296
Para satisfacer el punto de verificación 1.1 de prioridad 1 de las Directrices de Accesibilidad para el
Contenido Web 1.0 (WCAG 1.0) [http://www.w3.org/TR/WCAG10/], se proporciona un texto
equivalente si no se puede visualizar la imagen a través del atributo “alt”. Otra pauta que se ha tenido
en cuanta es la referente a la desactivación de objetos programados (en este caso, javascript) que viene
especificada en el punto de verificación 6.3 de prioridad 1 de las Directrices de Accesibilidad para el
Contenido Web 1.0 (WCAG 1.0) [http://www.w3.org/TR/WCAG10/]. Para satisfacer este punto de
verificación cuando se utiliza este etiqueta al visualizar la página se muestra al lado de la imagen del
calendario un texto que nos informa del formato de fecha utilizado, que coincide con el especificado
en el atributo format. El campo de texto asociado al calendario es editable con la finalidad de permitir
introducir la fecha en el formato especificado si el javascript esta desactivado.
9.9.1.2. Configuración del calendario
La etiqueta <date:calendar-config/> permite configurar el calendario. Para utilizar esta etiqueta
debemos incluir el fichero princast-date.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-date.tld" prefix="date" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
•
•
•
•
•
•
•
•
language. Atributo opcional. Idioma en el que se mostrará el calendario (por defecto 'es').
enablePast. Atributo opcional. Booleano para indicar si que permite seleccionar una fecha
anterior a la actual (por defecto 'false').
enableFuture. Atributo opcional. Booleano para indicar si que permite seleccionar una fecha
posterior a la actual (por defecto 'true').
fixedX. Atributo opcional. Coordenada X en la que se mostrará el calendario (por defecto '-1').
fixedY. Atributo opcional. Coordenada Y en la que se mostrará el calendario (por defecto '-1').
startAt. Atributo opcional. Día en el que comienza la semana (0 = domingo y 1 =lunes (por
defecto '1').
showWeekNumber. Atributo opcional. Booleano que indica si se desea mostrar en número de la
semana (por defecto 'false').
showToday. Atributo opcional. Booleano que indica si se desea resaltar la fecha actual (por
defecto 'true').
imgDir. Atributo opcional. Ruta al directorio donde se encuentran las imágenes que necesita el
calendario (por defecto '/').
dayName. Atributo opcional. Nombres de los días de la semana (No suele usarse y se deja que
sea el fichero de scripts quien lo gestione).
scriptFile. Atributo Obligatorio. Ruta al fichero JS necesario para mostrar el calendario (por
defecto 'calendar.js').
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
185 de
296
Hay que tener en cuenta que las dos etiquetas anteriores se utilizan de forma conjunta. Para que la
visualización del calendario sea correcta en todos los navegadores, la etiqueta <date:calendarconfig>, debe definirse dentro de la sección HEAD de la página HTML. La forma más correcta de
incluir la etiqueta de configuración del calendario es utilizar Tiles, tal y como se muestra en el ejemplo
siguiente:
<head>
<html:base />
<meta http-equiv="Content-type" content="text/html; charset=ISO-88591" />
<link rel="stylesheet" type="text/css" href="css/login05.css" />
<link rel="stylesheet" type="text/css" href="css/princast-ui.css" />
<date:calendar-config imgDir="./images/calendario/"
scriptFile="./tiles/scripts/calendar.js"/>
<title><bean:message key="welcome.title" /></title>
</head>
El resultado final es similar al expuesto en la siguiente imagen:
61 Ejemplo de calendario
9.9.1.3. Escribir la fecha actual
La etiqueta <date:date/> permite escribir la fecha actual en el formato:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
186 de
296
dia_de_la_semana, dia_del_mes / nombre_mes / año
Para utilizar esta etiqueta debemos incluir el fichero princast-date.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-date.tld" prefix="date" %>
Un ejemplo de utilización es el siguiente:
<date:date/>
El formato de la fecha escrita es como sigue:
viernes, 30 de Diciembre de 2011
Hay que tener en cuenta que el idioma en el que se visualiza la fecha es el seleccionado en el
navegador.
Esta etiqueta identifica el cambio de idioma para satisfacer el punto de verificación 4.1 de prioridad 1
de las Directrices de Accesibilidad para el Contenido Web 1.0 (WCAG 1.0)
[http://www.w3.org/TR/WCAG10/]. Para especificar el cambio de idioma se utiliza el atributo lang y
el código de idioma [http://www.oasis-open.org/cover/iso639a.html] correspondiente.
9.9.2. Barra de navegación
OpenFWPA incluye una barra de navegación que muestra, en cada página la ruta de acceso a la misma
y contiene enlaces a todas las entradas de menú pulsadas anteriormente, ya sean entradas de menú o
submenú, es decir, es independiente de la jerarquía de menú.
La barra de navegación es gestionada por un objeto PrincastNavigationBar, almacenado en la session,
bajo la entrada de nombre: es.princast.framework.web.view.navigation.NavigationBar.
Además, la barra de navegación es un objeto configurable a través del sistema de configuración
centralizado de openFWPA (es decir, implementa el interface ConfigurationListener. La barra de
navegación toma los parámetros del contexto de configuración: “NAVIGATION.CONTEXT”.
Los parámetros que configuran la barra de navegación son:
•
DEFAULT.ITEM.NAME. Indica el nombre por defecto que se generará al crear la barra de
navegación. Este será el primer item de la barra, por ello, su valor por defecto es “Inicio”.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
Estado
Definitivo
Documento
Manual de Configuración
Página
187 de
296
ITEM.SEPARATOR. Cadena de texto que se utilizará como separador de las entradas de la
barra de navegación. El valor por defecto es “:”.
9.9.2.1. Generar una barra de navegación
La etiqueta <navigation:navigator/> genera el código HTML para generar una barra de navegación.
Para utilizar esta etiqueta debemos incluir el fichero princast-navigation.tld en la JSP correspondiente.
<%@
%>
taglib
uri="/WEB-INF/tld/princast-navigation.tld"
prefix="navigation"
Los atributos correspondientes a esta etiqueta son los siguientes:
•
id. Campo opcional. Atributo "id" del map dentro del cual ira la barra de navegación (por
defecto 'barra_nav').
•
name. Campo opcional. Atributo "name" del map dentro del cual ira la barra de navegación
(por defecto 'barra_nav').
•
title. Campo opcional. Atributo "title" del map dentro del cual ira la barra de navegación (por
defecto 'Barra de navegación').
•
titleKey. Campo opcional. Clave en el fichero de recursos de mensajes para el atributo "title"
del map dentro del cual ira la barra de navegación
•
cssClass. Campo opcional. Atributo "class" de los enlaces de los elementos que componen la
barra de navegación.
•
autoCreate. Campo opcional. Flag que indica si es necesario crear la barra de navegación de
forma automática si ésta no existe (por defecto 'true').
•
jump. Campo opcional. Nombre del ancho al que saltar para poder saltar la barra de navegación
sin tener que avanzar por cada uno de los enlaces que la componen en el caso de navegadores
de texto o dispositivos lectores de pantalla o similares (por defecto 'contenido').
•
jumpTitle. Campo opcional. Atributo "title" del enlace para poder saltar la barra de navegación
sin tener que avanzar por cada uno de los enlaces que la componen en el caso de navegadores
de texto o dispositivos lectores de pantalla o similares (por defecto 'Saltar barra de navegación
e ir al contenido').
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
188 de
296
•
jumpTitleKey. Campo opcional. Clave en el fichero de recursos del atributo "title" del enlace
para poder saltar la barra de navegación sin tener que avanzar por cada uno de los enlaces que
la componen en el caso de navegadores de texto o dispositivos lectores de pantalla o similares.
•
jumpText. Campo opcional. Texto del enlace para poder saltar la barra de navegación sin tener
que avanzar por cada uno de los enlaces que la componen en el caso de navegadores de texto o
dispositivos lectores de pantalla o similares (por defecto 'Ir al contenido').
•
jumpTextKey. Campo opcional. Clave en el fichero de recursos del texto del enlace para poder
saltar la barra de navegación sin tener que avanzar por cada uno de los enlaces que la
componen en el caso de navegadores de texto o dispositivos lectores de pantalla o similares.
•
navigationLabel. Campo opcional. Texto que va delante de los elementos de la barra de
navegación (por defecto 'Está usted aquí:').
•
navigationLabelKey. Campo opcional. Clave en el fichero de recursos del texto que va delante
de los elementos de la barra de navegación.
Esta etiqueta agrupa mediante un objeto de tipo Map todos los enlaces de la barra de navegación. Para
satisfacer el punto de verificación 13.6 de prioridad 3 de las Directrices de Accesibilidad para el
Contenido Web 1.0 (WCAG 1.0) [http://www.w3.org/TR/WCAG10/] se proporciona un medio de
poder saltar el grupo de enlaces. Por otra parte, en cada uno de los enlaces se utiliza la etiqueta title
para aportar una descripción al enlace.
Se puede ver un ejemplo de utilización de esta etiqueta en la Tile “pages/tiles/barra_navegacion.jsp”:
<%@ page errorPage="/pages/errorEnJSP.jsp" %>
<%@ taglib uri="/WEB-INF/tld/princast-navigation.tld"
%>
<div id="barra_navegacion">
<navigation:navigator />
</div>
prefix="navigation"
9.9.3. Etiquetas para componentes gráficos
A continuación se enumeran el grupo de etiquetas de etiquetas que se van a especificar en los
siguientes apartados:
•
•
panel. Contenedor de etiquetas (con aspecto visual)
panel-caption. Permite renderizar el caption o título de las etiquetas panel
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
189 de
296
box. Contenedor de etiquetas (con aspecto visual)
box-caption. Permite renderizar el caption o título de las etiquetas box
layout-area. Contenedor de etiquetas (sin aspecto visual)
block-row. Permite renderizar elementos de bloque de tipo fila
block-column. Permite renderizar elementos de bloque de tipo columna
Todos los contenedores de etiquetas tienen la siguiente parte en común:
•
Cuerpo. Es el bloque central del contenedor, donde se ubican los componentes. Dentro de este
bloque podemos anidar cualquier tipo de etiqueta.
Además de esta parte común, los contenedores de etiquetas "panel" y "box" añaden las siguientes
partes:
•
Caption. Es la cabecera del contenedor. Muestra una pequeña descripción del cometido de los
controles. En la etiqueta "panel" la cabecera se especifica mediante la etiqueta "panel-caption"
y en la etiqueta "box" se especifica a través de la etiqueta "box-caption".
•
Pie. Es un bloque decorativo que se coloca al final de estos dos contenedores de etiquetas.
En todas las etiquetas se puede personalizar el aspecto visual. Esto se realiza mediante hojas de estilo.
Cada etiqueta tiene varios atributos que nos permiten especificar hojas de estilo. Se pueden utilizar las
hojas de estilo ya existentes o se pueden crear nuevas hojas de estilo.
Al concluir la descripción de este grupo de etiquetas se muestra un ejemplo de utilización.
9.9.3.1. Etiqueta para renderizar Paneles de Componentes para la UI (similares a los fieldset de
HTML)
La etiqueta <ui:panel/> permite renderizar paneles de componentes para la UI . Para utilizar esta
etiqueta debemos incluir el fichero princast-ui.tld en la JSP correspondiente. Esta etiqueta es un
contenedor de etiquetas.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
mostrar el panel.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
190 de
296
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para mostrar el panel (por defecto 'panel').
bodyId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado
para el cuerpo del panel.
bodyCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para el cuerpo del panel (por defecto 'panel_body').
footerId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML
generado para el pie del panel.
footerCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento
HTML generado para el pie del panel (por defecto 'panel_footer').
Este componente tiene la posibilidad de añadirle una caption o título, utilizando la etiqueta
<ui:panel-caption>
9.9.3.2. Etiqueta para renderiza el caption o título de las etiquetas panel
La etiqueta <ui:panel-caption/> permite renderizar el caption o título de las etiquetas panel. Para
utilizar esta etiqueta debemos incluir el fichero princast-ui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
•
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
el caption del panel.
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para el caption del panel (Por defecto 'panel_caption').
textId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento de encabezado
HTML generado que contendrá el texto del caption del panel.
textCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento de
encabezado HTML generado que contendrá el texto del caption del panel (por defecto
'panel_caption_text').
headingLevel. Campo obligatorio. Nivel del elemento de encabezado que contendrá el texto (1
para renderizar un "h1", 2 para un "h2", etc.)
Esta etiqueta permite especificar el nivel de encabezamiento a través del atributo headingLevel, para
satisfacer el punto de verificación 3.5 de prioridad 2 de las Directrices de Accesibilidad para el
Contenido Web 1.0 (WCAG 1.0) [http://www.w3.org/TR/WCAG10/] referente a la utilice elementos
de encabezado para transmitir la estructura lógica.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
191 de
296
A continuación se muestra el código de ejemplo y el aspecto obtenido al utilizar las dos etiquetas
comentadas anteriormente:
<ui:panel id="id-panel" bodyId="bodyId-panel">
<ui:panel-caption headingLevel="2">
<bean:message key="envio.datosPersonales.panel.caption" />
</ui:panel-caption>
</ui:panel>
62 Ejemplo de uso de etiqueta panel y panel-caption
9.9.3.3. Etiqueta para generar el bloque central de información de una página con un borde
superior y otro inferior
La etiqueta <ui:box/> genera el bloque central de información de una página con un borde superior y
otro inferior. Esta etiqueta es un contenedor de etiquetas. Para utilizar esta etiqueta debemos incluir el
fichero princast-ui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
•
•
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
mostrar el box.
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para mostrar el box (por defecto 'box').
bodyId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado
para el cuerpo del box.
bodyCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para el cuerpo del box (por defecto 'box_body').
borderUpperId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML
generado para el borde superior del box.
borderLowerId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML
generado para el borde inferior del box.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
192 de
296
Proyecto
openFWPA
•
Estado
Definitivo
Documento
Manual de Configuración
borderCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento
HTML generado para los bordes superior e inferior del box (por defecto 'box_border').
Este componente tiene la posibilidad de añadirle una caption o título, utilizando la etiqueta:
<ui:box-caption>
9.9.3.4. Etiqueta para renderizar el caption o título de las etiquetas box
La etiqueta <ui:box-caption/> permite renderizar el caption o título de las etiquetas box. Para utilizar
esta etiqueta debemos incluir el fichero princast-ui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
•
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
mostrar el caption del box.
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para mostrar el caption del box (por defecto 'box_caption').
textId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento de encabezado
HTML generado que contendrá el texto del caption del box.
textCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento de
encabezado HTML generado que contendrá el texto del caption del box (por defecto
'box_caption_text').
headingLevel. Campo obligatorio. Nivel del elemento de encabezado que contendrá el texto (1
para renderizar un "h1", 2 para un "h2", etc.).
Esta etiqueta permite especificar el nivel de encabezamiento a través del atributo headingLevel, para
satisfacer el punto de verificación 3.5 de prioridad 2 de las Directrices de Accesibilidad para el
Contenido Web 1.0 (WCAG 1.0) [http://www.w3.org/TR/WCAG10/] referente a la utilice elementos
de encabezado para transmitir la estructura lógica.
A continuación se muestra el código de ejemplo al utilizar las dos etiquetas comentadas anteriormente:
<ui:box bodyId="bodyId-box">
<ui:box-caption headingLevel="2">
<bean:message key="envio.datosPersonales.panel.caption" />
</ui:box-caption>
</ui:box>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
193 de
296
9.9.3.5. Etiqueta para renderizar un bloque en área determinada de la página sin aspecto visual
La etiqueta <ui:layout-area/> permite renderizar un bloque en área determinada de la página sin
aspecto visual. Esta etiqueta es un contenedor de etiquetas. Para utilizar esta etiqueta debemos incluir
el fichero princast-ui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
mostrar el área.
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para mostrar el área (por defecto 'layout_area').
bodyId. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado
para el cuerpo del área.
bodyCssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para el cuerpo del área (por defecto 'layout_area_body').
A continuación se muestra el código de ejemplo al utilizar la etiqueta anterior:
<ui:layout-area id="id-layout" bodyId="bodyId-layout">
...
</ui:layout-area>
El HTML generado con esta etiqueta es simplemente una serie de DIVs anidados que actúan como
contenedor, tal y como podemos ver en el siguiente código:
<div class="layout_area" id="id-layout">
<div class="layout_area_body" id="bodyId-layout">
...
</div>
</div>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
194 de
296
9.9.3.6. Etiqueta para renderizar elementos de bloque de tipo fila
La etiqueta <ui:block-row/> permite renderizar elementos de bloque de tipo fila. Esta tiene que estar
contenida dentro de uno de los contenedores vistos anteriormente. Para utilizar esta etiqueta debemos
incluir el fichero princast-ui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
el block-row.
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para el block-row (por defecto 'item_row').
9.9.3.7. Etiqueta para renderizar elementos de bloque de tipo columna
La etiqueta <ui:block-column/> permite renderizar elementos de bloque de tipo columna. Por lo tanto,
este etiqueta debe estar contenida dentro de una etiqueta <ui:block-row/>. Para utilizar esta etiqueta
debemos incluir el fichero princastui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
id. Campo opcional. Valor que aparecerá en el atributo "id" del elemento HTML generado para
el block-column.
cssClass. Campo opcional. Valor que aparecerá en el atributo "class" del elemento HTML
generado para el block-column (por defecto 'item_columna').
Un ejemplo de utilización de las tres etiquetas anteriores puede ser el siguiente:
<ui:layout-area>
<ui:block-row>
<ui:block-column>Elemento 1</ui:block-column>
<ui:block-column>Elemento 2</ui:block-column>
</ui:block-row>
<ui:block-row>
<ui:block-column>Elemento 3</ui:block-column>
<ui:block-column>Elemento 4</ui:block-column>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
195 de
296
</ui:block-row>
</ui:layout-area>
El código JSP del ejemplo anterior generaría la siguiente vista:
63 Ejemplo de uso de etiqueta block-row y block-column
OpenFWPA incluye una hoja de estilos denominada "princast-ui.css" que contiene estilos aplicables al
modelo de etiquetas para el diseño de interfaces de usuario (UI).
Entre todos los estilos disponibles en esta hoja de estilos, se tienen tres tipos de estilos normalmente
aplicados a la etiqueta <ui:block-column/>. Estos estilos son los siguientes:
•
•
•
item_columna. Mantiene el ancho por defecto (100%).
item_dos_columnas. Asigna un ancho del 49.99%.
item_tres_columnas. Asigna un ancho del 33.33%.
Ejemplo de utilización de “item_tres_columnas”:
<ui:layout-area>
<ui:block-row>
<ui:block-column cssClass="item_tres_columnas">
Elemento 1
</ui:block-column>
<ui:block-column cssClass="item_tres_columnas">
Elemento 2
</ui:block-column>
<ui:block-column cssClass="item_tres_columnas">
Elemento 3
</ui:block-column>
</ui:block-row>
<ui:block-row>
<ui:block-column cssClass="item_tres_columnas">
Elemento 4
</ui:block-column>
<ui:block-column cssClass="item_tres_columnas">
Elemento 5
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
196 de
296
</ui:block-column>
<ui:block-column cssClass="item_tres_columnas">
Elemento 6
</ui:block-column>
</ui:block-row>
</ui:layout-area>
9.9.4. Notificación de errores <ui:errors>
La etiqueta <ui:errors/> permite visualizar los errores producidos en la validación de un formulario.
Hereda de la etiqueta "errors" de Struts, por lo tanto, se aplican todas las peculiaridades que esta
última pudiera tener. Además, permite dar formato a los errores mostrados. Otra particularidad, es que
esta etiqueta no va a generar mensajes de error duplicados. Para utilizar esta etiqueta debemos incluir
el fichero princast-ui.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-ui.tld" prefix="ui" %>
Esta etiqueta es una extensión de la etiqueta Struts: <html:errors/>
Los atributos correspondientes a esta etiqueta son los siguientes:
bundle. Campo opcional.
locale. Campo opcional.
name. Campo opcional.
property. Campo opcional.
cssClass. Campo opcional. Nombre de la clase CSS que dará estilo a los errores (por defecto 'errors')
cssId. Campo opcional. Identificador del bloque HTML que contiene los errores
Un ejemplo de utilización en un fichero JSP:
...
<ui:errors/>
...
9.9.5. Etiquetas de utilidad y propósito general
9.9.5.1. Etiqueta para ocultar o mostrar código en función de un objeto
La etiqueta <util:instanceOf/> permite ocultar o mostrar determinado código de una página en función
de si un objeto (en alguno de los ámbitos habituales: request , session, etc.) es instancia de una clase
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
197 de
296
determinada. Para utilizar esta etiqueta debemos incluir el fichero princast-util.tld en la JSP
correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-util.tld" prefix="util" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
variableName. Campo obligatorio. Nombre de la variable cuyo tipo se va a verificar.
className. Campo obligatorio. Nombre de la clase para verificar.
Esta etiqueta puede ser de utilidad para mostrar mensajes de error diferentes en función de si existe
una excepción de un tipo determinado. Por ejemplo:
<util:instanceOf variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.WrongPasswo
rdException">
<div id="errores">
<ul>
<li>Validación
incorrecta
de
NIF/NIE
y
Clave
personal</li>
</ul>
</div>
</util:instanceOf>
Recuerda que para utilizar “SecurityGlobals.LOGIN_EXCEPTION” se debe importar en la cabecera
de la página JSP la clase correspondiente, tal y como se especifica a continuación.
<%@page
import="es.princast.framework.web.filter.security.common.SecurityGlobals"%>
9.9.5.2. Etiqueta para generar código en función del rol de usuario (coincidencia)
La etiqueta <util:isAllowed/> permite la generación de código HTML de su cuerpo en función del rol
del usuario. En este caso se comprueba que el rol del usuario coincide con algún rol especificado como
atributo. Para utilizar esta etiqueta debemos incluir el fichero princast-util.tld en la JSP
correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-util.tld" prefix="util" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
Estado
Definitivo
Documento
Manual de Configuración
Página
198 de
296
role. Campo obligatorio. Lista de valores separados por comas de los roles permitidos.
Un ejemplo de utilización en un fichero JSP:
<util:isAllowed role=" Citizen">
<bean:message key="profile.greeting" />
</util:isAllowed>
En el ejemplo anterior mostrará el mensaje siempre que el usuario tenga el rol Citizen.
9.9.5.3. Etiqueta para generar código en función del rol de usuario (no coincidencia)
La etiqueta <util:isNotAllowed/> permite la generación de código HTML de su cuerpo en función del
rol del usuario. En este caso se comprueba que el rol del usuario no coincide con ninguno de los roles
especificados como atributo. Para utilizar esta etiqueta debemos incluir el fichero princast-util.tld en la
JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-util.tld" prefix="util" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
role. Campo obligatorio. Lista de valores separados por comas de los roles no permitidos.
Estas dos últimas etiquetas permiten ocultar o mostrar determinado código en función del rol de
usuario que se le pasa como parámetro.
Un ejemplo de utilización en un fichero JSP:
<util:isNotAllowed role=" Citizen">
<bean:message key="profile.greeting" />
</util:isNotAllowed>
En el ejemplo anterior mostrará el mensaje siempre que el usuario NO tenga el rol Citizen.
9.9.5.4. Etiqueta para generar código de combos relacionadas entre si
Con el objetivo de mejorar la usabilidad de las aplicaciones de tramitación, openFWPA ha incluido
una serie de etiquetas que permiten dotar a las páginas de comportamiento dinámico, siguiendo la
filosofía AJAX (Asynchronous JavaScript). Estas etiquetas están basadas en la librería DWR1 (Direct
Web Remoting).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
199 de
296
La etiqueta <util:dwr-select/> permite asociar dos combos de forma fácil y rápida. El contenido de
uno de estos campos se carga en función del valor de otro de ellos. Esta etiqueta utiliza la tecnología
DWR (Ajax) para la carga dinámica del contenido de cada campo, estableciendo una relación maestrodetalle entre dos combos. Esta etiqueta hereda de <html:select> proporcionada por Struts, por lo tanto,
tendrá todos sus atributos (salvo la propiedad "onchange" que es gestionada directamente por la propia
etiqueta). Para utilizar esta etiqueta debemos incluir el fichero princast-util.tld en la JSP
correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-util.tld" prefix="util" %>
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
controller. Atributo obligatorio. Nombre de la función javascript que llama al controlador
DWR para cargar el contenido del select detalle.
detailId. Atributo obligatorio. Id del select detalle.
labelProperty. Atributo opcional. Nombre de la propiedad de la que se tomarán los labels del
select, en los beans devueltos por DWR (por defecto 'label').
alt. Atributo opcional.
altKey. Atributo opcional.
disabled. Atributo opcional.
indexed. Atributo opcional.
multiple. Atributo opcional.
name. Atributo opcional.
onblur. Atributo opcional.
onclick. Atributo opcional.
ondblclick. Atributo opcional.
onfocus. Atributo opcional.
onkeydown. Atributo opcional.
onkeypress. Atributo opcional.
onfocus. Atributo opcional.
onkeyup. Atributo opcional.
onmousedown. Atributo opcional.
onmousemove. Atributo opcional.
onmouseout. Atributo opcional.
onmouseover. Atributo opcional.
onmouseup. Atributo opcional.
property. Atributo opcional.
style. Atributo opcional.
styleClass. Atributo opcional.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
200 de
296
styleId. Atributo opcional.
tabindex. Atributo opcional.
size. Atributo opcional.
title. Atributo opcional.
titleKey. Atributo opcional.
value. Atributo opcional.
A continuación, se muestra un ejemplo de cómo se pueden enlazar dos campos SELECT utilizando
esta etiqueta:
<util:dwr-select controller="MunicipiosController.getMunicipios"
detailId="municipio"
property="provincia"
styleId="provincia"
styleClass="cajaTexto input_form" size="1">
<html:optionsCollection name="listaProvincias"/>
</util:dwr-select>
El código JSP del ejemplo anterior generaría la siguiente vista:
64 Ejemplo de uso de etiqueta util:dwr-select
9.9.5.5. Etiqueta para generar código para incluir los js utilizados en DWR
La etiqueta <util:dwr-import/> permite la generación de código HTML para incluir los ficheros
JavaScript (js) necesarios para utilizar las etiquetas "dwr-based". Esta etiqueta debe incluirse en las
páginas antes de poder utilizar cualquier etiqueta "dwr-based". Para utilizar esta etiqueta debemos
incluir el fichero princast-util.tld en la JSP correspondiente.
<%@ taglib uri="/WEB-INF/tld/princast-util.tld" prefix="util" %>
Para poder utilizar cualquiera de las etiquetas de openFWPA basadas en DWR, es necesario
previamente, importar los scripts necesarios: engine.js, opcionalmente utils.js, y todos los interfaces
con el controlador, por ejemplo interface/MunicipiosController.js.
<script type="text/javascript" src="../../dwr/engine.js"></script>
<script type="text/javascript" src="../../dwr/util.js"></script>
<script type="text/javascript"
src="../../dwr/interface/MunicipiosController.js"></script>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
201 de
296
Para facilitar esta tarea, especialmente si se van a utilizar varios controladores diferentes, se ha
incluido la etiqueta <util:dwr-import> que se encarga de generar todas las etiquetas <script> que sean
necesarias.
Los atributos correspondientes a esta etiqueta son los siguientes:
•
•
•
renderDWRUtil. Atributo opcional. Indica si se debe importar o no el script de utilidades de
DWR.
controllers. Atributo opcional. Lista de controladores DWR (objetos con métodos exportados
por DWR) que se van a importar. La lista será una cadena con todos los nombres de
controladores separados por espacios o comas.
dwrBase. Atributo opcional. URL base para la localización de los scripts DWR. Esta URL será
relativa a la página JSP donde se escribe la etiqueta y apuntará al serlvet DWR.
A continuación, se muestra un ejemplo de cómo se puede utiliza esta etiqueta para generar los tres
script vistos anteriormente:
<util:dwr-import dwrBase="../../../dwr"
controllers="MunicipiosController"/>
10. Sistema de Inicialización y Arranque
El núcleo de openFWPA se construye sobre un sistema de inicialización que permite definir, de forma
declarativa, los componentes que deben ser creados, configurados e iniciados durante el período de
arranque de las aplicaciones. Generalmente estos componentes son objetos de utilidad que tienen
alcance global a toda la aplicación, como el sistema de logging, de configuración, monitorización,
contadores, consola de administración, etc..
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
202 de
296
El Sistema de Inicialización se basa en el Framework IoC Spring (http://www.springframework.org).
65 Estructura del sistema de inicialización y arranque
10.1. Declaración de objetos inicializables
El fichero de arranque de las aplicaciones que utiliza openFWPA: princast-init-script.xml. En este
fichero se deben definir los objetos que serán accesibles durante el periodo de inicialización.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
203 de
296
66 Path del fichero WEB_INF/princast-init-script.xml
La estructura del fichero princast-init-script.xml se ajusta a la DTD de los ficheros de inicialización del
Framework Spring (http://www.springframework.org/dtd/spring-beans.dtd).
Para definir un objeto, se utilizará la etiqueta <bean>, indicando, como atributos un identificador para
dicho objeto y su clase (opcionalmente se puede indicar si es un Singleton). Dentro de la etiqueta
<bean> se pueden establecer propiedades de los objetos de forma declarativa utilizando la etiqueta
<property> (se considera propiedad de un objeto a todo método que empiece por la cadena “set” y
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
tenga un solo parámetro. Ver documentación
http://www.oracle.com/technetwork/java/index.html).
oficial
de
Java
Beans
de
Página
204 de
296
Sun
en
Este sistema para dar valor a propiedades de métodos se llama “Inversion Of Control (IoC)”.
Las propiedades pueden ser valores introducidos directamente (etiqueta <value>), o referencias a otros
objetos definidos en el mismo fichero (etiqueta <ref bean=”…”>).
...
<bean id="securityRulesPlugin"
class="es.princast.framework.web.filter.security.corp.conf.SecurityRulesCon
figurationPlugin">
<constructor-arg>
<value>security-rules</value>
</constructor-arg>
<property name="file">
<value>WEB-INF/princast-security-rules.xml</value>
</property>
<property name="contexts">
<list>
<value>SECURITY</value>
</list>
</property>
</bean>
...
<bean id="jmxBasePluginCap"
class="es.princast.framework.core.management.configuration.ConfigurationPlu
ginJMXAdapter">
<property name="plugin">
<ref bean="baseConfigurationPlugin"/>
</property>
</bean>
...
Existen muchas otras etiquetas que permiten:
•
•
•
especificar valores para los parámetros del constructor
asignar colecciones a propiedades de los objetos
definir variables al estilo ANT (${name})
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
Estado
Definitivo
Documento
Manual de Configuración
Página
205 de
296
etc.
Para mas información al respecto
[http://www.springframework.org].
consulte
la
página
Web
del
Framework
Spring
10.1.1. Variables ${…} en el fichero de inicialización
En el fichero princast-init-script.xml es posible utilizar variables al “estilo ANT”: ${nombre}. Los
valores de estas variables se obtienen de un fichero de propiedades.
Para poder utilizar este tipo de variables, es necesario incluir, en el propio fichero princast-initscript.xml, el siguiente bean:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigur
er">
<property name="location"><value>deploy.properties</value></property>
</bean>
Donde “deploy.properties” es el fichero del que se cargarán los valores de las variables. La ruta de
este fichero es relativa al classpath (se encuentra en el directorio resources).
Un ejemplo de uso de variables es el que sigue:
<bean id="myBean" class="es.princast.framework.examples.MyBean”
lazy-init="false" singleton="true">
<property name="exampleProp"><value>${PROP}</value></property>
</bean>
Suponiendo que en el fichero “deploy.properties” se haya definido la propiedad PROP.
Es posible utilizar rutas de fichero absolutas. Para ello, es necesario utilizar la construcción de Spring
“FileSystemResources”, tal y como se indica en el siguiente ejemplo:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigur
er">
<property name="location">
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg>
<value>c:/deploy.properties</value>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
206 de
296
</constructor-arg>
</bean>
</property>
</bean>
67 Fichero princast-init-script.xml
10.2. Desarrollo de objetos inicializables
Es posible implementar objetos para que sean arrancados de forma automática, durante la
inicialización, por openFWPA.
Todos los objetos que están definidos en el fichero princast-init-script.xml pueden ser inicializados y
arrancados automáticamente. No es necesario que los objetos implementen ningún interfaz específico
pero se tendrá en cuenta:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
•
•
•
Estado
Definitivo
Documento
Manual de Configuración
Página
207 de
296
Si los objetos implementan el interfaz Configurable, además de ser creados serán configurados
de forma automática por el Framework.
Si los objetos implementan el interfaz Launchable, serán creados de forma automática
(ejecutándose cualquier tarea que tengan implementada bajo el método create()).
Si los objetos implementan el interfaz RegistrableMBean, éstos serán registrados bajo el
sistema de gestión JMX.
El sistema de inicialización siempre arranca los siguientes objetos:
•
•
•
Manager de logging.
Factoría del sistema de control y gestión JMX. ManagementFactory.
Sistema de configuración. FrameworkConfigurator
10.3. Arranque de aplicaciones Web
El componente inicializador de las aplicaciones es: PrincastStartupListener.
El startup-listener implementa el interfaz ServletContextListener y, por tanto, debe ser declarado en el
fichero web.xml. Además, también se debe declarar un parámetro de contexto (<context-param>) que
indique la ruta del fichero de arranque princastinit-script.xml, tal y como se muestra en el siguiente
ejemplo:
<context-param>
<param-name>INIT.SCRIPT.FILE</param-name>
<param-value>/WEB-INF/princast-init-script.xml</param-value>
</context-param>
<listener>
<listener-class>
es.princast.framework.web.startup.PrincastStartupListener
</listener-class>
</listener>
10.4. Arranque manual
El arranque automático de los servicios de openFWPA (configuracion, management, etc.) únicamente
está operativo en aplicaciones Web (al estar basado en un ServletContextListener).
Para cualquier otro tipo de aplicaciones (consola, EJBs, etc.) en las cuales no hay una parte Web
disponible, para acceder a los servicios de openFWPA es necesario lanzar la inicialización de forma
manual.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
208 de
296
Para realizar esta tarea, se incluye la clase PrincastStandaloneInitializer (disponible en el core de
OpenFWPA). Esta clase se debe iniciar (utilizando el método estático init()) al arrancarse la
aplicación. Durante la ejecución pone a disposición de la aplicación todos los beans declarados en el
fichero de inicialización (princast-init.script.xml), a través del PrincastApplicationContext, que se
obtiene con el método getInitScriptContext() de PrincastStandaloneInitializer.
// INIT_SCRIPT tiene asociada la clave INIT.SCRIPT.FILE utilizada en el
// fichero “web.xml” para definer la ruta del fichero de inicialización
// “/WEB-INF/princast-init-script.xml”, como vimos en el apartado anterior
InputStream stream =
this.getClass().getClassLoader().getResourceAsStream(INIT_SCRIPT);
//Default configuration properties
Properties props = new Properties();
props.put("myProp", "myValue");
PrincastStandaloneInitializer.init(stream, props);
Para finalizar la aplicación se debe llamar al método estático finish().
El método init() también permite también cargar todos los ficheros XML de definición de beans (de
Spring) que sean necesarios para la aplicación. Para especificar los ficheros a cargar se indicarán los
patrones correspondientes (siguiendo el convenio de nombrado habitual en Spring), teniendo en cuenta
que se tomarán relativos al classpath.
11. Sistema de configuración de aplicaciones
Otro de los sistemas del núcleo de openFWPA es el Sistema de Configuración. El sistema de
configuración permite, tanto a los componentes de las aplicaciones como del propio Framework,
recibir parámetros de configuración de forma completamente transparente, sin necesidad de
preocuparse por la forma o el lugar en que éstos están almacenados.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Objetos
configurables
solicitan
parámetros de
un
CONTEXTO
Página
209 de
296
Objetos
configurables
solicitan
los
parámetros al
Framework
Configurator
Los
contextos
son
clasificacion
es
de
parámetros
Plugins
se
encargan de
leer / escribir
parámetros de
configuración
Los Plugins
se gestionan
desde
la
consola JMX
68 Estructura del sistema de configuración
El Sistema de Configuración actúa como un almacén centralizado de parámetros de configuración. En
la configuración de aplicaciones intervienen los siguientes componentes:
•
•
•
•
Plugins de configuración (ConfigurationPlugin). Se trata de objetos que pueden acceder a un
almacén de parámetros de configuración, ya sea para únicamente recuperar sus valores, o
también para actualizarlos.
Contextos de configuración. Los contextos son conjuntos de parámetros agrupados por su
funcionalidad. Los parámetros agrupados en un mismo contexto sirven, habitualmente, a
objetos relacionados entre sí.
Configurador de aplicaciones (FrameworkConfigurator). Es el componente central del sistema
de configuración. Se encarga de cargar los parámetros y repartirlos a los objetos que los
necesiten.
Objetos configurables (Configurable). Este tipo de objetos escuchan eventos en el
“Configurador de Aplicaciones” y pueden actualizar su estado a medida que la configuración
de la aplicación cambia. Los listeners son, generalmente, objetos de aplicación que necesitan
acceder a los parámetros que proporciona el Sistema de Configuración de openFWPA.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
210 de
296
11.1. Implementación de los objetos configurables
Para que un objeto pueda acceder a los parámetros del sistema centralizado de configuración de
openFWPA:
•
Implementar el interface Configurable.
•
Registrarse en el configurador: FrameworkConfigurator.
11.1.1. Implementando el interface Configurable
El interface Configurable define una serie de métodos para la gestión del ciclo de vida del objeto
configurable. Los tres métodos definidos son, en realidad, métodos callback. Únicamente van a ser
utilizados por el sistema de configuración y no se deben invocar directamente desde objetos de la
aplicación.
Estos métodos son:
•
•
•
configure(ConfigurationParameters). Se invoca cuando el objeto se configura por primera vez.
Cuando se llama a este método, se presupone que el objeto no ha sido configurado con
anterioridad. Este método recibe como argumento un conjunto de parámetros de configuración
(ConfigurationParameters).
reconfigure(ConfigurationEvent). Se invoca cuando el valor de algún parámetro que pueda ser
relevante para la configuración del objeto, es actualizado (si se actualizan más de un parámetro,
en caso contrario, se utiliza el método siguiente). Este método recibe como parámetro un
evento de configuración (ConfigurationEvent).
reconfigure(ConfigurationParameterUpdatedEvent). Reconfigura un objeto configurable ante
la actualización de un único parámetro.
En la implementación de estos métodos, el objeto configurable debe obtener, principalmente del
conjunto de parámetros (ConfigurationParameters) o del evento (ConfigurationEvent), los datos que
necesite para su configuración.
11.1.1.1. Conjunto de Parámetros de Configuración (ConfigurationParameters)
Se trata de un almacén que contiene todos los parámetros de configuración de la aplicación, agrupados
en contextos. Es responsabilidad del objeto configurable seleccionar aquellos parámetros que le
puedan ser de utilidad.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
211 de
296
Se pueden obtener todos los parámetros de un conjunto utilizando el método getKeys(). Este método
devuelve una enumeración (Enumeration) con los nombres (String) de todos los parámetros existentes
en el sistema. Otra opción es buscar únicamente los parámetros clasificados bajo un contexto
determinado. En este caso, se utilizará el método getKeys(String), pasando como argumento el nombre
del contexto cuyos parámetros se quieren enumerar.
Para obtener un parámetro del conjunto ConfigurationParameters, se utilizará el método
getParameter(String), si se sabe con certeza que el valor del parámetro es una cadena de caracteres, o
el método getConfigurationObject(String) si se quiere recuperar un Object genérico. Ambos métodos
reciben como argumento el nombre del parámetro a localizar.
Utilizando estos métodos, si dos parámetros coinciden en nombre, se devolverá el primero que se
encuentre. Para evitar colisiones de nombrado, se pueden utilizar los métodos alternativos:
getParameter(String, String) y getConfigurationObject(String, String). A los cuales se les especifica,
como primer argumento, el nombre del contexto en el que se quiere buscar el parámetro.
public void configure(ConfigurationParameters params) {
String param = params.getParameter(”MY_FOO_KEY_1”) ;
if (param != null) {
this.fooKey = param;
}
param = params.getParameter(“FOO_CONTEXT”, “MY_FOO_KEY_2”);
if (param != null) {
this.fooKey2 = param;
}
}
11.1.1.2. Eventos de Configuración (ConfigurationEvent)
Los eventos de configuración se disparan cuando se produce una actualización en los valores de los
parámetros de configuración. Cuando un evento de configuración se dispara se invocan los métodos
reconfigure() de los objetos configurables.
Es responsabilidad del desarrollador de los objetos configurables implementar la respuesta que tendrán
sus objetos ante determinados eventos.
Como vimos anteriormente, el método reconfigure(), son realmente dos métodos:
•
reconfigure(ConfigurationEvent). Recibe un evento de configuración de carácter general. No
existe una causa concreta que peda disparar este evento: reinicio del sistema, recarga de un
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
212 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
fichero de configuración, etc. El objeto event proporciona: nombre del contexto afectado por el
evento (getContextName()) y conjunto de parámetros de configuración actualizados
(getParameters()).
•
reconfigure(ConfigurationParameterUpdatedEvent). Recibe un evento de reconfiguración más
específico que indica la actualización de un único parámetro de configuración. El objeto event,
además de la información suministrada por la superclase (ConfigurationEvent), proporciona,:
nombre del parámetro actualizado (getParameterName()), valor anterior (getFormerValue()) y
nuevo valor (getCurrentValue()).
public void reconfigure(ConfigurationParameterUpdatedEvent event) {
if (event.getContext().equals(this.configurationConetxtName)) {
if (event.getParameterName().equals(“MY_FOO_KEY_1”)) {
this.fooKey = event.getCurrentValue().toString();
} else if (event.getParameterName().equals(“MY_FOO_KEY_2”)) {
this.fooKey2 = event.getCurrentValue().toString();
}
}
}
public void reconfigure(ConfigurationEvent event) {
if (event.getContext().equals(this.configurationConetxtName)) {
this.configure(event.getParameters());
}
}
11.1.2. Registro de un objeto en el FrameworkConfigurator
Por último, para que un objeto (que implemente Configurable) pueda ser gestionado por el sistema de
configuración, éste debe ser registrado en el configurador de openFWPA. Para registrar un objeto,
basta con llamar al método configureMe() del FrameworkConfigurator.
public MyClass() {
FrameworkConfigurator.getConfigurator().configureMe(this, true);
}
Este método recibe dos parámetros: el objeto configurable y un valor booleano que indica si el objeto
quiere escuchar, o no, eventos de reconfiguración.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
213 de
296
11.1.3. Ejemplo de clase que implementa la interfaz Configurable
A continuación podemos ver un ejemplo de una clase que implementa la interfaz Configurable,
definiendo para ello las tres clases que hemos visto en los apartados anteriores.
Esta clase está disponible en la aplicación de ejemplo “sampleapp” dentro de openFWPA.
public class AgenciasManager implements Configurable {
/**
* El nombre de la agencia disponible
*/
private String agencia;
/**
* El nombre del contexto de configuración que se utiliza para
* obtener el nombre de la agencia oficial
*/
private static final String AGENCIA = "CARRITO.AGENCIA";
/**
* El logger de la clase
*/
protected static final Logger logger =
Logger.getLogger(AgenciasManager.class);
{
FrameworkConfigurator.getConfigurator().configureMe(this, true);
}
public void reconfigure(ConfigurationParameterUpdatedEvent event) {
Debug.trace(this, "Reconfigurando AgenciasManager. Parametro
"+event.getParameterName());
if (event.getParameterName().equals(AGENCIA)) {
this.agencia = event.getCurrentValue().toString();
}
}
public void configure(ConfigurationParameters conf) {
agencia = conf.getParameter(AGENCIA);
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
214 de
296
if (agencia == null) {
logger.warn("No se ha definido una agencia...");
}
}
/**
* Obtiene el nombre de la agencia de transporte a utilizar para el
* envío
*/
public String getAgencia() {
return agencia;
}
public void reconfigure(ConfigurationEvent event) {
this.agencia = event.getParameters().getParameter(AGENCIA);
}
}
11.2. Plugins de configuración
Los plugins de configuración son los componentes que proporcionan los parámetros que maneja el
Sistema de Configuración. Un plugin de configuración se encarga de gestionar un único almacén de
datos (un fichero, una base de datos, etc.), sin embargo, un plugin puede servir parámetros a varios
contextos de configuración. Los plugins de configuración, implementan el interface
ConfigurationPlugin.
11.2.1. Añadir un plugin de configuración
Si una aplicación tiene alguna necesidad de configuración, la mejor opción suele ser definir plugins de
configuración específicos. Para ello, es necesario seguir los siguientes pasos:
•
•
•
•
•
•
Seleccionar, de los tipos de plugins que contiene openFWPA, el más adecuado.
Si no se encuentra ninguno que se ajuste a las necesidades, implementar uno propio.
Escribir los parámetros de configuración en el almacén seleccionado.
Declarar el plugin en el fichero de arranque de la aplicación (princast-init-script.xml).
Opcionalmente, definir un bean manager para la gestión del plugin a través de la consola JMX.
En el propio fichero princast-init-script.xml, registrar el plugin en la declaración del bean
FrameworkConfigurator.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
215 de
296
11.2.1.1. Declaración de plugins en el fichero de inicialización
Antes de poder utilizar un plugin de configuración es necesario definirlo en el fichero de arranque de
la aplicación (princast-init-script.xml).
Los plugins de configuración son objetos inicializables de openFWPA (Ver Sección “10.1.
Declaración de objetos inicializables”) y se deben definir como beans en el fichero de arranque.
<bean id="abstractConfigurationPlugin" abstract="true"
class="es.princast.framework.core.configuration.plugins.PropertiesFileConfi
gurationPlugin">
<property name="contexts">
<list>
<value>SECURITY</value>
<value>ROOT.CONTEXT</value>
<value>ACTION.CONTEXT</value>
<value>MENU.CONTEXT</value>
<value>NAVIGATION.CONTEXT</value>
<value>JMX.CONTEXT</value>
</list>
</property>
</bean>
<!— Hereda del padre el «property name="contexts"
ya que aquí no se
definen -->
<bean id="baseConfigurationPlugin" parent="abstractConfigurationPlugin">
<constructor-arg><value>basePlugin</value></constructor-arg>
<property name="file"><value>${base.module.file}</value></property>
<property name="priority"><value>1</value></property>
</bean>
Los parámetros que se definen en el ejemplo anterior son:
•
<constructor-arg><value>pluginId</value></constructor-arg>. (Obligatorio para todos los
plugins) Se debe definir, como argumento de constructor, el nombre que identifica al plugin (en
este caso: “basePlugin”).
•
<property name="priority">. Se trata de la prioridad del plug-in. En caso de que haya varios
plugins que, para un mismo contexto ofrezcan parámetros de igual nombre (es decir, en caso de
que haya conflicto de nombres de los parámetros), se tomarán primero los parámetros ofertados
por el plug-in de prioridad mas alta (numero más bajo). Si no se establece ningún valor, por
defecto, la prioridad de todos los plug-ins es 10 (un valor intermedio).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
216 de
296
La prioridad permite definir jerarquías de plug-ins de configuración. De esta forma, se permite
definir plug-ins a nivel de contenedor (con parámetros comunes a todas las aplicaciones) que
pueden sobrescritos para definir parámetros específicos para cada aplicación.
•
<property name="file">. Algunas propiedades se deben definir, o no, en función del tipo de
plugin. En este caso, el plugin PropertiesFileConfigurationPlugin, exige la definición de la
property “file”.
•
<property name="contexts">. (Obligatorio para todos los plugins) Por ultimo, se debe definir
la lista de contextos a los que el plugin sirve parámetros. En este caso, el plugin sirve
parámetros al contexto raíz (ROOT.CONTEXT), al contexto de seguridad (SECURITY), al
contexto del sistema de gestión JMX (JMX.CONTEXT), al contexto de las Actions de la
aplicación (ACTION.CONTEXT), al contexto de configuración para los menús
(MENU.CONTEXT), y al contexto de configuración de la barra de navegación
(NAVIGATION.CONTEXT).
Opcionalmente, una vez definido el plugin, se le puede asignar un adaptador JMX de forma que éste
pueda ser manejado desde la consola HTML de la aplicación.
Si se define un adaptador, será posible, a través de la consola, actualizar o referescar, en caliente, los
valores de los parámetros de configuración del plugin (siempre y cuando el plugin soporte estas
operaciones).
<!-- Sombreros JMX para los módulos -->
<bean id="jmxBasePluginCap"
class="es.princast.framework.core.management.configuration.ConfigurationPlu
ginJMXAdapter">
<property name="plugin">
<ref bean="baseConfigurationPlugin"/>
</property>
</bean>
<bean id="jmxJaasConfigPluginCap"
class="es.princast.framework.core.management.configuration.ConfigurationPlu
ginJMXAdapter">
<property name="plugin"><ref bean="jaasConfigPlugin"/></property>
</bean>
El adaptador JMX es otro bean, del tipo: ConfigurationPluginJMXAdapter. Únicamente es necesario
indicar la referencia del plugin (utilizando su identificador de bean: <bean id=…) que debe gestionar,
al definir la propiedad “plugin”, tal y como se muestra en el ejemplo anterior.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
217 de
296
Para finalizar, es necesario registrar el plugin en la definición del FrameworkConfigurator (que no es
más que otro bean en el fichero princast-init-script.xml). Se debe añadir la referencia al plugin en la
propiedad: “plugins”.
<!-- Gestor de configuracion -->
<bean id="configurationManager"
class="es.princast.framework.core.configuration.FrameworkConfigurator"
factory-method="getConfigurator" lazy-init="false" singleton="true">
<property name="plugins">
<list>
<ref bean="baseConfigurationPlugin"/>
<ref bean="globalConfigurationPlugin"/>
<ref bean="jaasConfigPlugin"/>
<ref bean="securityRulesPlugin"/>
</list>
</property>
</bean>
11.2.1.2. Plugins en openFWPA
En openFWPA se incluyen algunos plugins de configuración listos para ser utilizados. Además, se
proporcionan clases para facilitar el desarrollo de plugins por parte de los usuarios.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
218 de
296
ConfigurationPlugin
plugins::
BaseConfigurationPlugin
plugins::
PropertiesConfigurationPlugin
plugins::
ServletContextPlugin
plugins::
ServletConfigurationPlugin
xml::
XMLConfigurationPlugin
#handler
plugins::
PropertiesFileConfigurationPlugin
xml::
XMLStringConfigurationPlugin
xml::
XMLFileConfigurationPlugin
xml::
XMLConfigContentHandler
69 Jerarquía de plugins en openFWPA
11.2.1.2.1. Plugins basados en Properties
Los plugins basados en Properties almacenan parámetros como pares {atributo, valor}.
En openFWPA se empaquetan dos clases para gestionar este tipo de parámetros:
•
PropertiesConfigurationPlugin, para cargar los datos de configuración de un objeto
java.util.Properties en memoria.
<bean id="myPropsConfigurationPlugin"
class="es.princast.framework.core.configuration.plugins.PropertiesConfigura
tionPlugin">
<constructor-arg><value>propsPlugin</value></constructor-arg>
<property name="priority"><value>12</value></property>
<property name="properties">
<map>
<entry key="PARAMETRO.UNO">
<value>Un valor</value>
</entry>
<entry key="PARAMETRO.DOS">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
219 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<value>Otro valor</value>
</entry>
</map>
</property>
<property name="contexts">
<list>
<value>CONTEXTO.UNO</value>
</list>
</property>
</bean>
En la propiedad “properties” se deben indicar todos los pares {clave, valor} que va a servir el
plugin. Este plugin puede ser actualizado, pero no se pueden guardar los cambios realizados.
•
PropertiesFileConfigurationPlugin, que obtiene los parámetros de un fichero de properties.
<bean id="baseConfigurationPlugin" parent="abstractConfigurationPlugin">
<constructor-arg><value>basePlugin</value></constructor-arg>
<property name="file"><value>${base.module.file}</value></property>
<property name="priority"><value>1</value></property>
</bean>
En la propiedad “file” se debe especificar la ruta del fichero .properties a cargar. Esta ruta
puede ser absoluta, relativa al contexto de la aplicación Web, o al classpath (siempre que
empiece por la cadena “classpath://”).
11.2.1.2.2. Plugins basados en XML
Este tipo de plugins obtienen la configuración de un documento XML. Este documento puede estar en
memoria (en un String, por ejemplo), o en un fichero.
•
XMLStringConfigurationProperties. Carga la configuración directamente de un String.
<bean id="xmlStringConfigurationPlugin"
class="myapp.MyXMLStringConfigurationPlugin">
<constructor-arg><value>xmlStringPlugin</value></constructor-arg>
<property name="priority"><value>12</value></property>
<property name="xml">
<value>
<![CDATA[
<elements>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
220 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
<element value='myId' label='bar'/>
<element value='myId2' label='bar2'/>
</elements>
]]>
</value>
</property>
<property name="contexts">
<list>
<value>EXAMPLE.CONTEXT</value>
</list>
</property>
</bean>
Para configurar este plugin, debe escribirse el documento XML (que contiene la configuración) en
la propiedad “xml”. Es importante observar que debe escribirse en una sección CDATA, de lo
contrario, el fichero de inicio no sería valido de acuerdo a su DTD. Este plugin es de solo-lectura.
•
XMLFileConfigurationPlugin. Carga la configuración de un fichero XML.
Para configurar este plugin, se debe indicar el fichero XML de configuración en la propiedad
“file”. El path de este fichero puede ser absoluto, relativo respecto al contexto de la aplicación
Web, o respecto al classpath (si empieza por la cadena “classpath://”, como ocurre en el ejemplo).
Debido a la flexibilidad del formato XML, este tipo de plugins delegan el análisis del documento, y la
gestión de los parámetros de configuración, en un objeto auxiliar: XMLConfigContentHandler.
Para definir un plugin de configuración XML, es
XMLConfigContentHandler. Se deben implementar métodos para:
•
•
necesario
extender
la
clase
Analizar el documento XML. El análisis del documento se realiza utilizando el API Apache
Commons Digester. Los métodos a implementar son: setDigesterRules(Digester), en el que se
definirán las reglas del Digester para analizar el fichero y registerDTDs(Digester), para
registrar las DTD que se quieran utilizar para validar el documento XML proporcionado.
Gestionar los parámetros de configuración. Además, se deben implementar métodos que
permitan obtener un determinado parámetro (getParameter()), escribir un valor
(setParameter()), etc.
/**
* Clase que se encarga de cargar la configuración JAAS del sistema.
* Disponible en el core de openFWPA
*/
public class JAASConfigurationPlugin extends XMLFileConfigurationPlugin {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
221 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
/**
* Logger de la clase.
*/
protected static final Logger logger = Logger
.getLogger(JAASConfigurationPlugin.class);
/**
* Clase auxiliar para gestionar le contenido del fichero XML de
* configuración
*/
class JAASConfigContentHandler extends XMLConfigContentHandler {
/**
* Constructor de la clase interna
*/
public JAASConfigContentHandler(String name) {
super(name);
setValidate(true);
}
/**
* Declaracion de DTD publica
*/
protected static final String DTD =
"-//Framework PA - Team//DTD JAAS Configuration 1.3F//ES";
/**
* Ubicacion en el classloader de la DTD
*/
protected static final String DTD_FILE =
"es/princast/framework/resources/jaas-config.dtd";
protected void registerDTDs(Digester digester) {
//Establece la ubicacion de la DTD
URL url = Thread.currentThread().getContextClassLoader()
.getResource(DTD_FILE);
if (url == null) {
log.error("No se ha encontrado DTD en la ubicación "
+ DTD_FILE +
". Se producirá un error parseando” +
" el documento XML");
} else {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
222 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
digester.register(DTD, url.toString());
if (log.isDebugEnabled()) {
log.debug("Utilizando
DTD
en:
"
+
url.toString());
}
}
}
protected void setDigesterRules(Digester digester) {
digester
.addObjectCreate("jaas",
"es.princast.framework.facilities.security.jaas.config.ApplicationCon
figBean");
digester
.addObjectCreate("jaas/application",
"es.princast.framework.facilities.security.jaas.config.ConfigBean");
digester.addSetProperties("jaas/application");
digester.addCallMethod("jaas/application/module",
"setModule", 0);
digester
.addObjectCreate("jaas/application/options/option",
"es.princast.framework.facilities.security.jaas.config.OptionBean");
digester.addCallMethod("jaas/application/options/option/name",
"setName", 0);
digester.addCallMethod("jaas/application/options/option/value",
"setValue", 0);
digester
.addSetNext("jaas/application/options/option",
"addOption",
"es.princast.framework.facilities.security.jaas.config.OptionBean");
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
223 de
296
digester
.addSetNext("jaas/application", "addAppConfig",
"es.princast.framework.facilities.security.jaas.config.ConfigBean");
}
public void setParameter(String key, String value) {
log.info("Fichero de configuracion JAAS-CONFIG no soporta "
+
"actualizacion directa. Si quiere modificar la
configuración, debe " +
"realizar
los
cambios
directamente
sobre
el
fichero y recargarlo " +
"mediante la consola.");
}
public List getConfigurationObjects() {
ArrayList objs = new ArrayList(1);
objs.add(getXMLObject());
return objs;
}
public String getParameter(String key) {
if
(key
==
!SecurityGlobals.JAAS_CONFIG_OBJECT.equals(key)) {
return null;
}
null
||
return getXMLObject().toString();
}
public Enumeration getKeys() {
Vector keys = new Vector(1);
keys.add(SecurityGlobals.JAAS_CONFIG_OBJECT);
return keys.elements();
}
public Object getConfigurationObject(String key) {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
224 de
296
return
(key
!=
null
SecurityGlobals.JAAS_CONFIG_OBJECT.equals(key)) ? getXMLObject()
: null;
}
&&
public void setConfigurationObject(String key, Object value) {
log.info("Fichero de configuracion JAAS-CONFIG no soporta "
+
"actualizacion directa. Si quiere modificar la
configuración, debe " +
"realizar
los
cambios
directamente
sobre
el
fichero y recargarlo " +
"mediante la consola.");
}
public String getParameter(String path, String key) {
if (log.isDebugEnabled()) {
log.debug("Modulo de configuracion de JAAS-CONFIG no
soporta contextos anidados. " +
"Se ignora el contexto "+path);
}
return getParameter(key);
}
public Object getConfigurationObject(String path, String key) {
if (log.isDebugEnabled()) {
log.debug("Modulo de configuracion de JAAS-CONFIG no
soporta contextos anidados. " +
"Se ignora el contexto "+path);
}
return getConfigurationObject(key);
}
}
/**
* Constructor del plugin de configuracion
*/
public JAASConfigurationPlugin(String name, File file) {
this(name);
setFile(file);
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
225 de
296
}
/**
* Constructor del plugin de configuracion
*/
public JAASConfigurationPlugin(String name) {
super(name);
setHandler(new JAASConfigContentHandler(name));
}
}
12. Filtros Web
Con vistas a poder acceder de forma sencilla a las peticiones y respuestas HTTP que circulan entre el
navegador del cliente y el servidor Web se proporciona una arquitectura de filtros extensible de forma
sencilla.
12.1. Filtros de openFWPA. PrincastFilter
Todos los filtros (Servlet Filters) proporcionados por openFWPA extienden del filtro base:
PrincastFilter. Este filtro extiende la jerarquía básica de Servlet Filters proporcionada por la
plataforma J2EE y ofrece algunas funcionalidades extra.
En caso de que las aplicaciones vayan a implementar sus propios filtros, es recomendable siempre
extender la clase PrincastFilter.
En openFWPA, los filtros se almacenan en el directorio “web/filter” tal y como podemos ver en la
siguiente imagen:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
226 de
296
70 Path directorio filter en openFWPA
12.1.1. Implementación de un nuevo filtro
El proceso de implementación de un nuevo filtro que haga uso de la infraestructura facilitada por
openFWPA es muy sencillo. A continuación se detallan los pasos a seguir:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
227 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
•
Crear una clase Java que extienda la clase PrincastFilter.
•
Sobrescribir el método filter() para añadir la lógica de negocio del filtro.
Atención
El método que se debe sobrescribir es filter() y no doFilter() como se haría para escribir un
filtro normal. El método doFilter() es final en la clase PrincastFilter.
•
Crear un interfaz java que extienda el interfaz PrincastFilterMBean. Este interfaz debe tener
como nombre el de la clase Java que define el nuevo filtro seguido de MBean. Esto es
necesario para poder hacer uso de las facilidades JMX aportadas por openFWPA para la
gestión de los filtros. No es necesario que el nuevo interfaz tenga métodos.
•
Si se quiere implementar alguna lógica al inicializar el filtro, se debe extender el método
initFilter().
Atención
El método init() de la clase PrincastFilter es final, por lo tanto no se puede extender dicho
método.
Ejemplo de filtro disponible en la aplicación de ejemplo de openFWPA “sampleapp”.
/**
* Filtro Web que se encarga de extraer los principals de autenticación y,
* con ellos, crear un objeto UserContainer.
*/
public class LoginFilter extends PrincastFilter
implements LoginFilterMBean{
protected void filter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, resp);
return;
}
HttpServletRequest request = (HttpServletRequest) req;
UserVO user = new UserVO();
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
228 de
296
// Se obtiene el subject
Subject subject = (Subject) request.getSession(true).getAttribute(
SecurityGlobals.SUBJECT);
// Cargamos sus credenciales.
if (subject == null) {
// el usuario todavía no está autenticado
chain.doFilter(req, resp);
return;
}
UserContainer existingContainer = UserContainer
.getUserContainer(request);
// si ya cargue los datos anteriormente entonces retorno
if (existingContainer.getUserVO() != null) {
chain.doFilter(req, resp);
return;
}
UserVOLoader.populateUserVO(user, subject);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Se ha autentificado al usuario:\n"
+ user.toXML());
}
existingContainer.setUserVO(user);
chain.doFilter(req, resp);
}
}
Ejemplo de interfaz para el filtro anterior, sin métodos disponibles.
/**
* Interface MBean para el filtro LoginFilter.
*/
public interface LoginFilterMBean extends RegistrableMBean{
//Empty
}
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
229 de
296
12.1.2. Gestión de los filtros de forma dinámica
Una de las características más novedosas aportadas por openFWPA en cuanto a la gestión de los filtros
es que estos pueden ser conectados y desconectados “en caliente” utilizando para ello una consola
JMX. De esta forma, el administrador de la aplicación, en base a determinadas métricas de
rendimiento, puede decidir en un momento dado si desea tener un filtro que comprima la respuesta
enviada al cliente, arrancándolo o apagándolo sin necesidad de tener que para la aplicación para aplicar
la nueva configuración en el fichero web.xml.
12.1.3. Filtros activables por reglas
Los filtros que extienden PrincastFilter pueden ser desactivados para un conjunto determinado de
URLs.
Este tipo de filtros se pueden mapear sobre un patrón de URL (como cualquier otro filtro) pero es
posible definir un subconjunto de patrones de URL, para las cuales el filtro no entrará en acción.
Cada uno de los patrones de URL excluidos de la acción del filtro se definirá utilizando un “init
param”, en el fichero web.xml. Estos parámetros deben cumplir el siguiente convenio de nombrado:
“EXCLUDED.URL.<Identificador descriptivo del patrón>”.
<filter>
<filter-name>ExampleByRuleFilter</filter-name>
<filter-class>
es.princast.example.web.filter.ExampleFilter
</filter-class>
<init-param>
<param-name>EXCLUDED.URL.SELECCION</param-name>
<param-value>
/action/seleccionaExplotacion
</param-value>
</init-param>
<init-param>
<param-name>EXCLUDED.URL.LOGOUT</param-name>
<param-value>
/action/logout
</param-value>
</init-param>
</filter>
Además, utilizando la consola JMX, es posible actualizar, “en caliente”, los patrones de URLs que se
excluirán del efecto del filtro.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
230 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
12.2. Configuración del filtro SecurityFilter
Para el control de acceso de las aplicaciones que usen openFWPA se facilita un filtro al efecto.
Para poder hacer uso de este filtro es necesario definirlo en el fichero de configuración web.xml. Un
ejemplo de la configuración a añadir en este fichero se presenta a continuación:
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>
es.princast.framework.web.filter.security.corp.PrincastSecurityFilter
</filter-class>
</filter>
...
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
El filtro de seguridad se enmarca dentro del sistema de seguridad de openFWPA. Para más
información, puede revisar el apartado “15. Seguridad”, de este mismo documento.
12.3. Filtro de navegación
El Filtro de Navegación (clase NavigationFilter) tiene dos objetivos:
•
Mantener siempre el conocimiento de las entradas de menú (y submenú) activas, evitando la
necesidad de utilizar tecnologías del lado del cliente como JavaScript y Cookies.
•
Mantener el estado de la barra de navegación (Ver Sección 9.9.2, “Barra de navegación.”).
<filter>
<filter-name>NavigationFilter</filter-name>
<filter-class>
es.princast.framework.web.filter.navigation.NavigationFilter
</filter-class>
</filter>
...
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
231 de
296
<filter-mapping>
<filter-name>NavigationFilter</filter-name>
<url-pattern>/action/*</url-pattern>
</filter-mapping>
El Filtro de Navegación debe estar mapeado a todas las URLs referenciadas por alguna entrada de
menú o submenú.
El Filtro de Navegación, extrae de la Request los valores de los parámetros GET que indican la entrada
de menú y submenú activas y, a partir de ellas, se encarga de mantener el estado del menú y de la barra
de navegación, manteniéndolos siempre sincronizados.
Para conocer los nombres de los parámetros GET a los que tiene que acceder, el Filtro de Navegación
implementa el interface Configurable (es decir, es un objeto configurable por el sistema de
configuración de openFWPA) que escucha el contexto del menú (MENU.CONTEXT), lo que significa,
que no se requiere ninguna configuración especial para el Filtro de Navegación, siempre y cuando, se
configure convenientemente el menú.
12.4. Filtros de Activación
En ocasiones, es necesario poder activar (o desactivar) una aplicación o determinadas partes de la
misma, de forma declarativa. OpenFWPA incluye una clase base (ActivacionFilter) que facilita la
implementación de filtros Web para la gestión de la activación de las aplicaciones.
Básicamente este tipo de filtros tienen dos responsabilidades:
•
Determinar cuando la aplicación está activa (o no).
•
En caso de que la aplicación esté inactiva ejecutar alguna operación (generalmente
redireccionar a una página de aviso).
Para implementar filtros de activación es necesario extender la clase ActivationFilter. Los métodos
más relevantes de esta clase son:
•
isActive(). Determina cuando el recurso solicitado (URL) está activo. Este método devolverá
true si el recurso está activo. Se trata de un método abstracto y, por tanto, es de implementación
obligatoria por parte de las subclases.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
232 de
296
•
handleInactive(). Realiza la lógica correspondiente en caso de que el recurso solicitado por el
cliente no esté activo. La implementación por defecto redireccionará a una página previamente
configurada.
•
configure(). Los filtros de activación pueden ser configurados mediante el Sistema de
Configuración de openFWPA. Por defecto, todos los filtros de activación toman parámetros del
contexto "ACTIVATION.FILTER". Es posible cambiar el nombre del contexto utilizando el
parámetro de inicialización del filtro (init-param en web.xml) de nombre: "CONTEXT".
Dentro de este contexto, se puede definir una página de redirección (en caso de que el recurso
no esté activo), utilizando el parámetro "ERROR.URL".
12.4.1. Filtro de Temporalidad
El Filtro de Temporalidad permite activar/desactivar una aplicación (o partes de la misma) en función
de la fecha en la que se produzca el acceso.
El Filtro de Temporalidad (clase TimingFilter) es un filtro de activación y, por tanto, tiene todas sus
características.
El Filtro de Temporalidad permite que los recursos que protege estén activos únicamente durante
determinados intervalos temporales, definidos como parámetros de configuración. Estos parámetros
seguirán el siguiente convenio de nombrado: ACTIVE.INTERVAL.<id del intervalo>. El valor del
intervalo, se especificará siguiendo el convenio: <inicio intervalo> - <fin intervalo>, pudiendo
especificarse el inicio o el fin del intervalo de las siguientes formas:
•
Con una fecha, especificada según cualquier formato estándar válido (SimpleDateFormat). El
formato concreto a utilizar se define con el parámetro de configuración: DATE.FORMAT. Por
defecto vale: "dd/MM/yyyy HH:mm:ss".
•
Utilizando el carácter "?". En este caso, se supone que se trata de un intervalo abierto, cuyo
extremo no está especificado.
Algunos ejemplos de intervalos pueden ser:
ACTIVE.INTERVAL.1
ACTIVE.INTERVAL.2
ACTIVE.INTERVAL.3
ACTIVE.INTERVAL.4
=
=
=
=
Cluster TIC (www.clustertic.net)
22/01/2012 11:11:11 - 22/02/2012 11:11:11
22/04/2012 11:11:11 - ?
? - 22/01/2106 11:11:15
? - ?
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
233 de
296
13. Excepciones
OpenFWPA dispone de su propia jerarquía de excepciones. La política general de manejo de
excepciones en openFWPA es que se utilicen excepciones Runtime (no manejadas estáticamente).
71 jerarquía de excepciones
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
234 de
296
La clase base para la creación de excepciones es PrincastException. Existen dos ramas en esta
jerarquía de excepciones runtime:
•
Excepciones de sistema (PrincastSystemException), reservadas para openFWPA y sus
componentes.
•
Excepciones de modelo (PrincastModelException), que son disparadas por las excepciones.
Como norma general, las aplicaciones no deberían nunca extender las excepciones del sistema.
Siempre deben extender PrincastModelException.
Además, openFWPA también tiene una clase base para la creación de excepciones gestionadas:
PrincastRequiredHandlingException.
La excepción DeprecatedAPIException se reserva para ser disparada desde métodos deprecados en los
que no sea posible implementar una lógica alternativa.
13.1. Loggeo de las Excepciones en los DAO
A pesar de que no hace falta capturar las excepciones producidas en el acceso a datos, es recomendable
imprimir en el log de la aplicación, la excepción que se produce. Para ello, basta con definir dos spring
beans en el fichero dao-beans.xml, y las excepciones que se produzca quedan loggeadas
automáticamente.
<!-- Con estas dos definiciones se auditan todas las excepciones que se
produzcan en los DAOs a nivel de log de ERROR-->
<bean id="loggerThrowsAdvice"
class="es.princast.framework.facilities.interceptor.logger.LoggerThrowsAdvi
ce">
<property name="level"><value>ERROR</value></property>
</bean>
<bean id="daoBeanAutoProxy"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
">
<property name="beanNames"><value>*DAO</value></property>
<property name="interceptorNames">
<list>
<value>loggerThrowsAdvice</value>
</list>
</property>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
235 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
</bean>
La primera definición de bean loggerThrowsAdvice, indica la clase de log que se va a usar. La
propiedad más importante es el nivel de log, en el ejemplo se indica que las excepciones se van a
loggear a un nivel de ERROR (son válidos los mismos niveles de log que para log4j).
La segunda definición indica los beans a los que se va a aplicar el log, se aplican por nombre de bean.
En este caso se indica con un patrón "*DAO", esto quiere decir que el log se aplica a todos los métodos
de todos los beans que su identificador acabe en la cadena DAO. Aunque aquí se auditen los DAO, se
puede auditar cualquier otra clase por su definición de bean de Spring, por ejemplo todos los
"Delegate" con el patrón "*Delegate".
13.2. Excepciones durante el proceso de autenticación
En caso de que durante el proceso de autenticación se lance alguna excepción, ésta es almacenada en la
sesión del usuario bajo la clave LOGIN_EXCEPTION, que se puede encontrar en la clase
SecurityGlobals.
Pudiera darse el caso de querer mostrar un determinado mensaje de error en la capa de presentación en
función de la excepción que se haya producido. Para ello se proporciona un tag JSP denominada
<instanceOf> y que recibe los siguientes parámetros:
•
variableName. Nombre de la clave bajo la cual se busca la excepción.
•
className. Nombre cualificado de la excepción con la que se realiza la comprobación.
Un ejemplo de uso de esta etiqueta se presenta a continuación:
<princast:instanceOf variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.WrongPasswo
rdException">
<div id="errores">
<ul>
<li>
Validación incorrecta de NIF/NIE y Clave personal
</li>
</ul>
</div>
</princast:instanceOf>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
236 de
296
Como se puede apreciar se comprueba que la excepción que se encuentra almacenada en la clave
SecurityGlobals.LOGIN_EXCEPTION
sea
de
la
misma
clase
que
es.princast.framework.facilities.security.exceptions.WrongPasswordException. En caso afirmativo se
incluyen los elementos contenidos entre <princast:instanceOf></princast:instanceOf>. Las
excepciones que se pueden disparar durante el proceso de autenticación, se encuentran en el core de
openFWPA en el paquete: es.princast.framework.facilities.security.exceptions.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
237 de
296
72 Path del paquete de excepciones para el proceso de autenticación
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
238 de
296
14. Informes
La
generación
de
informes
se
basa
en
el
proyecto
JasperReports
(http://jasperforge.org/projects/jasperreports) JasperReports es una librería de clases que puede verse
como un motor de reporting para desarrollos java. El principal objetivo de este proyecto es facilitar la
construcción de documentos con contenido dinámico y su visualización en diferentes formatos.
JasperReports organiza la información que le servirá para generar los documentos en forma de fichero
XML. El fichero XML, de acuerdo al DTD, es visto como el diseño del informe. Una vez en
disposición de un diseño XML válido, es necesario realizar un proceso de compilación, que generará
un objeto que es serializado, y podría ser almacenado en disco con extensión .jasper. La compilación
validará todas las expresiones java que pudieran estar embebidas en el XML. Una vez compilado, y
para proveer al informe con datos dinámicos, se realiza el proceso de completado (fill). Este proceso
puede recibir diferentes fuentes de datos, entre ellas conexiones a bases de datos relacionales
(instancias de clase Connection), colecciones o arrays de Beans (instancias de clase JRDataSource de
la librería de JasperReports) o fuentes de datos personalizadas, extendiendo el interface JRDataSource.
Otra forma de pasar información dinámica a los documentos es a través de parámetros de informe, que
forman parte del diseño XML y pueden ser establecidos por programación, e incluso tener valores por
defecto en diseño.
Posibilita la salida de informes a pantalla, impresora o a fichero en diversos formatos (PDF, HTML,
CSV, XML).
73 Vision general (jasperReports)
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
239 de
296
14.1. Creación de diseños XML
El proyecto JasperReports no provee de ninguna herramienta adicional que facilite la labor de la
creación de los ficheros XML. En este punto, un desarrollador que pretenda crear el diseño XML de un
documento necesario para su aplicación, debería crearse el fichero XML desde un editor de texto, o
editor XML. Evidentemente, esto es una tarea tediosa y poco operativa.
Más bien se necesitaría otra herramienta que facilitara la labor de visualizar, compilar y generar el
XML del documento que se está diseñando, una herramienta visual del tipo WYSIWYG. Existen
varias herramientas de este tipo desarrolladas como proyectos abiertos.
El desarrollador es libre de elegir su herramienta preferida; el openFWPA no provee de ninguna de
ellas, aunque se han realizado las pruebas con el proyecto iReport-Designer for JasperReports
(http://jasperforge.org/projects/ireport)
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
240 de
296
74 iReport
14.2. La herramienta iReports
La herramienta iReports es un editor visual de ficheros XML listos para ser usados por el motor de
reporting JasperReports. Trabaja en modo standalone (aplicación de ventana de java) y tiene un
interfaz claro. En la página del proyecto http://jasperforge.org/projects/ireport puede obtenerse una
amplia documentación sobre como manejar esta herramienta, e incluso un video tutorial que muestra
algunos de los aspectos más interesantes sobre ella.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
241 de
296
Al estar estrechamente relacionada con JasperReports, es necesario conocer los aspectos en que este
último organiza su información (bandas, grupos, subreports, parameters, fields, variables…) para
optimizar el manejo de la herramienta visual.
14.2.1. Visión general de la Interfaz
75 iReport (Visión general de la interfaz)
14.2.2. Compilar y establecer programas externos
Una vez instalado el iReport, lo primero que habría que hacer es establecer los programas externos que
se utilizarán. Para ello hay que ir a la opicón de Menú
Opciones
Opciones
Pestaña programas
externos.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
242 de
296
En la pestaña Compilador podremos establecer el directorio de compilación por defecto (donde nos
generará los ficheros .jasper asociados a los reports).
Los .jasper asociados a los reports en OpenFWPA tienen que estar en la carpeta del proyecto WEBINF/reports, por lo tanto, se le puede establecer esta carpeta como directorio de compilación.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
243 de
296
Otra forma de compilar los ficheros xml asociados a los informes es ejecutar la tarea de ant:
“compile.report”, que está en el fichero build.xml de la carpeta src/main/java/buid.xml.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
244 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
14.2.3. Nuevo informe con iReports
Opción de menú Fichero
Nuevo documento
Aquí deberá definirse el nombre del reporte, tamaño de la pantalla, orientación, márgenes, etc.
76 Propiedades del informe
La apariencia del layout (plantilla) de la página del informe es la siguiente:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
245 de
296
77 Layaout de la página del informe
Donde:
• title: Aparece sólo al inicio del reporte. El título se escribe en está sección. Ejemplo: “Reporte
de Desempeño de los empleados”
• pageHeader: Aparece en la parte superior de cada página. Puede contener información como la
fecha y hora, nombre de la organización, etc.
• columnHeader: Sirve para listar los nombres de los campos que se van a presentar (desplegar).
Por ejemplo: “Nombre del Empleado”, “Hora de Entrada”, “Hora de Salida”, “Horas
trabajadas”, “Fecha”, etc.
• Detail: En esta sección se despliegan los valores correspondientes a las entradas de campos
definidas en la sección anterior. Por ejemplo “Juan Perez”, “09:00”, “18:00”, “9”,”2005-0427”.
• columnFooter: Puede presentar información sumarizada para cada uno de los campos. Por
ejemplo “Total de Horas Trabajadas: 180”
• pageFooter: Aparece en la parte inferior de cada página. Este parte puede presentar, el
contador de páginas como “Página 1/7”
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
246 de
296
• summary: Esta sección se usa para proporcionar información sumarizada de los campos
presentes en la sección “detail” por ejemplo para el caso de las horas trabajadas de cada
empleado se puede definir un objeto gráfico tipo “pie” para tener una mejor comparación y
comprensión visual de los datos.
Los objetos de texto, imágenes,…, pueden ser colocados en la plantilla del documento usando el
método de arrastrar y pegar.
Para insertar texto puro usar:
Para insertar campos (Fields) usar:
14.2.4. Parametros en iReport
Opción de Menú Ver Parámetros.
Los parámetros son una buena forma de añadir datos dinámicos al informe y parametrizar éste, de
forma que se puedan visualizar elementos según el valor o rango de algún parámetro, e incluso
modificar la consulta SQL según parámetros. Los parámetros añaden más flexibilidad a la generación
de los informes, hasta el punto de que es posible crear informes sin fuente de datos, y que toda su
información llegue por parámetros.
Un parámetro tiene un nombre, un tipo (clase java seleccionable de una lista) y opcionalmente un valor
por defecto (expresión java que será compilada en el proceso de compilación y evaluada en el proceso
de completado del informe) Los parámetros son referencias a objetos que son pasadas al proceso de
completado (fill) del informe. Su uso, como ya se ha comentado, servirá para enviar información al
motor de reporting que no puede ser encontrada en la fuente de datos (DataSource).
Los parámetros se identifican en el fichero XML por construcciones similares a la siguiente:
<parameter name="ejemplar_para" isForPrompting="false" class="java.lang.String">
<defaultValueExpression >
<![CDATA[new String("Ejemplar para ... por defecto")]]>
</defaultValueExpression>
</parameter>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
247 de
296
En el entorno de iReports, se puede hacer referencia a este parámetro mediante la construcción
$P{ejemplar_para}
78 iReport - Declaración de parámetros
14.2.5. Fields
Los fields representan la forma de mapear campos en el diseño del report con datos de la fuente de
datos. Si el DataSource es una base de datos, entonces el mapeo es directo con los nombres de campos
en una o varias tablas. Si el DataSource es una collección de Beans, el mapeo se realizará con las
property´s de éstos.
Un Field se puede idetificar en el XML por una construcción como:
<field name="DL_FINALIDAD" class="java.lang.String"/> En el entorno de iReports se le
puede hace referencia como $F{DL_FINALIDAD}
14.2.6. Variables
Se declaran como expresiones en java, y más tarde pueden ser usadas de forma masiva. Pueden servir
como forma de no repetir código. Tambíen se utilizan para realizar cálculos. Exiten funciones built-in
que facilitian algunas tareas de cálculo, como Count, Sum, Average, Lowest, Highest y
StandardDeviation. Las variables serán reinicializadas según la jerarquía de niveles: Report, Page,
Column y Group.
Exiten una serie de variables inherentes a todo informe (built-in variables), a las que se puede hacer
referencia en todo momento:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
248 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
• PAGE_NUMBER
• REPORT_COUNT
• COLUMN_COUNT
En el entorno de iReports se les puede hace referencia como $V{NOMBRE_DE_VARIABLE}
14.3. Clases del OpenFWPA para la renderización de informes
En openFWPA se han incluido dos clases para la generación de informes: PrincastReport y
PrincastMultiReport. La primera permite generar informes simples y la segunda de ellas, crear multireports a partir de la agregación de varios informes sencillos.
79 API informes openFWPA
14.3.1. Informes simples
Para crear un informe simple se usará la clase PrincastReport. Para poder crear un PrincastReport, es
necesario indicarle, en su constructor, los parámetros:
• Nombre del informe: El informe debe tener un nombre. Este nombre puede ser el que se
utilice para generar un fichero PDF.
• Fuente de datos: El origen de datos para cargar el informe también debe ser especificado. Por
defecto, se utilizará el origen de datos nulo: JREmptyDataSource. El informe no tomará datos
de ninguna fuente.
• Report compilado: Se debe suministrar un stream de entrada (InputStream) que permita leer la
definición compilada del informe. Este stream debe estar abierto sobre un fichero .jasper.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
249 de
296
Además, si en el diseño del informe se han definido parámetros, sus valores deben ser especificados al
PrincastReport utilizando el método setParams(Map).
Antes de obtener el informe es MUY recomendable pregenerarlo (para validar que no se producen
errores antes de exportar el informe). Para pregenerar un informe se debe utilizar el método process().
Para obtener un informe de un PrincastReport (correctamente creado y con los parámetros que necesite
asignados) se puede utilizar uno de los siguientes métodos:
• getReportToPrint(). Devuelve el objeto jasper imprimible: JasperPrint. Este objeto puede ser
manejado por las clases de Jasper Reports (se puede exportar a múltiples formatos, imprimir,
etc.)
• getPDFContent(). Devuelve el informe exportado a formato PDF, en un array de bytes, listo
para ser volcado a un fichero (o enviado a un cliente, etc.)
• exportPDF(OutputStream). Exporta el informe, en formato PDF, al OutputStream que se
pasa como parámetro.
A continuación se muestra un ejemplo de construcción de un PrincastReport.
//Obtener el fichero del Report (.jasper)
InputStream stream = loadReport(REPORT_NAME+".jasper");
//Obtener origen de datos
List listaProducto =
CarritoDelegateFactory.getCarritoDelegate().getListaProducto();
JRDataSource dataSource = new JRBeanCollectionDataSource(listaProducto);
//Obtener parametros
Map parameters = new HashMap();
MessageResources
messages
=
(MessageResources)
request.getAttribute(Globals.MESSAGES_KEY);
parameters.put("P_Titulo", messages.getMessage("report.title"));
parameters.put("P_AmpliacionTitulo",
messages.getMessage("report.description"));
//Crear report
PrincastReport
report
=
new
stream);
report.setParams(parameters);
report.process();
Cluster TIC (www.clustertic.net)
PrincastReport(REPORT_NAME,
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
dataSource,
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
250 de
296
14.3.2. Multi Reports
Los Multi-reports son informes compuestos de informes simples. El objetivo de los multireports es
agrupar un conjunto de informes para que puedan ser volcados en un mismo fichero PDF.
El openFWPA incluye la clase PrincastMultiReport para la generación de informes compuestos. Esta
clase es muy simple de manejar: basta con especificarle un nombre (para el fichero PDF) y añadir
todos los informes simples que se quieran adjuntar con el método addReport(PrincastReport report).
Los multi-reports también deben ser procesados, al igual que los informes simples, utilizando el
método process().
El informe se puede obtener con el método getPDFContent() que, al igual que en la clase
PrincastReport, devuelve un array de bytes con el informe en formato PDF, listo para ser volcado a un
fichero. También se puede exportar con el método exportPDF(OutputStream).
14.3.2.1. Forma de actuar:
• Crear un objeto PrincastMultiReport
• Crear todos los reports simples que se necesiten
• Añadirlos con addReport
14.3.3. Las fuentes de datos de los informes.
Los informes visualizarán contenido dinámico, provenientes de dos tipos diferentes de fuentes de
datos:
• DataSources JDBC Connection: conexión con una base de datos relacional.
• JRDataSources: fuentes de datos JasperReports. La librería de clases de Jasper Reports provee
de una serie de implementaciones de este tipo de fuentes de datos. Las más interesantes son
aquellas que gestionan collecciones de Beans java (en forma de Collection, Array o Map de
Beans). Es recomendable el uso de estas fuentes de datos, en detrimento de las anteriores, ya
que de esta forma no se rompe la encapsulación de las capas de la aplicación.
14.3.4. Utilizando JasperReports en Linux / Unix sin X11.
ADVERTENCIA: No es posible generar informes con imágenes (escudos, marcas de agua, códigos de
barras, etc.) en un entorno Unix/Linux sin las librerías X11.
14.3.5. Clase para la generación de tablas en PDF.
El FW-PA incluye la clase PDFTableExporter para la generación de informes PDF en forma de tabla,
de esta manera es posible realizar de una manera sencilla listados en PDF. Para usar esta clase se hará
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
251 de
296
en combinación con una PrincastPDFReportAction, sobrescribiendo el método getReport(). Un
ejemplo de su uso es el siguiente:
// número de columnas de la tabla, las filas se ajusta automáticamente
int columnas = 3;
// nombre del report
String REPORT_NAME = "tabla";
PDFTableExporter
columnas);
tableExporter
=
new
PDFTableExporter(REPORT_NAME,
// se establece el título del report
tableExporter.setTitle("Mi título");
// se añaden celdas de cabecera (aparecen sombreadas)
tableExporter.addCellHeader("Enero");
tableExporter.addCellHeader("Febrero");
tableExporter.addCellHeader("Marzo");
// se añaden las celdas de la tabla
tableExporter.addCell("1");
tableExporter.addCell("2");
tableExporter.addCell("3");
// se retorna el objeto
return tableExporter;
14.4. Ejemplo de creación de infome con openFWPA
En los próximos apartados mostraremos como se diseña un informe con openFWPA. Este informe se
encuentra en la aplicación de ejemplo (sampleapp) que se distribuye con openFWPA.
14.4.1. Diseñar con iReports y obtener XML
Declaramos los Fields (campos del informe) que vamos a utilizar: opción de Menú Ver
informe.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
Campos del
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
252 de
296
80 campos del informe
Declaramos los parámetros que vamos a utilizar: opción de Menú Ver
Declaramos las variables que vamos a utilizar: opción de Menú Ver
Cluster TIC (www.clustertic.net)
Parámetros del informe.
Variables del informe.
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
253 de
296
Conformamos el informe con todas las imágines, campos de texto, field, parámetros, …
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
254 de
296
81 Página del informe
14.4.2. Guardar el XML
Copiamos o guardamos el xml asociado a la página del informe en la carpeta src/main/jasperreports:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
255 de
296
82 Ubicación de ficheros XML
14.4.3. Compilación
Una vez compilado el informe anterior obtenemos el fichero .jasper que tiene que estar ubicado en la
carpeta src/main/webapp/WEB-INF/reports.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
256 de
296
83 Ubicación de ficheros .jasper
Para compilar el informe podemos configurar el iReport para que compile directamente en esa ruta o
ejecutar la tarea de Ant “compile.reports.”
14.4.4. Crear clase Action que extienda PrincastPDFReportAction (abstracta)
Las clases Actions asociadas a los informes se encuentran ubicadas en:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
257 de
296
A continuación mostramos el código fuente de la clase ProductosPDFReportAction donde
sobrescribimos el método getReport() para obtener un PDFProvider:
import
import
import
import
java.io.InputStream;
java.util.HashMap;
java.util.List;
java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import
import
import
import
org.apache.struts.Globals;
org.apache.struts.action.ActionForm;
org.apache.struts.action.ActionMapping;
org.apache.struts.util.MessageResources;
import
import
import
import
import
es.princast.framework.core.exceptions.PrincastModelException;
es.princast.framework.facilities.providers.PDFProvider;
es.princast.framework.facilities.reports.PrincastReport;
es.princast.framework.web.action.report.PrincastPDFReportAction;
es.princast.sampleapp.web.delegate.CarritoDelegate;
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
258 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
/**
* Action para generar un informe PDF con la lista de productos
*/
public class ProductosPDFReportAction extends PrincastPDFReportAction {
// inyeccion de dependencia (WEB-INF/beans/web/action-defs.xml)
/**
* El delegate que permite obtener la lista de productos
*/
protected CarritoDelegate carritoDelegate;
/**
* Asigna el delegate que permite obtener la lista de productos
*
* @param carritoDelegate el delegate que gestiona el carrito
*/
public void setCarritoDelegate(CarritoDelegate carritoDelegate) {
this.carritoDelegate = carritoDelegate;
}
/**
* El nombre del informe a generar
*/
private final static String REPORT_NAME = "productosReport3";
protected void catchException(Exception e, ActionMapping arg1,
ActionForm arg2, HttpServletRequest arg3,
HttpServletResponse arg4) {
//En este método habrÃ-a que tratar la excepción.
//Por ejemplo, redireccionar a pagina de error.
throw new PrincastModelException(e, "Al ejecutar lógica", "");
}
protected PDFProvider getReport(HttpServletRequest request,
HttpServletResponse response, ActionForm form, ActionMapping mapping)
{
//Obtener el fichero del Report (.jasper)
InputStream stream = loadReport(REPORT_NAME+".jasper");
//Obtener origen de datos
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
259 de
296
List listaProducto = carritoDelegate.getListaProductoPDF();
JRDataSource dataSource =
new JRBeanCollectionDataSource(listaProducto);
//Obtener parametros
Map parameters = new HashMap();
MessageResources messages =
(MessageResources) request.getAttribute(Globals.MESSAGES_KEY);
parameters.put("P_Titulo", messages.getMessage("report.title"));
parameters.put("P_AmpliacionTitulo",
messages.getMessage("report.description"));
//Crear report
PrincastReport report =
new PrincastReport(REPORT_NAME, dataSource, stream);
report.setParams(parameters);
report.process();
return report;
}
}
14.4.5. Resultado final
De la aplicación de ejemplo (sampleapp) podemos generar el informe que hemos construido desde:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
260 de
296
84 Listado de productos
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
261 de
296
85 Ejemplo de informe
15. Seguridad en aplicaciones con openFWPA
15.1. Seguridad
En el apartado Seguridad se contemplan todas las políticas y herramientas que permiten, tanto
controlar (y monitorizar) el acceso a determinadas partes de una aplicación, como aquellas que
permiten garantizar la integridad y confidencialidad de los datos que se transmiten.
Los conceptos más importantes dentro del control de acceso a una aplicación son la Autentificación y
la Autorización.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
262 de
296
La Autentificación es el proceso mediante el cual los privilegios de acceso de un usuario son
comprobados antes de que pueda tener acceso a un área protegida de la aplicación. Dentro de la
autentificación se pueden distinguir diferentes alternativas, siendo las más recurridas la básica (Basic
authentication) y la basada en formulario (Form-based authentication).
15.1.1. Autentificación básica
La autentificación básica delega el control de acceso al servidor Web. El usuario podrá navegar
libremente por el sitio Web sin necesidad de facilitar una contraseña. Sin embargo, cuando se intente
acceder a una página protegida será el propio navegador el que solicite al usuario un nombre de
usuario (username) y una contraseña (password) mostrándole una ventana de diálogo.
Tanto el nombre de usuario como la contraseña son enviados sin encriptar al servidor Web, quien se
encarga de validarlos contra un fichero plano, un base de datos o servidor de directorios.
Si el usuario consigue validarse se comprueba que se tenga privilegio suficiente para acceder al
recurso basándose en ciertas políticas definidas, por ejemplo, en un fichero tipo http.conf. Si la
comprobación es positiva se sirve la página al cliente. En caso contrario, se le solicita de nuevo la
combinación usuario/contraseña o se le muestra una página de error denegando el acceso.
15.1.2. Autentificación basada en formulario
Suele ser la alternativa más usada por los sitios Web dada su sencillez. Al igual que en la
autentificación básica, el usuario puede navegar libremente por los recursos desprotegidos. En el
momento que se intenta acceder a un área protegida se redirecciona al usuario a una página de login
con un formulario con los campos nombre de usuario y contraseña.
Esta autenticación está implementada como un filtro de URLs y se integra con las APIs Java de
Seguridad (JAAS).
15.1.3. Autentificación basada en el Filtro de Seguridad de openFWPA
La autentificación basada en el Filtro de Seguridad, es la opción estándar propuesta por openFWPA
para el control de acceso. Este tipo de autenticación se basa en un Servlet Filter que se encarga de
gestionar tanto el control de acceso como los protocolos de seguridad http/https) a utilizar.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
263 de
296
86 Esquema del sistema de autenticación
Como resultado del proceso de autenticación y autorización, el Filtro de Seguridad de openFWP, pone
a disposición de las aplicaciones todos los datos obtenidos en dicho proceso.
Para utilizar la autenticación de openFW-PA, se tendrán que tener en cuenta los siguientes puntos:
•
Configuración del Contenedor. El contenedor debe estar configurado convenientemente para
permitir el acceso a las aplicaciones bajo el protocolo HTTPS y utilizando sockets SSL-3 (https
con certificado digital).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
264 de
296
•
Uso de la seguridad Web J2ee estándar. En la clase HttpServletRequest, se puede interrogar
por las credenciales del usuario para realizar la autenticación.
•
Configuración. Es necesario definir los plugins de configuración adecuados.
•
Paso de credenciales. Usando una extensión de la clase Principal, donde se proporcionan a la
aplicación todos los parámetros que se recogieron durante el proceso de autenticación.
•
Diseño de páginas de login. Las aplicaciones necesitan mostrar a los usuarios páginas que les
permitan introducir todos los datos necesarios para su autentificación. Estas páginas deben
tener unas características determinadas para poder integrarse con la seguridad de openFWPA.
15.1.3.1. Integración con seguridad Web J2EE
En la clase javax.servlet.http.HttpServletRequest hay tres métodos para controlar el acceso a recursos
de la aplicación. Los siguientes párrafos se han extraído de la documentación de la versión 1.3 (JDK
1.3):
•
java.lang.String getRemoteUser(). Returns the login of the user making this request, if the user
has been authenticated or null if the user has not been authenticated.
•
java.security.Principal getUserPrincipal(). Returns a java.security.Principal object containing
the name of the current authenticated user.
•
boolean isUserInRole(java.lang.String role). Returns a Boolean indicating whether the
authenticated user is included in the specified logical "role".
El método getRemoteUser devuelve el nombre del usuario que realiza la httpRequest. Es equivalente a
(PrincastIdentifier)getUserPrincipal()).getId()(ver abajo).
El método getUserPrincipal devuelve el Principal más importante (DNI) – en este aso, como una
instancia de la clase PrincastIdentifier. Soporta el método getName() definido en Principal) y getId()
(definido en PrincastIdentifier). getName() devuelve la cadena “DNI” y getId() devuelve el DNI del
usuario.
Para la gestión de roles (isUserInRole()) se emplean los roles asignados en el esquema e empleado
público. Los roles son tanto para ciudadanos como para empleados públicos.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
265 de
296
15.1.3.2. Configuración
El sistema de seguridad estándar se configura utilizando el Sistema de Configuración de openFWPA.
Todo el sistema tomará parámetros del contexto de seguridad llamado “SECURITY”, por lo tanto, es
importante recordar que cualquier plugin que sirve parámetros al sistema de seguridad debe registrarse
para el contexto “SECURITY”.
15.1.3.2.1. Parámetros básicos
Los parámetros básicos son:
•
app-config. Bajo este parámetro debe indicarse el nombre de la aplicación. Este es el nombre
de la configuración JAAS que se utilizará para realizar la autenticación.
•
http.PORT. Puerto http que se utiliza para acceder a la aplicación. Si no se especifica este
parámetro, se utilizará el puerto por defecto (80).
•
https.PORT. Puerto https que se utiliza para acceder a la aplicación. Si no se especifica este
parámetro se utilizará el puerto SSL (443) por defecto.
•
https/cert.PORT. Puerto https (SSL-3) con certificado digital de cliente, que se utiliza para
acceder a la aplicación. Si no se especifica este parámetro se utilizará el puerto SSL (443) por
defecto.
•
http.IP. Dirección IP (o nombre DNS) del servidor que atiende peticiones http. Si no se
especifica este parámetro, la redirección se realizará sobre la IP del propio contenedor.
•
https.IP. Dirección IP (o nombre DNS) del servidor que atiende peticiones https (SSL v2), con
certificado de servidor. Si no se especifica este parámetro, la redirección se realizará sobre la IP
del propio contenedor.
•
https/cert.IP. Dirección IP (o nombre DNS) del servidor que atiende peticiones https (SSL v3),
con certificado de cliente. Si no se especifica este parámetro, la redirección se realizará sobre la
IP del propio contenedor.
Por ejemplo:
<bean id="baseConfigurationPlugin"
class="es.princast.framework.core.configuration.plugins.PropertiesFileConfi
gurationPlugin">
<constructor-arg><value>basePlugin</value></constructor-arg>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
266 de
296
<property name="file"><value>ejemplo.properties</value></property>
<property name="contexts">
<list>
<value>SECURITY</value>
<value>ROOT.CONTEXT</value>
<value>ACTION.CONTEXT</value>
<value>JMX.CONTEXT</value>
</list>
</property>
</bean>
Siendo el contenido del fichero carrito.properties, el que sigue:
#
#Fri Jan 07 10:08:36 CET 2005
CARRITO.AGENCIA=Manin Directo.
app-config=Carrito
DEFAULT.MENU=MenuMiPerfil
ITEM.SEPARATOR = >
JMX.SERVER.NAME = SampleApp
#PERFORMANCE.TEST.MODE = ON
URL_LOGOUT=/carrito
#Configuracion de cache
CACHE_CONF=classpath:/ehcache.xml
#Tamaño de página para displayTag
PAGE_SIZE=10
Y el contenido del fichero global.properties, el que sigue:
#
#Fri Jan 07 10:08:36 CET 2005
HIT.COUNTER=es.princast.framework.core.management.mcounters.historic.Histor
icalCounter
ACTION_MGMT=es.princast.framework.web.action.monitoring.PrincastActionMgmtI
nterfaceImpl
LOGGING_XMLCONF=WEB-INF/log4j.xml
http.PORT=8082
https.PORT=8447
https/cert.PORT=8447
ITEM.SEPARATOR = /
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
267 de
296
#JMX.SERVER.ADAPTOR
es.princast.framework.core.management.adapters.JMXRIMBeanServerAdapter
JMX.SERVER.ADAPTOR
es.princast.framework.core.management.adapters.OC4JMBeanServerAdapter
=
=
Ambos ficheros (carrito.properties y global.properties) se encuentran en el directorio WEB-INF de la
aplicación de ejemplo “sampleapp”.
87 Path de los ficheros carrito.properties y global.properties
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
268 de
296
15.1.3.2.2. Configuración JAAS
El sistema de autenticación de openFWPA está basada en el estándar JAAS (Java Authentication and
Authorization Service).
En realidad, el Filtro de Seguridad, no realiza ninguna tarea de autenticación. Estas funciones son
delegadas en un Módulo de Login JAAS (LoginModule). La configuración del módulo a utilizar para
autenticar y autorizar usuarios se realiza a través del plug-in de configuración JAAS
(JAASConfigurationPlugin), que debe ser declarado en el fichero de inicialización princast-initscript.xml.
Por ejemplo:
<bean id="jaasConfigPlugin"
class="es.princast.framework.facilities.security.jaas.config.JAASConfigurat
ionPlugin">
<constructor-arg><value>jaas-config</value></constructor-arg>
<property
name="file"><value>WEB-INF/jaasconfig.xml</value></property>
<property name="contexts">
<list>
<value>SECURITY</value>
</list>
</property>
</bean>
Los módulos JAAS se configuran, en el openFWPA, mediante el fichero jaas-config.xml, disponible en
el directorio WEB-INF de la aplicación de ejemplo “sampleapp”, como se puede ver a continuación:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
269 de
296
88 Path del fichero jaas-config.xml
A continuación se muestra el contenido de este fichero incluido en la aplicación de ejemplo
“sampleapp”.
<!DOCTYPE jaas
PUBLIC "-//Framework PA - Team//DTD JAAS Configuration 1.3F//ES"
"jaas-config.dtd">
<jaas>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
270 de
296
<application name="Carrito" controlFlag="required">
<module>es.princast.framework.modules.security.standalone.StandaloneL
oginModule</module>
<options>
<option>
<name>USERS.FILE</name>
<value>WEB-INF/authorized-users.xml</value>
</option>
<option>
<name>LOOKUP.FILE.MODE</name>
<value>WEBAPP.CONTEXT</value>
</option>
</options>
</application>
</jaas>
En este fichero se definen los módulos de configuración a utilizar. Cada módulo se define con la
etiqueta <application ..>. Cuando se vaya a autenticar a un usuario, se utilizará el módulo cuyo valor
del atributo “name” coincida con el parámetro app-config (de los parámetros básicos de autenticación,
ver sección anterior).
Eventualmente, el atributo “controlFlag” está desactivado. No se tiene en consideración el valor
especificado para realizar la autenticación.
Para cada módulo, es obligatorio indicar el nombre de la clase que implementa la lógica de
autenticación, utilizando la etiqueta anidada: <module>. Esta clase debe implementar el interface
LoginModule, definido en el paquete JAAS. Por último, en la etiqueta <options> se pueden definir
todas las opciones de configuración específicas del módulo JAAS que se vaya a utilizar.
Por defecto, en la aplicación de ejemplo y en la aplicación en blanco, las credenciales de los usuarios
están definidas en el fichero WEB-INF/authorized-users.xml.
A continuación se muestra el contenido del fichero autorized-user.xml incluido en la aplicación de
ejemplo “sampleapp”.
<!DOCTYPE users
PUBLIC "-//Framework PA
1.3F//ES"
"authorized-users.dtd">
-
Team//DTD
Authorized
Users
Configuration
<users>
<user username="cliente" password="cliente" type="CITIZEN">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
271 de
296
<principals>
<principal name="USERNAME" value="cliente"/>
<principal name="SURNAME1" value="Lopez"/>
<principal name="SURNAME2" value="Otro"/>
<principal name="NIF/NIE" value="12345678Z"
identifier="true"/>
<principal name="ID THIRD PARTY" value="12345"/>
<principal name="AGENT USER TYPE" value="CITIZEN USER
TYPE"/>
<principal name="ORGANIZATIONAL UNIT ID" value="1001"/>
<principal name="ORGANIZATIONAL UNIT NAME"
value="Consejería de Infraestructuras"/>
</principals>
<roles>
<role name="Citizen">
<domainRole name="grupo1" value="grupo1"
procedure="no"/>
</role>
</roles>
</user>
<!—
Ejemplo de citizen para escenario de autenticación con nivel 0.5
-->
<user username="28356558L" password="01/01/2010" type="CITIZEN">
<principals>
<principal name="USERNAME" value="interop"/>
<principal name="SURNAME1" value="Uno"/>
<principal name="SURNAME2" value="Otro"/>
<principal name="NIF/NIE" value="28356558L"
identifier="true"/>
<principal name="ID THIRD PARTY" value="12345"/>
<principal name="AGENT USER TYPE" value="CITIZEN USER
TYPE"/>
<principal name="ORGANIZATIONAL UNIT ID" value="1001"/>
<principal name="ORGANIZATIONAL UNIT NAME"
value="Consejería de Infraestructuras"/>
<!-- Principals nuevos -->
<principal name="NATIONALITY" value="Spain"/>
<principal name="SEX" value="Male"/>
<principal name="DATE OF BIRTH" value="01/01/1970"/>
<principal name="LOCALITY OF BIRTH" value="Madrid"/>
<principal name="PROVINCE OF BIRTH" value="Madrid"/>
<principal name="NAME OF FATHER" value="Jose"/>
<principal name="NAME OF MOTHER" value="Ines"/>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
272 de
296
<principal name="LOCALITY OF ADDRESS" value="Madrid"/>
<principal name="PROVINCE OF ADDRESS" value="Madrid"/>
<principal name="STREET OF ADDRESS" value="Calle Mayor"/>
<principal name="EXPIRY DATE OF NIF/NIE"
value="01/01/2011"/>
</principals>
<roles>
<role name="Citizen">
<domainRole name="grupo1" value="grupo1"
procedure="no"/>
</role>
</roles>
</user>
</users>
15.1.3.2.3. Reglas de Seguridad
Por último, es necesario configurar las reglas de seguridad que definirán que recursos de la aplicación
están protegidos, y de que forma. Un recurso sólo puede estar protegido una vez. Si una URL encaja
en varios patrones definidos en el fichero de reglas de seguridad, se tendrá en cuenta el patrón más
restrictivo.
Para configurar las reglas de seguridad, se debe definir, en el fichero princast-init-script.xml, un plugin de configuración de tipo: SecurityRulesConfigurationPlugin.
Por ejemplo:
<bean id="securityRulesPlugin"
class="es.princast.framework.web.filter.security.corp.conf.SecurityRulesCon
figurationPlugin">
<constructor-arg><value>security-rules</value></constructor-arg>
<property name="file">
<value>WEB-INF/princast-security-rules.xml</value>
</property>
<property name="contexts">
<list>
<value>SECURITY</value>
</list>
</property>
</bean>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
273 de
296
Las reglas de seguridad se definirán, por su lado, en el fichero princast-security-rules.xml, disponible
en el directorio WEB-INF:
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
274 de
296
89 Path del fichero princast-security-rules.xml
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
275 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
A continuación vemos el contenido del fichero princast-security-rules.xml disponible en la aplicación
de ejemplo sampleapp:
<!DOCTYPE resources
PUBLIC "-//Framework PA - Team//DTD
1.3F//ES"
"princast-security-rules.dtd">
Security
Rules
Configuration
<resources>
<!-- Acceso para ciudadanos -->
<resource actor="CITIZEN" level="0">
<url-pattern>/*</url-pattern>
</resource>
<resource actor="CITIZEN" level="0">
<url-pattern>/action/viewlistaproductoxml</url-pattern>
</resource>
<resource actor="CITIZEN" level="1">
<url-pattern>/action/*</url-pattern>
<forwards>
<forward name="login" path="/pages/login.jsp" />
<forward name="error" path="/pages/error.jsp" />
<forward name="no-login" path="/pages/login.jsp" />
<forward name="no-roles" path="/pages/noroles.jsp" />
</forwards>
</resource>
<resource actor="CITIZEN" level="1">
<url-pattern>/dwr/*</url-pattern>
<forwards>
<forward name="login" path="/pages/login.jsp" />
<forward name="error" path="/pages/error.jsp" />
<forward name="no-login" path="/pages/login.jsp" />
<forward name="no-roles" path="/pages/noroles.jsp" />
</forwards>
</resource>
</resources>
En este fichero, cada etiqueta <resource> define un recurso protegido. Un recurso tiene tres atributos:
actor, nivel de seguridad y protocolo.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
276 de
296
El atributo “actor” define el usuario-tipo que va a acceder al recurso. En función de este valor, el
proceso de autenticación puede ser diferente. La semántica exacta de este atributo la establece el
módulo JAAS que realice la autenticación.
El atributo “level”, define el nivel de protección establecido para el recurso. Generalmente, hay 3:
• nivel 0 para recursos sin protección.
• nivel 1 para recursos protegidos bajo par usuario/contraseña.
• nivel 2 para recursos protegidos con certificado digital.
Generalmente, un nivel de seguridad permite el login por los mecanismos para sí definidos y también
mediante los definidos para niveles superiores. Por ejemplo, un recurso protegido bajo
usuario/contraseña también será accesible con certificado digital. La semántica exacta del nivel de
seguridad, la define el módulo JAAS.
El protocolo (atributo “protocol”) define el tipo de acceso deseado al recurso. Puede tomar dos
valores: “http” si no se quiere ninguna encriptación del recurso o “https” si se desea garantizar la
privacidad de los datos transmitidos entre el cliente y la aplicación. Este atributo puede omitirse, en tal
caso, se permite el acceso al recurso bajo cualquier protocolo.
Un recurso protegido es, exactamente, un patrón URL que se aplica sobre el espacio de direcciones de
la aplicación. Este patrón URL se define en la etiqueta anidada <url-pattern>. Si, en un mismo fichero
de reglas, varios patrones, de varios recursos, coinciden, el recurso que se utiliza para autenticar es el
que defina el patrón más restrictivo de todos.
Cuando se produce un error autenticando al usuario, en función de la naturaleza de dicho error, el
Filtro de Seguridad, actuará redireccionando a un path determinado. Por ejemplo, si no se puede
autenticar al usuario porque la contraseña es incorrecta, se le redirigirá a una página donde se muestra
el formulario de entrada. Sin embargo, si no se puede autenticar al usuario porque no tiene privilegios
suficientes (roles) para acceder a un recurso, se le puede redireccionar a otra página distinta
informándole de dicha situación.
Las redirecciones se especifican bajo la etiqueta “<forwards>”. Cada redirección tendrá un nombre
que la identifica (“name”) y una URL a la que se redirigirá al usuario (“path”).
Los nombres de forwards válidos son:
•
•
login. Se redirige a login la primera vez que un usuario trata de acceder a un recurso protegido.
no-login. Esta redirección se ejecuta cuando no se puede autenticar al usuario por cualquier
motivo (por ejemplo, contraseña equivocada).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
277 de
296
Proyecto
openFWPA
•
•
Estado
Definitivo
Documento
Manual de Configuración
no-roles. Se redirige a este forward cuando el usuario, que está correctamente autenticado, no
tiene autorización para acceder al recurso.
error. Esta redirección está reservada a situaciones de autenticación no controladas por los
forwards definidos para el recurso. Si no se define forward de error, cuando se de un fallo de
autenticación, se devolverá un error http 515.
En cada recurso también se definirán los nombres de los roles que tienen acceso. Si no se incluye la
etiqueta <roles>, no se realizará chequeo de roles.
Por último, se pueden definir las opciones de configuración (<options>) que se estimen convenientes
para el recurso. La semántica de estas opciones depende exclusivamente del módulo JAAS que realiza
la operación de login.
15.1.3.3. Paso de Credenciales
Durante el proceso de autenticación, se recaba una serie de datos del usuario. Estos datos se guardan
en la sesión http en un objeto de tipo javax.security.auth.Subject, bajo la clave
SecurityGlobals.SUBJECT.
Para recuperar las credenciales de los usuarios se utiliza el filtro "LoginFilter", llamando al método
“populateUserVO” de la clase “UserVOLoader”, como podemos ver a continuación.
public class LoginFilter extends PrincastFilter implements LoginFilterMBean
{
protected void filter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, resp);
return;
}
HttpServletRequest request = (HttpServletRequest) req;
UserVO user = new UserVO();
// Se obtiene el subject
Subject subject = (Subject) request.getSession(true).getAttribute(
SecurityGlobals.SUBJECT);
// Cargamos sus credenciales.
if (subject == null) {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
278 de
296
// el usuario todavia no está autenticado
chain.doFilter(req, resp);
return;
}
UserContainer existingContainer = UserContainer
.getUserContainer(request);
// si ya cargue los datos anteriormente entonces retorno
if (existingContainer.getUserVO() != null) {
chain.doFilter(req, resp);
return;
}
UserVOLoader.populateUserVO(user, subject);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Se ha autentificado al usuario:\n"
+ user.toXML());
}
existingContainer.setUserVO(user);
chain.doFilter(req, resp);
}
}
Como podemos ver en el método “populateUserVO” de la clase “UserVOLoader” que se muestra a
continuación, se recuperan las credenciales del usuario, y los roles definido en el fichero “autorizaduser.xml”, para el usuario que ha accedido al sistema.
Para recuperar las diferentes credenciales almacenadas en el objeto de tipo
“javax.security.auth.Subject”, basta con emplear las diferentes constantes definidas en la clase
SecurityConstants como parámetros para las llamadas al método getPrincipal() de la clase Principals
contenida en el objeto “Subject”.
public static void populateUserVO(UserVO user, Subject subject) {
Set principals =
subject.getPrincipals(PrincastCompositePrincipal.class);
if (principals.isEmpty()) {
logger.error("No hay principals en el subject");
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
279 de
296
throw new UnmanagedLoginException(UserVOLoader.class, "buscando
principals", "no se han encontrado principals");
}
PrincastCompositePrincipal principal =
(PrincastCompositePrincipal) principals.iterator().next();
String val = principal.getPrincipal(SecurityConstants.NAME);
if (val != null) {
user.setName(val);
}
val = principal.getPrincipal(SecurityConstants.SURNAME1);
if (val != null) {
user.setFirstName(val);
}
val = principal.getPrincipal(SecurityConstants.SURNAME2);
if (val != null) {
user.setLastName(val);
}
val = principal.getPrincipal(SecurityConstants.NIFNIE);
if (val != null) {
user.setUserName(val);
}
val =
principal.getPrincipal(SecurityConstants.ORGANIZATIONAL_UNIT_NAME);
if (val != null) {
user.setOrganizationalUnit(val);
}
// Roles del usuario
Set roles = subject.getPrincipals(PrincastGroup.class);
String nombreRoles = "";
if (logger.isDebugEnabled()) {
logger.debug("--> Roles del usuario: ");
}
Iterator it = roles.iterator();
while (it.hasNext()) {
Group rol = (Group) it.next();
nombreRoles = nombreRoles + " " + rol.getName();
if(logger.isDebugEnabled()) {
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
280 de
296
logger.debug("\t" + rol.getName());
}
}
user.setRoles(nombreRoles);
user.setEmailAddress(UNKNOWN);
principals = subject.getPrincipals(ScenarioPrincipal.class);
ScenarioPrincipal scenario =
(ScenarioPrincipal) principals.iterator().next();
user.setChannel(scenario.getChannel());
}
Atención
No es recomendable obtener los datos de autenticación (j_username y j_password)
directamente de los parámetros de la request. No se garantiza que estos datos vayan a ser los
correctos. Además, en openFWPA, cualquier parámetro que se utilice como contraseña será
enmascarado (reemplazado por la cadena "*********") por el filtro de autenticación.
15.1.3.4. Diseño de páginas de login
En las aplicaciones que utilicen openFWPA, las páginas de login deben escribirse en páginas JSP para
la obtención de los datos de autentificación (filtro "LoginFilter" visto anteriormente).
90 Página de login de la aplicación de ejemplo de openFWPA
Con el fin de facilitar el diseño e implementación de estas páginas, se utilizan varias etiquetas
incluidas en el fichero princast-ui.tld, como por ejemplo ui:layout-area, ui:block-row ó ui:blockcolumn, así como un conjunto de clases CSS definidas en el fichero login.css.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
281 de
296
El filtro de autenticación deja, en el scope session, la URL del recurso protegido solicitado, al que se
estaba intentando acceder. El nombre del atributo bajo el que se almacena esta URL está definido por
la constante: SecurityGlobals.REQUESTED_URL.
A continuación se muestra el contenido del body de la página “login.jsp” de la aplicación de ejemplo
“sampleapp” de openFWPA.
<ui:errors/>
<form id="mainForm"
action="<%if(session.getAttribute(SecurityGlobals.REQUESTED_URL)==null){out
.print("../action/viewperfil");}else
out.print(session.getAttribute(SecurityGlobals.REQUESTED_URL));%>"
method="post">
<div id="exterior">
<div id="interior">
<h1><bean:message key="login.body"/></h1>
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.Princ
astLoginException">
<div id="errors" class="errors">
<bean:message key="error.login.titulo"/>:
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.
WrongPasswordException">
<ul><li>
<bean:message key="error.login.WrongPasswordException"/>
</li></ul>
</princast:instanceOf>
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.
InsufficientPrivilegesException">
<ul><li>
<bean:messagekey="error.login.InsufficientPrivilegesException"/>
</li></ul>
</princast:instanceOf>
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.
InsufficientDataException">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
282 de
296
<ul><li>
<bean:message key="error.login.InsufficientDataException"/>
</li></ul>
</princast:instanceOf>
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.
UnknownUserException">
<ul><li>
<bean:message key="error.login.UnknownUserException"/>
</li></ul>
</princast:instanceOf>
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.
UnmanagedLoginException">
<ul><li>
<bean:message key="error.login.UnmanagedLoginException"/>
</li></ul>
</princast:instanceOf>
</div> <!-- div errors -->
<!-- No queremos que muestre el error la primera vez que se
muestra la pantalla de login. -->
<princast:instanceOf
variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
className="es.princast.framework.facilities.security.exceptions.
RequiredPasswordException">
<script type="text/javascript">
document.getElementById('errors').style.display = "none";
</script>
</princast:instanceOf>
</princast:instanceOf>
<div id="loginPanel" class="panel">
<div class="panel_caption">
<h2 class="panel_caption_login_text">
<bean:message key="login.caption"/>
</h2>
</div>
<div id="loginPanelBody" class="panel_body">
<ui:layout-area>
<ui:block-row cssClass="item_row loginPanelRow">
<label for="j_username">
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
283 de
296
<bean:message key="login.user.label" />
</label>
<input type="text" id="j_username" name="j_username"/>
</ui:block-row>
<ui:block-row cssClass="item_row loginPanelRow">
<label for="j_password">
<bean:message key="login.password.label" />
</label>
<input type="password" id="j_password"
name="j_password"/>
</ui:block-row>
</ui:layout-area>
<div class="item_pie">
</div>
</div>
</div> <!-- div loginPanel-->
<hr/>
<div class="buttons">
<html:image src="images/botones/enter-button.gif"
altKey="button.entrar" styleClass="button_login_text"/>
</div>
</div> <!-- div interior -->
<div id="footer">
<ui:layout-area id="desplazamiento">
<ui:block-row>
<ui:block-column >
<img src="images/alerta.gif" alt="Alerta"/>
</ui:block-column >
<ui:block-column cssClass="footer_text_login" >
  <bean:message key="login.footer"/>
</ui:block-column >
</ui:block-row>
</ui:layout-area>
</div> <!-- div footer-->
</div> <!-- div exterior -->
</form>
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
284 de
296
15.1.3.5. Excepciones durante el proceso de autenticación
Ver apartado "13.2. Excepciones durante el proceso de autenticación".
15.1.3.6. Niveles de Seguridad
Para la autenticación se contemplan tres niveles de seguridad:
•
•
•
Nivel 0. Con este nivel de seguridad no se requiere autenticación.
Nivel 1. Con este nivel es necesaria la validación mediante usuario y contraseña. Para ello,
deben especificarse dos parámetros denominados j_username y j_password con dicha
información.
Nivel 2. Este nivel de seguridad se corresponde a la autenticación utilizando certificado digital.
Debe tratarse de un certificado digital válido de la FNMT (Fábrica Nacional de la Moneda y
Timbre). Para forzar a esta validación debe incluirse en la petición http un parámetro
denominado forceLevel con el valor 2.
Un ejemplo de uso de este nivel de seguridad se presenta a continuación:
http://localhost:8082/prueba/action/suscribe?forceLevel=2
16. Pruebas de rendimiento
Las pruebas de rendimiento son aquellas que se realizan para medir el tiempo que tarda una
determinada tarea en ejecutarse bajo unas condiciones determinadas de trabajo. También sirve para
verificar que el sistema cumple los criterios de rendimiento, comparar dos sistemas para encontrar cual
de ellos funciona mejor, medir que partes del sistema o de carga de trabajo provocan que el conjunto
rinda mal, la escalabilidad del sistema o analizar la fiabilidad y uso de los recursos.
Por tanto, los principales objetivos de las pruebas de rendimiento son:
•
•
•
Asegurar que la infraestructura de sistemas y comunicaciones está preparada para albergar la
aplicación.
Ayuda a detectar bugs como “memory leaks” o una mala gestión de conexiones (muy
habitual).
Información importante para la toma de decisiones y gestión de riesgos del equipo de sistemas
con la aplicación en producción.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
285 de
296
Ejemplo de indicadores analizados habitualmente en las pruebas de rendimiento:
•
•
•
•
•
Ancho de banda consumido por usuario.
Degradación del tiempo de respuesta en función del número de usuarios.
Degradación de la calidad del servicio frente al número de usuarios.
Cómo decrece el % peticiones respondidas.
Punto de saturación (número de usuarios donde los tiempos de respuesta o la calidad del
servicio están fuera de lo considerado aceptable por la aplicación).
Para alcanzar un buen nivel de rendimiento de un nuevo sistema, es fundamental que los esfuerzos en
estas pruebas comiencen en el inicio del proyecto de desarrollo y se amplie durante su construcción.
Cuanto más se tarde en detectar un defecto de rendimiento, mayor es el coste de la solución. Esto es
cierto en el caso de las pruebas funcionales, pero mucho más en las pruebas de rendimiento, debido a
que su ámbito de aplicación es de principio a fin.
Sin embargo, muchos desarrolladores no siguen esta recomendación, porque por ejemplo ven las
pruebas aburridas, innecesarias o confían en que su codificación es correcta, y deciden realizar todas
las pruebas al finalizar el desarrollo, momento en que se detectan todos los problemas, es dificil
diagnosticar las causas de los fallos, los costes de solucionar los problemas son muy elevados, …,
obteniendo un producto final defectuoso.
Antes de realizar las pruebas de rendimiento de nuestra aplicación, debemos tener una visión global
del proyecto, identificar los escenarios en los que tendrá lugar la aplicación, conover las razones por
las que debemos hacer las pruebas de rendimiento, …, para planificar y diseñar el plan de pruebas e
identificar los criterios de.
Un desarrollo estable de la aplicación instalado en un entorno lo más parecido al de producción. El
entorno de pruebas de rendimiento no debe cruzarse con pruebas de aceptación de usuarios ni con el
entorno de desarrollo. Esto es tan peligroso que si las pruebas de aceptación de usuarios, o las pruebas
de integración o cualquier otra prueba se ejecutan en el mismo entorno, entonces los resultados no son
fiables. Como buena práctica, siempre es aconsejable disponer de un entorno de pruebas de
rendimiento lo más parecido como se pueda al entorno de producción.
Finalmente, tras ejecutar el plan de pruebas, es muy importante analizar los resultados obtenidos,
identificar puntos de mejora, sacar conclusiones, y volver a ejecutar las pruebas hasta obtener los
resultados satisfactorios.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
286 de
296
16.1. Tipos de pruebas
16.1.1. Pruebas de carga
Este es el tipo más sencillo de pruebas de rendimiento. Una prueba de carga se realiza generalmente
para observar el comportamiento de una aplicación bajo una cantidad de peticiones esperada. Esta
carga puede ser el número esperado de usuarios concurrentes utilizando la aplicación y que realizan un
número específico de transacciones durante el tiempo que dura la carga. Esta prueba puede mostrar los
tiempos de respuesta de todas las transacciones importantes de la aplicación. Si la base de datos, el
servidor de aplicaciones, etc también se monitorizan, entonces esta prueba puede mostrar el cuello de
botella en la aplicación.
16.1.2. Prueba de estrés
Esta prueba se utiliza normalmente para romper la aplicación. Se va doblando el número de usuarios
que se agregan a la aplicación y se ejecuta una prueba de carga hasta que se rompe. Este tipo de prueba
se realiza para determinar la solidez de la aplicación en los momentos de carga extrema y ayuda a los
administradores para determinar si la aplicación rendirá lo suficiente en caso de que la carga real
supere a la carga esperada.
16.1.3. Prueba de estabilidad (soak testing)
Esta prueba normalmente se hace para determinar si la aplicación puede aguantar una carga esperada
continuada. Generalmente esta prueba se realiza para determinar si hay alguna fuga de memoria en la
aplicación.
16.1.4. Pruebas de picos (spike testing)
La prueba de picos, como el nombre sugiere, trata de observar el comportamiento del sistema variando
el número de usuarios, tanto cuando bajan, como cuando tiene cambios drásticos en su carga. Esta
prueba se recomienda que sea realizada con un software automatizado que permita realizar cambios en
el número de usuarios mientras que los administradores llevan un registro de los valores a ser
monitorizados.
16.2. Herramientas
Las pruebas de rendimiento de aplicaciones Web, se deben realizar, de forma automatizada, utilizando
herramientas inyectoras de carga, como por ejemplo Apache Meter, Opensta o JAMon.
•
Apache JMeter [http://jmeter.apache.org/] es una herramienta de escritorio desarrollada en
Java, diseñada para realizar pruebas de rendimiento y pruebas funcionales sobre aplicaciones
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
287 de
296
en entorno Web. Apache JMeter se puede utilizar para medir el rendimiento de recursos
dinámicos y estáticos (archivos, Servlets, scripts de Perl, Objetos Java, bases de datos y
consultas, servidores FTP,…). Se puede utilizar para simular una carga pesada en un servidor,
,… , y poner a prueba su resistencia o analizar el rendimiento general con distintos tipos de
carga. JMeter destaca por su versatilidad, estabilidad y por se de uso gratuito.
•
Opensta (Open System Testing Architecture) con licencia GNU General Public License y lo
podemos encontrar en (http://www.opensta.org). Es una herramienta basada en arquitectura
CORBA que permite realizar pruebas de carga y pruebas de estrés en aplicaciones Web.
•
JAMon Java Applicaton Monitor [http://jamonapi.sourceforge.net] es una herramienta libre,
que permite ver claramente los tiempos entre capas, cuanto tiempo tarda en ejecutarse un
determinado EJB o un JSP o un Servet. Cuanto tarda la BBDD en ejecutar cierta consulta y
pasarla a la clase que le ha pedido, etc. Es una herramienta sencilla utilizar, y permite trabajar
con distintos servidores de aplicaciones (Sybase EAServer, BEA Weblogic, Tomcat, JBoss, ...).
…
•
16.3. Pruebas de rendimiento en openFWPA
Para realizar pruebas de rendimiento en openFWPA, hay que poner el parámetro de configuración
PERFORMANCE.TEST.MODE al valor ON. Este parámetro se puede definir en cualquier plug-in de
configuración que sirva parámetros al contexto de seguridad: SECURITY.
Por ejemplo, en la aplicación de ejemplo lo tenemos comentado por defecto en el fichero
“carrito.properties” comentado anteriormente, como podemos ver a continuación.
#
#Fri Jan 07 10:08:36 CET 2005
CARRITO.AGENCIA=Manin Directo.
app-config=Carrito
DEFAULT.MENU=MenuMiPerfil
ITEM.SEPARATOR = >
JMX.SERVER.NAME = SampleApp
#PERFORMANCE.TEST.MODE = ON
URL_LOGOUT=/carrito
#Configuracion de cache
CACHE_CONF=classpath:/ehcache.xml
#Tamaño de página para displayTag
PAGE_SIZE=10
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
288 de
296
17. Anexo: Consola de gestión de Tomcat 7
Se recomienda a los administradores de sistemas utilizar la consola de gestión de Apache Tomcat para
facilitar la monitorización y gestión “en caliente” de las aplicaciones.
…
Para acceder al gestor de aplicaciones Web de Tomcat 7, pulsaremos en el botón “Manager App”
disponible en la zona derecha de la pantalla, tal y como podemos ver en la siguiente imagen.
91 Sección Manager App
Aparecerá una ventana emergente en la tendremos que introducir el usuario y la contraseña que
previamente hemos introducido en el fichero “tomcat-users.xml” (ver Manual de instalación de
openFWPA en Windows/Linux).
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
289 de
296
92 Identificación de usuario en Tomcat 7
Tras identificarnos, accederemos al gestor de aplicaciones Web de Tomcat 7.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
290 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
93 Gestor de aplicaciones Web de Tomcat 7
La interfaz para la gestión de aplicaciones Web de Tomcat 7 consta de varios apartados, que se
comentarán brevemente a continuación.
Para más información, acceder a http://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html.
17.1. Mensajes
En esta sección se mostrarán los mensajes que nos informarán del estado de las acciones que se
realicen en el gestor de aplicaciones Web del Tomcat 7.
94 Sección de mensajes del gestor de aplicaciones Web de Tomcat 7
17.2. Gestor
Esta sección se divide en cuatro apartados.
95 Sección de gestión del gestor de aplicaciones Web de Tomcat 7
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
291 de
296
•
Lista de aplicaciones. Tras pulsar en este enlace, se recargará la lista de aplicaciones que se
muestran en el bloque siguiente, y que se verá en el próximo apartado.
•
Ayuda HTML del Gestor. Enlace a una página local de ayuda [http://localhost:8082/docs/htmlmanager-howto.html] donde se explica más en detalle el gestor de aplicaciones Web de
Tomcat.
•
Ayuda del Gestor. Enlace a una página local de ayuda [http://localhost:8082/docs/managerhowto.html] donde, de manera similar al enlace anterior, se explica el gestor de aplicaciones
Web de Tomcat.
•
Estado del Servidor. Este enlace nos permite ve el estado del motor del servidor.
96 Estado del servidor Tomcat 7
17.3. Aplicaciones
En esta sección se muestra el listado de aplicaciones Web disponibles en Apache Tomcat 7.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
292 de
296
97 Sección de aplicaciones del gestor de aplicaciones Web de Tomcat 7
Para cada aplicación se muestra la siguiente información:
•
•
•
•
Trayectoria. Es la ruta del contexto de la aplicación.
Nombre a mostrar. Nombre configurado en el fichero “web.xml” para la aplicación.
Ejecutándose. Será “trae” si la aplicación Web se está ejecutando, y “false” si la aplicación no
está en ejecución o no está disponible.
Sesiones Número de sesiones activas en la aplicación Web. Este número de sesiones activas es
un enlace que muestra la información ampliada sobre estas sesiones activas.
98 Detalle de las sesiones activas para un proyecto determinado
•
Comandos. Para cada aplicación tendremos disponibles cuatro comandos, que nos permitirán
gestionar las aplicaciones Web disponibles en el servidor.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
293 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
o Start. – Arrancar una aplicación Web que ha sido detenida.
o Stop. Detener una aplicación Web que actualmente está en ejecución, dejándola
inaccessible para los visitantes.
o Reload. Recargar el contexto de la aplicación Web, de forma que por ejemplo estarán
disponibles nuevos fichero “.jar” en el directorio “/WEB-INF/lib/” o nuevas clases en
el directorio “/WEB-INF/classes/” de la aplicación.
o Undeploy. Detener una aplicación Web y eliminar todas las referencia a la misma del
servidor.
17.4. Desplegar
Desde esta sección se pueden realizar despliegues de las aplicaciones Web utilizando ficheros o
directorios ya existentes en el servidor Tomcat, o bien subiendo un fichero de tipo “WAR” (web
application archive) al servidor.
Como podemos ver en la siguiente imagen, tras completar correctamente el formulario (en función de
la forma seleccionada para realizar el despliegue), tendremos que pulsar en el botón “Desplegar”.
99 Sección de despliegues del gestor de aplicaciones Web de Tomcat 7
17.4.1. Despliegue utilizando un directorio o un fichero WAR del propio servidor Tomcat
17.4.1.1. Despliegue mediante el directorio o la URL del fichero WAR
En esta sección se comentará como instalar un directorio de una aplicación Web o un fichero WAR
localizados en el propio servidor Tomcat.
Si el apartado “Trayectoria del contexto”, que es opcional, no se completa, se tomará el nombre del
fichero, eliminando la extensión “.war”.
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
294 de
296
La URL del WAR o del directorio debe seguir el esquema “file:” disponible por ejemplo en el
Javadoc
para
la
clase
“java.net.JarURLConnection”:
http://docs.oracle.com/javase/1.4.2/docs/api/java/net/JarURLConnection.html.
A continuación vamos a ver un ejemplo de una aplicación Web disponible en el directorio
“/<path>/to/foo” en el servidor Apache Tomcat, que será desplegada bajo el nombre de contexto
“/footoo” (Linux).
Trayectoria del Contexto (opcional): /footoo
URL del WAR o Directorio: file:/<path>/to/foo
Ahora veremos otro ejemplo para un fichero WAR disponible en el servidor Tomcat en el directorio
“/home/<path>/to/bar.war”. En este caso no introduciremos nombre para el Contexto, y por tanto la
aplicación estará disponible bajo el contexto “/bar”, ya que el fichero se llama “bar.war”, y se quitará
automáticamente la extensión “.war” (Linux).
URL del WAR o Directorio: jar:file:/<path>/to/bar.war!/
17.4.1.2. Despliegue mediante el directorio o la URL en el directorio base de Tomcat
En esta sección se comentará como instalar un directorio de una aplicación Web o un fichero WAR
localizados en el directorio base del propio servidor Tomcat, que habitualmente se llama “webapps”
Al igual que en el apartado anterior, si el apartado “Trayectoria del contexto” no se completa, se
tomará el nombre del fichero, eliminando la extensión “.war”.
A continuación vamos a ver un ejemplo de una aplicación Web disponible en el directorio base en el
servidor Apache Tomcat, que será desplegada bajo el nombre de contexto “/foo” (en este caso no
introducimos el nombre del contexto, y se toma el nombre del directorio).
URL del WAR o Directorio: foo
Ahora veremos otro ejemplo para un fichero WAR disponible en el directorio base del servidor
Tomcat. En este caso si introduciremos nombre para el Contexto “bartoo”, y por tanto la aplicación
estará disponible bajo el contexto “/bartoo”.
Trayectoria del Contexto (opcional): bartoo
URL del WAR o Directorio: bar.war
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
Página
295 de
296
17.4.1.3. Despliegue mediante URL de archivo de configuración XML
Si el flag “deployXML” está puesto a “true”, se podrán utilizar ficheros XML de configuración de
contexto para realizar el despliegue de aplicaciones Web. Este parámetro se puede actualizar
añadiéndolo en el fichero “Server.xml” en la línea que empieza por:
<Host
appBase="webapps"
unpackWARs="true" ...
autoDeploy="true"
name="localhost"
Para más información ver:
http://tomcat.apache.org/tomcat-7.0-doc/config/host.html#Standard_Implementation
Al realizar el despliegue mediante el archivo de configuración XML, se ignora el texto introducido en
el campo opcional “Trayectoria del Contexto”.
A continuación se muestra un ejemplo de fichero XML de configuración del contexto para una
aplicación Web.
<Context path="/foobar" docBase="/path/to/application/foobar">
</Context>
A continuación se muestra un ejemplo de despliegue de una aplicación Web a través de un fichero de
contexto (Linux).
URL de archive de Configuración XML: file:/home/<path>/foobar.context.xml
17.4.2. Desplegar a través de un archive WAR externo
A través de esta sección se realizará el despliegue de una aplicación Web en el servidor Apache
Tomcat utilizando un fichero WAR que se encuentre en el sistema de archivos del desarrollador, a
través del botón examinar que está disponible en este apartado.
El nombre del contexto de la aplicación será por tanto el nombre del fichero, pero eliminando la
extensión “.war”.
17.5. Diagnósticos
Esta sección permite revisar si las aplicaciones Web han provocado algún fallo de memoria al parar,
recargar, …
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
OpenFWPA Internacional
Página
296 de
296
Proyecto
openFWPA
Estado
Definitivo
Documento
Manual de Configuración
100 Sección de diagnósticos del gestor de aplicaciones Web de Tomcat 7
Más información en http://tomcat.apache.org/tomcat-7.0-doc/html-manager-howto.html#Diagnostics.
17.6. Información del servidor
This section displays information about Tomcat, the operating system of the server Tomcat is hosted
on, and the Java Virtual Machine Tomcat is running in.
Esta sección muestra la información del Servidor Tomcat, el sistema operativo del servidor donde está
alojado, la máquina virtual donde está corriendo, …
101 Sección de información del servidor del gestor de aplicaciones Web de Tomcat 7
Cluster TIC (www.clustertic.net)
04. ManualConfiguracion_openFWPA_20111230_v1.0.docx
30/12/2011
Descargar