Está en la página 1de 124

Manual de Desarrollo

de Aplicaciones J2EE

Manual de Desarrollo de Aplicaciones J2EE


Versin 1.5
publicado 26-Junio-2006
Copyright Gobierno del Principado de Asturias 2005

Tabla de contenidos
1. Presentacin de openFWPA .............................................................................................. 1
Introduccin .............................................................................................................. 1
Visin General de openFWPA ...................................................................................... 2
Empaquetamiento de openFWPA .......................................................................... 4
Requerimientos tcnicos y de sistema ..................................................................... 5
Lista completa de funcionalidades ......................................................................... 5
Lista de componentes de terceras partes .................................................................. 6
Arquitectura de referencia ............................................................................................ 8
Desarrollo de aplicaciones .......................................................................................... 10
Estructura de directorios ..................................................................................... 10
Compilacin y despliegue del sistema ................................................................... 11
Pruebas unitarias ............................................................................................... 11
Instalacin de la aplicacin de ejemplo (Sample App) .............................................. 11
2. Arquitectura Modelo -Vista- Controlador con openFWPA ..................................................... 13
MVC ...................................................................................................................... 13
Desarrollo de la Vista ................................................................................................ 14
Aspecto corporativo de las aplicaciones del Principado de Asturias ............................. 14
Cascading Style Sheets (CSS) ............................................................................. 14
Desarrollo del Controlador ......................................................................................... 16
Declaracin de Actions ...................................................................................... 16
Jerarqua de Actions .......................................................................................... 17
Action Forms ............................................................................................. 29
Desarrollo de lgica de negocio .................................................................................. 31
Service Locator ................................................................................................ 31
Session EJBs .................................................................................................... 31
Value Objects .................................................................................................. 31
Excepciones ..................................................................................................... 32
Utilidades ........................................................................................................ 33
Otras clases de utilidad .............................................................................................. 33
PrincastMessageFmtter ............................................................................ 33
PrincastUtils ............................................................................................ 33
ParameterCaster ........................................................................................ 33
ServletPathUtils ...................................................................................... 33
DateDecorator ............................................................................................ 34
PrincastPathResolver .............................................................................. 34
PrincastOSCacheInterceptor .................................................................. 35
Providers ......................................................................................................... 35
3. Implementacin de la Arquitectura de Referencia con openFWPA .......................................... 37
Inversin de Control en la Arquitectura de Referencia ..................................................... 37
Introduccin al manejo de la Arquitectura con Spring ...................................................... 37
Estableciendo el Datasource ........................................................................................ 38
Enlazando con los DAOs ........................................................................................... 39
Enlazando con los Managers ....................................................................................... 40
Gestin de transacciones ............................................................................................ 41
Enlazado con los Delegates ........................................................................................ 42
Enlazado con las Actions ........................................................................................... 42
Acceso directo al ApplicationContext ................................................................. 43
BeanDoc para obtener la grfica de arquitectura ............................................................. 43
Plugin SpringIDE para Eclipse .................................................................................... 43
4. Componentes para acceso a datos ..................................................................................... 45
Acceso a Bases de Datos Relacionales .......................................................................... 45

iv

Manual de Desarrollo
de Aplicaciones J2EE

5.

6.

7.

8.

9.

El patrn DAO ................................................................................................. 45


Loggeo de las Excepciones en los DAO ................................................................ 47
Listas clave/valor .............................................................................................. 47
LookupPropertyBean .................................................................................. 49
Providers ......................................................................................................... 49
Generadores de Secuencia .................................................................................. 49
Pools de conexiones .......................................................................................... 50
Construccion de informes con openFWPA ......................................................................... 51
Generacin de Informes ............................................................................................. 51
Creacin de los diseos XML. ............................................................................ 51
Clases en el openFWPA para la renderizacin de informes. ...................................... 57
Operaciones ................................................................................................................. 61
Sistema de Inicializacin y Arranque ............................................................................ 61
Declaracin de objetos inicializables .................................................................... 61
Desarrollo de objetos inicializables ...................................................................... 62
Arranque de aplicaciones web ............................................................................. 63
Arranque manual .............................................................................................. 63
Sistema de Configuracin de Aplicaciones .................................................................... 63
Implementacin de objetos configurables .............................................................. 64
Plugins de Configuracin ................................................................................... 66
Logging .................................................................................................................. 72
Log4J. Componentes ......................................................................................... 72
Configuracin ................................................................................................... 74
Componentes del openFWPA para Logging. .......................................................... 75
Pista de auditora .............................................................................................. 76
Pista de Rendimiento ......................................................................................... 77
Ficheros de Configuracin .......................................................................................... 77
web.xml ........................................................................................................ 77
struts-config.xml .................................................................................... 79
Filtros web .............................................................................................................. 83
Filtros del openFWPA. PrincastFilter. ......................................................... 83
Configuracin del filtro GZIPFilter ................................................................. 85
Configuracin del filtro SecurityFilter ......................................................... 85
Filtro de navegacin .......................................................................................... 85
Filtro de activacin ........................................................................................... 86
Filtros de Activacin ......................................................................................... 87
Consola de gestin .................................................................................................... 88
Seguridad en aplicaciones con openFWPA ......................................................................... 90
Seguridad ................................................................................................................ 90
Autentificacin bsica ........................................................................................ 90
Autentificacin basada en formulario .................................................................... 90
Autentificacin basada en el Filtro de Seguridad del openFWPA ............................... 90
Single Sign On ............................................................................................... 103
Integracin de Sistemas ................................................................................................ 104
Tecnologas de Integracin ....................................................................................... 104
XML Genrico: Configuracin .......................................................................... 104
Pruebas ...................................................................................................................... 106
Pruebas unitarias ..................................................................................................... 106
Jerarqua de clases para las pruebas unitarias ........................................................ 106
Convenciones a seguir ..................................................................................... 107
Ejecucin de las pruebas unitarias ...................................................................... 107
Consultando los resultados de los tests ................................................................ 107
Pruebas unitarias de objetos que acceden a bases de datos. ...................................... 108
Pruebas unitarias de Spring Beans ...................................................................... 112

Manual de Desarrollo
de Aplicaciones J2EE
Pruebas unitarias de objetos Configurables ....................................................
Pruebas unitarias en contenedor .........................................................................
Pruebas unitarias de informes ............................................................................
Ms informacin sobre la implementacin de pruebas unitarias ................................
Pruebas de Rendimiento ...........................................................................................
Modo de Prueba de Rendimiento .......................................................................

vi

112
113
114
115
116
116

Lista de figuras
1.1. Estructura de openFWPA ............................................................................................... 2
1.2. Arquitectura de Referencia ............................................................................................. 8
1.3. Estructura de directorios del proyecto Sample App. ........................................................... 10
2.1. Modelo Vista Controlador ............................................................................................ 13
2.2. Ciclo peticin-accin-jsp de Struts ................................................................................. 13
2.3. Estructura de capas de las aplicaciones web con openFWPA ............................................... 14
2.4. Aspecto corporativo del portal princast.es ................................................................ 14
2.5. Aspecto de la aplicacin de ejemplo (Sample App) ........................................................... 14
2.6. Jerarqua de Actions .................................................................................................... 17
2.7. Maquinaria de Estados de PrincastAction ................................................................ 18
2.8. Almacenamiento de la Action .................................................................................... 21
2.9. Esquema de la PrincastDispatchAction del ejemplo ............................................... 25
2.10. Esquema de las Actions para listados ............................................................................ 28
2.11. Estructura de la capa Modelo ...................................................................................... 31
2.12. Diagrama de Value Objects ........................................................................................ 32
2.13. Jerarqua de Excepciones ............................................................................................ 32
3.1. Ficheros de configuracin de Beans ............................................................................... 37
3.2. Ejemplo de grfica generada con BeanDoc ...................................................................... 43
3.3. Spring IDE para visualizar ficheros de Spring .................................................................. 44
4.1. Ejemplo de necesidad de lookup .................................................................................... 49
4.2. Navegacin de una relacin en BD con un LookupPropertyBean ......................................... 49
5.1. Proceso de generacin de informes ................................................................................ 51
6.1. Estructura del sistema de configuracin .......................................................................... 64
6.2. Jerarqua de Plugins .................................................................................................... 68
6.3. Estados del Sistema de Logging .................................................................................... 74
7.1. Esquema del sistema de autenticacin ............................................................................ 91
9.1. Set de pruebas unitarias disponibles .............................................................................. 106
9.2. Autowiring de DAOs y DataSources ............................................................................ 110

vii

Lista de tablas
1.1. Componentes necesarios para la ejecucin del openFWPA ................................................... 7
1.2. Capas de la Arquitectura de Referencia de openFWPA ........................................................ 9

viii

Captulo 1. Presentacin de openFWPA


Introduccin
openFWPA es el framework de desarrollo libre para sistemas de administracin electrnica y gobierno
electrnico desarrollado por el Gobierno del Principado de Asturias. Est basado en la tecnologa J2EE y
su objetivo es facilitar el diseo, implementacin, implantacin y mantenimiento de las aplicaciones.
openFWPA es Software Libre / Open Source y est publicado bajo una doble licencia: LGPL 3.0 (o
superior) y EUPL 1.0 (o superior). La Licencia Pblica General Menor del proyecto GNU (LGPL) es
una de las licencias desarrolladas y promovidas por la Free Software Foundation (FSF), y da permisos de
reproduccin, distribucin, modificacin y redistribucin con copyleft, aunque no se impide la utilizacin
de componentes privativos dentro del sistema. La Licencia Pblica de la Unin Europea (EUPL) es una
licencia de software libre con copyleft creada y apoyada por la Unin Europea para el impulso del Software
Libre en las administraciones pblicas.
Los dos grandes objetivos del framework son:
Simplificacin y homogeneizacin del proceso de desarrollo de aplicaciones. Para ello openFWPA
proporciona una arquitectura reutilizable y un conjunto de herramientas y libreras que implementan
algunos de los componentes ms habituales, y de escritura ms tediosa, en aplicaciones web. Todo ello
debiera redundar en un menor coste total de propiedad (TCO) de las soluciones desarrolladas sobre
openFWPA.
Definicin de estndares de desarrollo, calidad y aceptacin. Se trata de un conjunto de directrices, de
obligado cumplimiento, para exigir y garantizar unos niveles mnimos de calidad en las aplicaciones
J2EE [1]. Estos estndares son internos al Principado de Asturias, y son por tanto aplicables solamente
dentro de aquellos proyectos desarrollados dentro del Principado de Asturias.
El openFWPA posee las siguientes caractersticas:
Uso de software libre. Hay una serie de proyectos del mundo del software libre que poseen una excelente
calidad, lo que los habilita para participar en aplicaciones de misin crtica.
Uso de patrones de diseo. El openFWPA promueve el uso de patrones de diseo, en dos sentidos
importantes. En primer lugar, el framework est diseado y construido sobre patrones. Por otro lado,
las aplicaciones que se desarrollan sobre el framework hacen uso asimismo de patrones. Entre otros,
las aplicaciones desarrolladas sobre openFWPA siguen una arquitectura Modelo2 , el estndar en
aplicaciones web (se trata de una adaptacin del famoso MVC).
Uso de estndares. En el diseo del openFWPA se ha promovido la utilizacin e incorporacin de
estndares (por ejemplo, XHTML [4] + CSS [14], etc.). El uso tanto de patrones de diseo como
de estndares proporciona importantes ventajas en cuanto a la adaptabilidad y longevidad de las
aplicaciones que los utilizan, al ser ms fcilmente mantenidas, extendidas o reutilizadas.
Aspecto corporativo. Otra caracterstica importante es que las aplicaciones deben integrarse con el resto
de aplicaciones del Principado de Asturias, tanto a nivel funcional como de aspecto (look & feel). El
openFWPA incluye un conjunto de plantillas y componentes para construir la capa de presentacin de
acuerdo a las guas de estilo corporativo del Principado de Asturias. En la versin publicada en portal,
estas plantillas pueden modificarse de acuerdo a las necesidades de cada proyecto. Sin embargo, los
proyectos internos han de seguir las directrices de estilo corporativo.
Integracin de aplicaciones. La nueva funcionalidad, aadida al openFWPA en las ltimas versiones,
facilita la integracin de las aplicaciones con otros sistemas del Principado de Asturias (sistema de
seguridad, comunicaciones, bases de datos corporativas, sistemas de seguridad, sistemas de CRM, etc.).

Presentacin de openFWPA

Esta funcionalidad solo est disponible para los proyectos internos, al carecer de inters en aplicaciones
desarrolladas fuera de la organizacin.
Ciclo de vida. Las aplicaciones poseen un ciclo de vida ms all de su desarrollo y puesta en produccin.
stas han de ser configuradas, migradas y operadas en los diversos entornos. Por ejemplo, el framework
proporciona piezas con una funcionalidad importante que facilita el soporte a la operacin. Los
componentes del framework estn preparados para ser gestionados en caliente desde una consola
de operaciones, y ofrece componentes para aspectos crticos de operacin (como gestin adecuada de
logging, pistas de auditora, estadsticas de rendimiento y uso). En general, estos aspectos se incorporan
al framework de manera transparente a las aplicaciones. Asimismo, se ofrece (opcionalmente) una serie
de APIs avanzadas que permiten a las aplicaciones publicar funcionalidad en la consola de operaciones.

Visin General de openFWPA


El framework de desarrollo J2EE del Principado de Asturias posee la siguiente estructura. Dentro de cada
elemento se muestran los artefactos ms relevantes:

Figura 1.1. Estructura de openFWPA

A continuacin, se muestran en ms detalle los diversos elementos que lo componen.


Aceptacin

Las aplicaciones desarrolladas con el framework para uso interno


del Principado de Asturias deben pasar por una serie de controles
de calidad. A tal efecto, se han desarrollado una serie de guas que
deben seguirse para el desarrollo de estas aplicaciones. Dentro de
esta gua de aceptacin se define una arquitectura reutilizable que
debieran seguir las aplicaciones.

Entorno de desarrollo

El framework de desarrollo es agnstico en cuanto al entorno de


desarrollo. ste debiera poseer los siguientes elementos:
Entorno Integrado de desarrollo. Ofrece un entorno donde los
desarrolladores pueden desarrollar, compilar, depurar y probar el
software en construccin.
Herramientas de despliegue. Permite el despliegue de las
aplicaciones en los distintos entornos (mquina local, mquinas
del entorno de desarrollo, etc.).
Diseo de informes. Permite la construccin de informes en
distintos formatos.
Gestin de la configuracin. Permite la gestin del cambio de
los distintos elementos del sistema (cdigo fuente, scripts de
construccin, pruebas, etc.). Se trata de un sistema de control de
versiones.
Entorno de integracin (semi) continua. El entorno de desarrollo
debiera ofrecer funcionalidad avanzada de integracin continua
o semi-continua.
Los proyectos arrancados dentro del Principado de Asturias deben
poseer las herramientas definidas en el puesto estndar. Estas

Presentacin de openFWPA

herramientas deben instalarse y configurarse de manera estndar


(igual para todas las estaciones de trabajo).
Software Libre

Tras la definicin de los requisitos del framework en trminos de


herramientas necesarias para el entorno de desarrollo, directrices
de aceptacin y diseo del runtime del framework, se realiz la
seleccin de distintos componentes del mundo del cdigo abierto
o gratuito para su inclusin. Por ejemplo, se seleccion Eclipse
como Entorno Integrado de Desarrollo, o CVS para el Control
de Versiones. Como elementos ms relevantes, destaca el uso de
Eclipse, Spring o Struts.

Sistema de tiempo de ejecucin

El sistema de tiempo de ejecucin es un conjunto de ficheros .jar


que se despliegan con cada una de las aplicaciones del framework.
Este sistema sigue las directrices de construccin de aplicaciones,
y ofrece componentes reutilizables y una base extensible para
el desarrollo basado fuertemente en patrones de diseo. De esta
manera, las aplicaciones se reducen en tamao y complejidad,
teniendo todas la misma estructura interna (basada en una
adaptacin del patrn MVC llamada Modelo2).
El sistema de tiempo de ejecucin emplea diversos componentes
del mundo de cdigo abierto, usando lo mejor de cada uno de
ellos e integrndolos. Esta aproximacin ha facilitado enormemente
el desarrollo, y emplea internamente dos frameworks Struts y
Spring.

Mdulos de integracin

Los sistemas a construir dentro del mbito de la Administracin


del Principado de Asturias presentan una fuerte componente de
integracin con otros sistemas. Se han escrito adaptadores para los
distintos sistemas corporativos existentes dentro de la organizacin,
de manera que se simplifica y homogeneza enormemente las tareas
de integracin siguiendo un patrn proxy. Estos mdulos solo estn
disponibles para aquellos proyectos realizados para el Principado
de Asturias.

Seguridad

Es crucial que las aplicaciones desarrolladas posean un nivel


de seguridad suficiente, y que esta seguridad pueda gestionarse
centralmente desde los sistemas corporativos de seguridad. A este
fin, se ha desarrollado toda una infraestructura de seguridad sobre
estndares (X509, Java Authentication and Authorization Service,
Web Services, etc.). Desde el punto de vista de la aplicacin, se
trata de realizar una parametrizacin. Toda esta infraestructura es
extensible. Dado que determinados proyectos se desarrollan por
equipos externos sin acceso a la infraestructura del Principado
de Asturias, se incluye un simulador de autenticacin, de manera
que determinados escenarios pueden ejecutarse empleando un
documento XML en local como repositorio de credenciales.
Asimismo, esta infraestructura es extensible, de manera que pueden
desarrollarse adaptadores a otros repositorios (LDAP, etc) en
proyectos ajenos al Principado de Asturias.

Operacin

Las aplicaciones han de ser operadas en los distintos entornos,


de manera que el personal de operaciones pueda mantener la

Presentacin de openFWPA

aplicacin en funcionamiento. El framework posee una serie de


herramientas que facilitan esta operacin, como pueden ser:
Filtro de compresin. El framework proporciona un filtro de
compresin de las comunicaciones, de manera que se minimice
la comunicacin entre el servidor y el cliente.
Manual de Operaciones. En este documento se describen
las operaciones que pueden realizarse sobre la aplicacin
desplegada.
Configuracin. El framework posee un subsistema flexible de
configuracin, de manera que las aplicaciones se aislan de los
repositorios de configuracin.
Auditora. Se proporciona funcionalidad para la generacin de
pistas de auditora.
Gestin de logs. El framework proporciona un potente sistema
de logs, de manera que (por configuracin) puede enviarse los
mensajes a una BD, a ficheros de texto, XML, HTML, etc. Esta
configuracin puede cambiarse en caliente.
Consola de Administracin. Las aplicaciones desarrolladas con
el framework poseen una consola de administracin web para la
modificacin de los distintos componentes.
Mtricas de uso. Pueden habilitarse diversas mtricas de uso de
la aplicacin, de manera transparente para las aplicaciones.
Documentacin

Con el framework se entrega toda la documentacin necesaria


para el desarrollo y operacin de aplicaciones. Se entregan
una aplicacin de ejemplo (con sus pruebas de rendimiento
correspondientes) y una aplicacin en blanco, con la estructura de
directorios creada.

Soporte

Existe un sitio de soporte para la resolucin de dudas, incidencias,


etc. Este sitio web de soporte permite comunicar al equipo de
mantenimiento del framework bugs detectados, etc. de manera
que se pueda liberar una nueva entrega (release) con los defectos
corregidos. A tal efecto, se crea un usuario para cada equipo
de desarrollo que demande soporte, para que puedan realizar un
seguimiento consistente de las incidencias que puedan surgir.

Empaquetamiento de openFWPA
El conjunto completo de entregables que puede acompaa al openFWPA es el que sigue. En algunas
distribuciones, pueden no estar disponibles determinados elementos:
Manual del desarrollador. (Este documento).
Manual de operaciones.
Manual de configuracin de la seguridad.
Directrices de aceptacin de aplicaciones J2EE del Principado de Asturias.

Presentacin de openFWPA

Herramientas del desarrollador.


Gua de estilo del lenguaje Java
Gua de estilo del lenguaje JSP.
openFWPA. (binarios)
Aplicacin de ejemplo: SampleApp (binarios y fuentes)
Aplicacin en blanco: App Blank (binarios y fuentes)

Requerimientos tcnicos y de sistema


Para la correcta ejecucin de las aplicaciones que utilizan el openFWPA es necesario disponer de los
siguientes elementos:
Libreras de soporte (Ver Lista de componentes de terceras partes)
Servidor de aplicaciones Oracle10G OC4J (versin 10.1.2) con Java JRE 1.4.2
Determinadas partes de la aplicacin requieren adems, los siguientes componentes:
a. Seguridad:
Certificado Raz de la Fabrica Nacional de Moneda y Timbre (FNMT)
Fichero de certificados (cacerts) en la mquina virtual

Lista completa de funcionalidades


Las funcionalidades soportadas por el openFWPA son las siguientes:
Extensin del framework Struts [8] con una coleccin propia de clases Action.
Acceso a datos a travs de objetos DAO.
Automatizacin de la carga de consultas SQL desde ficheros de propiedades.
Plantillas (Tiles) para la creacin rpida de pginas JSP.
Hojas de estilos con el look & feel del Principado de Asturias.
Facilidades para la generacin de informes en formato PDF.
Etiquetas JSP para la inclusin de listas, barras de navegacin, fechas y calendarios en las pginas web.
Integracin de formularios (ActionForm) con entidades (ValueObject) de la aplicacin.
Utilidades para la gestin de tablas de datos en formato {atributo, valor}.
Facilidades para la obtencin de listas paginadas como resultado de consultas.
Herramienta para la generacin automtica de mens.
5

Presentacin de openFWPA

Infraestructura para pruebas unitarias.


Infraestructura para pruebas unitarias en contenedor.
Integracin de una consola de monitorizacin y gestin basada en el estndar JMX [19].
Jerarqua propia de excepciones.
Monitorizacin y control integrado de errores
Sistema de configuracin centralizado.
Sistema de inicializacin y arranque configurable.
Componentes para el acceso a pools de conexiones.
Sistema de logging con varios niveles.
Gestin de logging desde la consola de administracin.
Monitor de rendimiento.
Sistema de monitorizacin para las clases Action.
Generacin de estadsticas de acceso a las aplicaciones.
Generacin de estadsticas de excepciones no controladas en las aplicaciones.
Componente para monitorizar el estado del sistema sobre el que corre la aplicacin.
Infraestructura para filtros gestionados en caliente.
Filtro para compresin GZIP.
Inicializacin de componentes configurables.
Filtro de seguridad para integracin con el Mdulo de Autenticacin del SAC del Principado de Asturias.
Conexin con backends del Principado de Asturias (Claves, Terceros, Siebel, Mdulo Comn de SMS).

Lista de componentes de terceras partes


El framework de desarrollo del Principado de Asturias incorpora componentes de terceras partes. Las
aplicaciones que se construyan sobre el framework han de utilizar las versiones enumeradas en

Fundacin Apache.
Struts Menu

sourceforge.net

struts-menu.jar
struts-menu.tld
struts-menu-el.tld
Presentacin
de openFWPA

2.2

Librera
para
facilitar
el
desarrollo de mens
en
aplicaciones
web.

Tabla
necesarios para la ejecucin
Apache1.1.
Ant Componentes
ASF
1.6.1del openFWPA
Herramienta

para
la automatizacin
de las operaciones
de
compilacin,
construccin
y
despliegue
de
proyectos.

Java SDK

Sun Microsystems

1.3.1_11 - 1.4.x

Conjunto
herramientas
libreras Java.

de
y

Oracle AS9i

Oracle

9.0.3.0.0 - 10.1.2

Servidor
aplicaciones
Oracle.

de
de

JMX
Reference Sun Microsystems jmxri.jar
Implementation
jmxgrinder.jar
jmxtools.jar

1.0

Librera para la
gestin dinmica de
aplicaciones Java
(slo es necesaria
con OC4J 9.0.3).

Base de
Oraclae

8.1.7.3

Sistema de Gestin
de Bases de Datos.

0.6.0

Herramienta para
la generacin de
informes
en
diferentes formatos:
PDF, HTML, XLS,
CSV y XML.

oc4.jar admin.jar

Datos Oracle

Jasper Reports

sourceforge.net

JSSE

Sun Microsystems jsse.jar

1.0.3_03

Proporciona
soporte para la
conexin
bajo
protocolo SSL.

JAAS

Sun Microsystems jaas.jar

1.0

Proporciona
soporte
para
autentificacin
y
autorizacin.

JCE

Sun Microsystems jce.jar


1.2.2
local_policy.jar
sunjce_provider.jar
US_export_policy.jar

Proporciona
soporte para uso
de protocolos de
encriptacin.

JDBC

Sun Microsystems jdbc2_0-stdext.jar

2.0

Extensiones JDBC
para la compilacin
con
versin
1.3.1_11 de la JDK.

Spring

Spring Framework spring.jar

1.2.6

Framework IoC.

Java Monitor API

JAMon API

JAMon.jar

1.1.2

Librera
de
monitorizacin y
medicin
de
tiempos

dwr.jar

1.0

Librera de AJAX

Direct
Web Get Ahead
Remoting (DWR)

jasperreports.jar

Presentacin de openFWPA

Arquitectura de referencia
El framework de desarrollo del Principado de Asturias hace un uso intensivo de Patrones de Diseo. A fin
de lograr una homogeneidad efectiva en las aplicaciones realizadas en el marco del Principado de Asturias,
se propone una Arquitectura de Referencia que describe la arquitectura de las aplicaciones desarrolladas
con el openFWPA. El uso de esta arquitectura de referencia es obligatorio, al ser parte de las Directrices
de Aceptacin de aplicaciones.
Una arquitectura de referencia es una descripcin de los elementos de los que se compone una aplicacin, y
de las relaciones entre estos elementos. Manejar arquitecturas de referencia es tremendamente beneficioso,
ya que permite: Homogeneizar las aplicaciones. Al usar la arquitectura de referencia, las aplicaciones
son estructuralmente iguales, cambiando slo los elementos en concreto, pero no la forma que tienen de
relacionarse. Esto tiene un impacto directo en el esfuerzo en desarrollo y mantenimiento.
Extender las mejores prcticas y tecnologas. La arquitectura de referencia ha de mantenerse, de manera
que se vayan introduciendo cambios basados en cambios tecnolgicos o en el establecimiento de mejores
prcticas.
La arquitectura de referencia J2EE propuesta se basa en el patrn Modelo2 sobre una disposicin en capas,
y puede verse en el siguiente diagrama:

Figura 1.2. Arquitectura de Referencia

El concepto de separacin en capas est claramente definido en esta arquitectura de referencia:


La comunicacin entre capas slo puede existir a travs de a) interfaces, b) Objetos de Datos (Value
Objects). Los elementos de la arquitectura de referencia pueden verse en la siguiente tabla:

Presentacin de openFWPA

Tabla 1.2. Capas de la Arquitectura de Referencia de openFWPA


Elemento

Descripcin

Patrones relevantes

Capa de Acceso a Datos

Encapsula toda la lgica de acceso Data Access Object Proxy Value


a datos. Asimismo, encapsula los Object Absctract Factory
accesos a sistemas remotos.

Capa de Objetos de Datos

Representa las entidades del Value Object


modelo, como objetos JavaBean y
sin lgica de negocio.

Capa de Negocio

Implementa toda la lgica de Business Delegate Faade


negocio, implementada como
procesos sobre la capa de Acceso
a Datos. Oculta toda la comlejidad
a la capa superior.

Capa de Controlador

Transforma eventos en la vista a MVC Command


eventos en el modelo, y viceversa.

Capa de Vista

Presenta el modelo al usuario, MVC


y comunica sus acciones al
controlador

Filtro web

Permiten filtrar las peticiones de Chain Of Responsibility


los clientes, a fin de propor-cionar
autenticacin, asertos a toda la
aplicacin, compresin de datos,
etc.

Datasource

Gestiona pools de conexiones, a


fin de no crear una conexin por
cliente a Base de Datos u otros
repositorios.

Gestin de sesin

Gestiona la sesin de los clientes,


de manera que desconecta a los
inactivos.

Sistema externo

Representa cualquier sistema a


integrar a travs de un interfaz
bien definido.

Dado el nmero de libreras que implementan el patrn MVC, tiene todo el sentido usar alguna de ellas
en vez de implementarlo para un proyecto. El openFWPA da soporte para este patrn. Caso de ser una
aplicacin J2EE no construida sobre el openFWPA, debiera hacer uso del framework Struts.
Una vez fijada la arquitectura de referencia, se ha acudido al mundo del software libre buscando
implementaciones de los elementos reseados en ella. Por ejemplo, para la capa del controlador se ha
optado por usar una implementacin de un proyecto del software libre en vez de proceder a realizar una
implementacin propia. Asimismo, el openFWPA ofrece soporte en la implementacin de todas las capas,
desde acceso a datos hasta presentacin.
En general, prcticamente todas las libreras utilizadas por el openFWPA provienen de la Apache Software
Foundation (ASF) [5] y tambin pueden ser consideradas como estndares de facto en sus respectivas
reas. Las libreras proporcionadas por la ASF, son de cdigo libre y abierto, estn mantenidas por un
nutrido grupo de desarrolladores de todo el mundo y son muy habituales en proyectos de desarrollo
(principalmente Java) de cualquier ndole.

Presentacin de openFWPA

Desarrollo de aplicaciones
Antes de comenzar el desarrollo de una aplicacin web con el openFWPA, es importante tener en cuenta
las directrices y recomendaciones que se indican en este apartado.

Estructura de directorios
Las aplicaciones definirn una estructura de directorios siguiendo la plantilla:
build, target: Contendr los .class generados para el proyecto.
db: Contendr los scripts de creacin de la base de datos o la propia base de datos. En caso de darse
soporte a ms de una base de datos o ms de una versin, ha de crearse un directorio para cada una
de las BD.
config: Contendr los ficheros necesarios para la creacin del fichero EAR necesario para desplegar
la aplicacin en el contenedor J2EE (como por ejemplo application.xml), as como los ficheros
con la informacin necesaria para la configuracin de recursos que necesitar la aplicacin (por ejemplo
DataSources. En este caso podra incluirse un fichero data-sources.xml con la informacin a
aadir al fichero data-soruces.xml del contenedor J2EE para la definicin de los mismos).
src: Este directorio contendr dos subdirectorios:
java: Contendr los ficheros de cdigo fuente Java y de recursos de la aplicacin, y el fichero
build.xml.
webapp:
pages: Contendr el resto de ficheros de la aplicacin: pginas HTML, JSP, imgenes, hojas de
estilo CSS, etc.
WEB-INF: Contendr los ficheros de configuracin XML (web.xml, struts-config.xml,
validation.xml, etc.), DTDs y TLDs.
lib: Contendr las libreras que ser necesario distribuir con la aplicacin, puesto que no estarn
incluidas en el contenedor J2EE.
ejbApp:
META-INF: Contendr el fichero de MANIFEST.MF, as como los ficheros necesarios para el
despliegue de EJBs en caso de que sean utilizados en la aplicacin. Estos ficheros sera ejbjar.xml, orion-ejb-jar.xml, y cualquier otro fichero que fuera necesario.
dist: Se trata de un directorio temporal empleado para la generacin de los jars, ears, necesarios
para el proyecto.
javadoc: Contiene el javadoc generado con el target de Ant incluido al efecto.
Como ejemplo se muestra la estructura de la aplicacin de ejemplo (Sample App):

Figura 1.3. Estructura de directorios del proyecto Sample App.

10

Presentacin de openFWPA

Compilacin y despliegue del sistema


Para la compilacin y el despliegue de aplicaciones se utilizar la herramienta Ant [10] (http://
ant.apache.org). Ant es una herramienta de construccin basada en Java similar al clsico Make.
Los ficheros de configuracin de Ant estn escritos en XML y tienen por nombre build.xml. Cada uno
de ellos contiene un project y al menos un target (el default, que ser el que se ejecutar si no se especifica
ningn otro en la llamada a Ant). Cada uno de ellos ser el encargado de la compilacin, empaquetado,
despliegue en el contenedor J2EE, etc. de la aplicacin.
Con las aplicaciones en blanco (Blank App) de ejemplo (Sample App) de distribuye un fichero
build.xml. Los targets ms relevantes son los siguientes:
all (default): Realiza lo mismo que make-ear.
compile: Compila los ficheros fuente Java de la aplicacin.
javadoc: Genera la documentacin Javadoc.
test.unit: Lanza las pruebas unitarias utilizando JUnit [11]. Busca en los paquetes de cdigo fuente las
clases cuyo nombre termine en Test (segn el convenio de nombrado de JUnit), ejecuta las pruebas y
genera informes con los resultados de las mismas en formato HTML.
make-war: Genera un fichero WAR (Web Application Archive) con la aplicacin, necesario para la
posterior generacin del fichero EAR.
make-ear: Genera un fichero EAR (Enterprise Application Archive) con la aplicacin, que podr ser
desplegado en un contenedor J2EE.
deploy.localhost: Despliega la aplicacin en el contenedor J2EE instalado en la mquina local.
undeploy.localhost: Desinstala la aplicacin del contenedor J2EE instalado en la mquina local.
deploy.desa: Despliega la aplicacin en el contenedor J2EE instalado en la mquina cuya IP est
contenida en la variable desa.test.host.
undeploy.desa: Desinstala la aplicacin del contenedor J2EE instalado en la mquina cuya IP est
contenida en la variable desa.test.host.
new: Crea un nuevo proyecto a partir del proyecto actual, para ello es necesario pasarle el nombre del
proyecto nuevo mediante el parmetro -Dapp.name=proyectoNuevo. Esto copiar el proyecto
actual, al mismo nivel de directorio y sustituye el nombre del proyecto en los ficheros de configuracin
que sea posible.

Pruebas unitarias
Es muy recomendable la implementacin de pruebas unitarias, al menos para todos los componentes
crticos de la aplicacin. Es tambin recomendable, en aplicaciones web, implementar pruebas unitarias
para todos los objetos de acceso a datos (DAO). Para facilitar esta tarea se puede utilizar la librera dbUnit
y la clase PrincastDatabaseTestCase, suministrada en el openFWPA.

Instalacin de la aplicacin de ejemplo (Sample App)


Para instalar la aplicacin de ejemplo (Carrito) se deben seguir los pasos descritos en los siguientes
apartados.

11

Presentacin de openFWPA

Configuracin de la seguridad
Para habilitar la seguridad en la aplicacin de ejemplo deben seguirse los pasos especificados en el
documento [Manual de Operaciones].

Configuracin de la base de datos


Esta aplicacin utiliza una base de datos MySQL. Se ha de copiar el driver JDBC para MySQL (mysqlconnector-java-3.0.12-production-bin.jar) en el directorio {OC4J_HOME}/j2ee/
home/applib. Para instalar la base de datos es necesario ejecutar la tarea ANT createdb incluida en
build.xml (quiz sea necesario cambiar el usuario y contrasea para conectarse a MySQL).
A continuacin se edita el fichero data-sources.xml, que se encuentra en el directorio
{OC4J_HOME}/j2ee/home/config, y se le define un nuevo origen de datos para la aplicacin aadindole
el siguiente cdigo al fichero:
<data-source
class="com.evermind.sql.DriverManagerDataSource"
name="MySQLDS"
location="jdbc/CarritoDS"
xa-location="jdbc/xa/CarritoXADS"
ejb-location="jdbc/MySQLDS"
connection-driver="org.gjt.mm.mysql.Driver"
username="admin"
password=""
url="jdbc:mysql://localhost/carrito"
inactivity-timeout="30"/>
Si el servidor de base de datos no se encuentra en la misma mquina que OC4J, sustituir localhost por el
nombre o la direccin a dicha mquina. Hacer que los campos username y password coincidan con los de
algn usuario de MySQL con privilegios para acceder a la base de datos.
Llegados a este punto es necesario re iniciar el OC4J. Una vez re iniciado ejecutar el target deploy.localhost
del fichero build.xml, si se ejecuta desde la mquina donde est instalado OC4J, o deploy.desa si se trata
de una mquina remota (en este caso cambiar la variable desa.test.host del fichero build.xml debe apuntar
a la IP del servidor).
Una vez completado el proceso de instalacin, la aplicacin estar disponible desde la direccin http://
localhost:8888/carrito.
Para tener acceso al sistema puede utilizar como parmetros de autenticacin los siguientes:
Identificador de usuario: cliente.
Contrasea: cliente.

12

Captulo 2. Arquitectura Modelo -VistaControlador con openFWPA


MVC
El patrn MVC Model 2 puede ser visto como una implementacin del lado del servidor del patrn de
diseo Modelo-Vista-Controlador (MVC). Este patrn describe cmo debe implementarse una aplicacin
con tres elementos bsicos:
Modelo

Se trata de las entidades del dominio del problema, implementadas con


total independencia de su presentacin.

Vista (Presentacin)

Esta capa se encarga de mostrar las entidades del modelo al usuario. En


el openFWPA, se implementa esta capa sobre la tecnologa JSP. En esta
capa, no hay lgica de negocio

Controlador

Traduce eventos/operaciones realizadas sobre la vista a invocaciones de


mtodos en el modelo. En el openFWPA se emplean servlet para esta
capa. Bsicamente, en esta capa se procesa la peticin de entrada de
un cliente, se accede a las entidades del modelo y se coloca cualquier
elemento a pasar a la vista en algn mbito de aplicacin (request, session,
etc.). Asimismo, dispara un evento que se mapear a una pgina jsp que
mostar los resultados.

Esta estrategia da lugar a una separacin entre presentacin y contenido, producindose una clara
definicin de los roles y responsabilidades de los desarrolladores y diseadores de pginas, en los equipos
de programacin. De hecho, cuanto ms compleja sea la aplicacin, mayores son los beneficios de utilizar
la arquitectura de Modelo 2.

Figura 2.1. Modelo Vista Controlador

El proyecto Struts de la Apache Software Foundation es una implementacin del MVC Modelo 2.
El ncleo del framework Struts es una capa de control flexible basada en tecnologas estndar como
servlets, JavaBeans, ResourceBundles y XML, as como varios paquetes del proyecto Jakarta Commons.
(http://jakarta.apache.org/commons).
Struts suministra su propio componente controlador (Controller) y se integra con otras tecnologas
para proporcionar el Modelo y la Vista. Para el Modelo, Struts puede interactuar con tecnologas de acceso
a datos estndar, como JDBC y EJB, as como con la mayora de paquetes de terceras partes, como
Hibernate, iBATIS, u Object Relational Bridge. Para la Vista, Struts trabaja bien con JSPs, incluyendo
JSTL y JSF, as como con Velocity, XSLT y otros sistemas de presentacin. Actualmente, el framework
del Principado de Asturias slo da soporte a JDBC y JSP.
La figura siguiente muestra como es el ciclo peticin-accion-jsp del framework Struts:

Figura 2.2. Ciclo peticin-accin-jsp de Struts

Para obtener informacin ms detallada sobre Struts consultar el tutorial que se adjunta en la
documentacin de openFWPA.

13

Arquitectura Modelo -VistaControlador con openFWPA

Figura 2.3. Estructura de capas de las aplicaciones web con openFWPA

Desarrollo de la Vista
Aspecto corporativo de las aplicaciones del Principado
de Asturias
Las aplicaciones construidas bajo los estndares del openFWPA de desarrollo J2EE se integrarn en el
portal del Principado de Asturias ya existente (http://www.princast.es) tanto en internet como
intranet. Por lo tanto debe respe-tarse el look & feel del portal en la medida de lo posible. Se
establece como premisa la construccin de un look & feel ligeramente diferenciado, pero que a su
vez respete la imagen corporativa del Principado de Asturias.
Para lograr este objetivo, se ha partido de la hoja de estilos general.css propiedad del Principado de
Asturias, y en base a ella se han desarrollado nuevas hojas de estilos que establezcan el aspecto de la vista
de las aplicaciones construidas bajo el framework. Estas hojas de estilo permiten separar las instrucciones
de formateo (posicin, color, tamao, etc) del cdigo HTML generado por la aplicacin. 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 CSS.

Figura 2.4. Aspecto corporativo del portal princast.es

Figura 2.5. Aspecto de la aplicacin de ejemplo (Sample App)

Cascading Style Sheets (CSS)


La aplicacin ejemplo (Sample App) maneja 5 hojas de estilos CSS. Debe tomarse esta implementacin
como referencia de posicionamiento y formateo de textos, bloques, prrafos, etc. En general, se prohbe
el uso de directrices de estilo dentro del cdigo HTML. Cualquier estilo o posicionamiento de bloques
deber ir contenido en una hoja de estilos CSS.

Hojas de estilo en la aplicacin de ejemplo (Sample App)


Las hojas de estilo son enlazadas a travs de la pgina 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 cdigo actual de la pgina head.jsp es:

<!-- Css basicas -->


<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" />

14

Arquitectura Modelo -VistaControlador con openFWPA

<!-- 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" />
Las hojas de estilo manejadas por la aplicacin de ejemplo SampleApp son:
general.css

proviene de la hoja de estilos de referencia con el mismo nombre, incluida


en el portal princast.es. Ha sufrido ligeras modificaciones para adaptarse a las
necesidades del framework PA. Establece los estilos para los elementos ms
comunes de una pgina HTML (enlaces, tablas, celdas, prrafos, listas, textos)

position.css

define el posicionamiento de los bloques <div> dentro de la pgina. La estructura


de una pgina se ha definido en base a bloques, de los cuales no todos tienen
porque aparecer, segn las necesidades de pgina. Para ms informacin, vase
los apartados correspondientes a los layouts tiles.

princast-ui.css

hoja de estilos para el estilo de los componentes de las etiquetas de princast para
las pginas

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 (Ver ???). El displaytag genera listas paginadas.

carrito.css

Hoja de estilo para la ubicacin y formato de componentes especficos de la


aplicacin de ejemplo.

Estos ficheros CSS definen los estilos para aplicaciones de tramitacin. Adems de estas hojas de estilo,
se incluyen en el openFWPA ficheros CSS que definen estilos para aplicaciones de portal. Estas hojas de
estilo son: componentsPortal.css, displaytagPortal.css y carritoPortal.css.
Segn lo expuesto, el cdigo de las pginas JSP debe reducirse al mnimo imprescindible, obteniendo as
un cdigo mucho ms claro y mantenible.
Ejemplo: cdigo JSP del cuerpo de una pgina de la aplicacin Sample App:
<%@ 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" %>
<%@ 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="sessionScope.ListaProductoKey"
id="listProd"

15

Arquitectura Modelo -VistaControlador con openFWPA

pagesize="3"
export="false"
sort="page"
requestURI="../../../action/viewlistaproducto?paginate=true"
summary="Listado de productos"
>
<display:column>
<%=listProd_rowNum%>
</display:column>
<display:column titleKey="productos.column.name" sortable="true" >
<bean:define id="nombreProducto" name="listProd" property="name" toScope="page"
<html:link action="/viewdetalleproducto" paramId="id" paramName="listProd" para
<bean:write name="listProd" property="name" />
</html:link>
</display:column>
<display:column titleKey="productos.column.description" property="description" /
<display:column titleKey="productos.column.basePrice" property="basePrice" sorta
<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%>" alt="<%=\"Imagen de \" +
</display:column>
<display:column titleKey="productos.column.moreInfo" sortable="false" class="cen
<html:link action="/viewdetalleproducto" paramId="id" paramName="listProd" para
<html:img src="../../images/icon_info_sml.gif" altKey="label.masinformacion"
</html:link>
</display:column>
</display:table>
</ui:box>
<html:img styleClass="carrito_image" src="../../images/productos.jpg" alt=""/>

<span id="pdf_link">
<html:link styleClass="enlace_imagen enlace_pdf" action="/viewlistaproductopdf" t
<bean:message key="productos.descargaPDF"/>
</html:link>
</span>
</div>
El cdigo anterior responde a la forma en que se construye un cuerpo de pgina. No se ha utilizado en
ningn caso directrices de estilo o posicionamiento dentro de este cdigo, y en esta forma resulta ms
claro, donde se atiende nicamente a lo que debe mostrar la pgina y no a como y dnde debe mostrarlo.

Desarrollo del Controlador


Declaracin de Actions
Desde la versin 1.5, las aplicaciones desarrolladas con el openFWPA, estn basadas en el framework
Spring. Para poder inyectar dependencias en las Actions de las aplicaciones, es necesario que stas
sean definidas como beans de Spring. En concreto, las definiciones de Actions se realizarn ahora en
el fichero: beans/web/action-beans.xml, este fichero se debe ubicar en el CLASSPATH.

<bean id="login" class="es.princast.sampleapp.web.action.LoginAction" singleton="fa

16

Arquitectura Modelo -VistaControlador con openFWPA


</bean>

<bean id="logout" class="es.princast.sampleapp.web.action.LogoutAction" singleton=


<property name="carritoDelegate"><ref bean="carritoDelegate" /></property>
</bean>
Mientras que las Actions (clases) se declaran ahora en el fichero action-beans.xml, todos los aspectos
relativos a la navegacin (forwards), mappings, formularios, etc. se sigue definiendo en el fichero strutsconfig.xml.
En cada uno de los <action-mappings>, se debe inidcar el identificador (id) del bean que implementa
la lgica 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 (como en versiones
anteriores del openFWPA).

<action path="/login" type="login" scope="request" validate="false" input="/pages/l


<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>
En el cdigo anterior se puede ver cmo se realiza el mapeo, en el fichero struts-config.xml, de
las Actions definidas ms arriba como beans de Spring.

Atencin
Para poder realizar este tipo de mapeos es necesario utilizar como controlador (Controller)
la clase PrincastRequestProcessor:

<controller processorClass="es.princast.framework.web.action.PrincastRequestProc

Jerarqua de Actions
En el openFWPA se proporciona un conjunto de Actions de Struts. Estas Actions definen un nuevo
ciclo de ejecucin diferente del existente en las Actions tpicas de Struts (ver ms adelante). Las
aplicaciones que utilicen el openFWPA deben, obligatoriamente extender las Actions del Framework.
Adems de ser una imposicin, las Actions del openFWPA ofrecen funcionalidad de uso habitual en
las aplicaciones web.

Figura 2.6. Jerarqua de Actions

PrincastAction
La clase base de la jerarqua es PrincastAction. Es una clase abstracta que implementa una mquina
de estados de la que podrn hacer uso el resto de Actions. Define mtodos que deben ser sobrescritos
por las actions de la aplicacin. Estos mtodos sobrescritos sern invocados por el framework para dar
respuesta a una solicitud de un cliente, y en un orden preestablecido. Este orden se presenta como un
esquema de la mquina de estados:

17

Arquitectura Modelo -VistaControlador con openFWPA

Figura 2.7. Maquinaria de Estados de PrincastAction

Cada uno de los mtodos que aparecen en la figura anterior tiene un cometido en particular. Este cometido
es el siguiente:
preProcess ()

Se emplea para comprobar las precondiciones que debe cumplir la


PrincastAction. En caso de que no se cumpla alguna precondicin
se debe dejar un registro de ello mediante la creacin de un error o un
mensaje, dependiendo de la gravedad del mismo. Al dejar constancia
de la incidencia se redireccionar el flujo de ejecucin hacia una
pgina de error o a una de alerta, invocndose findFailure() y
findAlert(), respectivamente. La forma de crear una incidencia se
detalla en la seccin 4.5.1.1.1.

executeActionLogic ()

Implementa la lgica de negocio de la PrincastAction. ste ser


el mtodo sobrescrito de forma obligatoria por todas las acciones que
hereden de PrincastAction.

catchException()

Se encarga del tratamiento de cualquier excepcin que se pueda lanzar


durante la ejecucin de la lgica de negocio de la PrincastAction.
Si no se quiere que la excepcin sea lanzada de nuevo debe notificarse
su tratamiento mediante la llamada al mtodo unsetException().
De esta forma se entender que todo el tratamiento necesario ya ha sido
llevado a cabo y la excepcin no ser elevada.

18

Arquitectura Modelo -VistaControlador con openFWPA


postProcess()

Se emplea para comprobar las poscondiciones que debe cumplir la


PrincastAction. En caso de que no se cumpla alguna poscondicin
se debe dejar constancia de ello mediante la creacin de un error o un
mensaje. Al dejar constancia de la incidencia se redireccionar el flujo
de ejecucin hacia una pgina de error o a una de alerta, invocndose
findFailure() y findAlert(), respectivamente. La forma de
crear una incidencia se detalla en la seccin 4.5.1.1.1.

findFailure()

Redirecciona a una pgina de error. Por defecto, la redireccin 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 redireccin a un forward
llamado failure.

findAlert()

Redirecciona a una pgina de alerta en la que se muestra un mensaje


informativo. Por defecto la redireccin se hace a un forward llamado
warning.

findSuccess()

Redirecciona a la pgina de xito, es decir, a aquella a la que se debera


ir si la ejecucin de la accin no tiene ningn error. Por defecto se
redirecciona a un forward llamado success.

Creando un error en una PrincastAction


El openFWPA posee soporte integrado a la gestin de errores para usuario. Por error se entiende cualquier
situacin anmala en la aplicacin, 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.

Atencin
El mtodo saveErrors(HttpServletRequest, List) est deprecado a partir de la
versin 1.5 del openFWPA . Los errores ya no se deben almacenar directamente en la request, en
su lugar, se utiliza el almacenamiento interno de las Action . Si se utiliza el mtodo deprecado,
las Actions pueden no funcionar correctamente.
A continuacin se muestra un ejemplo de creacin 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 aadirn 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 parmetro. En caso de que el mensaje lleve parmetros de la forma {0},{1},{2},{3},
un posible mensaje sera:

error.general=Ha ocurrido un error de tipo {0} a las {1} horas en {2} con usuario {
En este caso, la creacin del error sera como sigue:
java.util.List error = new java.util.ArrayList();
error.add(error.general);

19

Arquitectura Modelo -VistaControlador con openFWPA


error.add(GRAVE); // Parmetro {0}
error.add(15:30); // Parmetro {1}
error.add(Gestin de usuarios); // Parmetro {2}
error.add(Administrador) // Parmetro {3}
El usuario de la aplicacin vera el siguiente mensaje:

Ha ocurrido un error de tipo GRAVE a las 15:30 horas en Gestin de usuarios con usu

Creando un mensaje de advertencia en una PrincastAction


La forma de crear un mensaje de advertencia es similar al de la creacin de un mensaje de error, con la
salvedad de que en lugar de llamar al mtodo saveErrors(HttpServletRequest, List) se ha
de invocar el mtodo saveMessages(List).

Modificando una redireccin


En el curso de tratamiento de una peticin, puede ser necesario redirigir la peticin a otro servlet.
PrincastAction proporciona una implementacin por defecto para las redirecciones que pueden tener
lugar durante la ejecucin de una peticin a una accin. Los mtodos 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 redireccin de estos mtodos es devolviendo una instancia diferente del
ActionForward. Por ejemplo, imaginemos que cuando la ejecucin de la PrincastAction es
xitosa deseamos que se nos redireccione a un forward etiquetado como ok. En este caso, deberamos
sobrescribir el mtodo findSuccess() como se muestra a continuacin:
ActionForward findSuccess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
return mapping.findForward(ok);
};
Como se puede apreciar en el ejemplo anterior, la cuestin es obtener del mapping (o crear indicando el
path) un ActionForward a donde deseamos redireccionar la repuesta.
ActionForward findSuccess(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
return new ActionForward("ok", "/action/test?method=ok", true);
};

20

Arquitectura Modelo -VistaControlador con openFWPA

Almacenamiento interno de una Action


Las Actions de Struts no son thread-safe. No es correcto utilizar atributos de instancia para compartir
informacin entre los distintos mtodos 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 almacn es un mapa de parmetros thread-local, cuyo mbito se limita a los mtodos del
ciclo de vida de la Action (preProcess(), executeActionLogic(), catchException()
y postProcess()).

Figura 2.8. Almacenamiento de la Action


Para acceder y manipular este almacenamiento, la PrincastAction dispone de los siguientes mtodos:
deleteActionParameter(nombre)
Borra del almacn el parmetro especificado.
getActionParameter(nombre)Obtiene del almacn el parmetro cuyo nombre se especifica.
getActionParameters()

Obtiene un iterador con los nombres de todos los parmetros del


almacn.

setActionParameter(nombre,Almacena un parmetro identificndolo con el nombre dado.


valor)
A continuacin se muestra un ejemplo de uso de este almacn:
public class MyAction extends PrincastAction {
public MyAction(){
setActionParameter("oneParam", "oneValue");
}
protected void preProcess(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
setActionParameter("myParam", "foo");
}
protected void executeActionLogic(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String param1 = (String) getActionParameter("myParam");
String param2 = (String) getActionParameter("oneParam");

}
}
En la Action del ejemplo: MyAction, se han sobrescrito dos mtodos del ciclo de vida de la Action:
preProcess() y executeActionLogic(). En el mtodo preProcess(), se establece el valor
de un parmetro: myParam, asignndole la cadena foo. Por otro lado, en el constructor, se establece
un valor para el parmetro oneParam. En el mtodo executeActionLogic(), se recuperan los
valores de ambos parmetros. Recurdese que nicamente los mtodos del ciclo de vida de la ejecucin de
la Action tienen visibilidad del almacn. Por este motivo, en el mtodo executeActionLogic(),
la variable param1 tomar el valor foo, mientras que la variable param2 tendr como valor null.

21

Arquitectura Modelo -VistaControlador con openFWPA

Interrupcin 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 ejecucin de la Action, basta con disparar una excepcin
de tipo ActionProcessInterruption.
Un uso prctico de esta excepcin es el siguiente:
Paginacin sin reejecucin de la lgica de negocio.
El problema es el siguiente: utilizando la librera Display Tag, cada vez que se produzca un movimiento de
pgina, se solicita una nueva ejecucin de la Action que genera el listado, suponiendo esto la reejecucin
de la lgica de negocio completa (con acceso a datos incluido). La solucin 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, aadir a la URL de la Action un
parmetro GET (que la 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 mtodo preProcess(). En este mtodo se detectar la existencia del parmetro 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 opcin es utilizar una de las Actions que ya vienen con esta funcionalidad implementada:
PrincastCRUDAction y PrincastListAction.

Diferentes tipos de PrincastAction


Adems de la clase base PrincastAction, en el openFWPA se proporcionan otros tipos de Actions.
Por un lado estn PrincastDispatchAction y PrincastCRUDAction, una generalizacin 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 gestin.

Implementaciones concretas
Existen varias clases que tienen una funcionalidad determinada y que pueden ser reutilizadas tal y como
estn. Estas son:
PrincastExistAttributeAction
PrincastRemoveAttributeAction

22

Arquitectura Modelo -VistaControlador con openFWPA


PrincastForwardAction
PrincastParameterAction
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 aplicacin web. En la propiedad "parameter" del <actionmapping> se indicar el scope y el nombre del atributo a eliminar, 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 parmetros, se produce un error.
PrincastRemoveAttribute
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").
Para indicar que la bsqueda se realice en todos los mbitos, el primer parmetro debe ser un asterisco
("*") en lugar del nombre de un mbito (parameter="*;HORAS"). El atributo slo ser eliminado del
primer contexto en el que sea localizado.
PrincastForwardAction
Accin que redirecciona a la URI relativa al contexto especificada por la propiedad parameter del
ActionMapping. Esta clase puede ser usada para integrar la aplicacin con otra lgica de negocio de
otros componentes implementados como Servlets o pginas 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 .
PrincastParameterAction
Esta Action busca un parmetro en la request llamado dispatch y usa su valor para recuperar
un forward local. Una vez conseguido este forward busca un segundo parmetro 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 redireccin. Un ejemplo de la declaracin de una
PrincastParameterAction de este tipo es:
<action
path="/menu/busca"
type="es.princast.framework.web.action.PrincastParameterAction"
name="menuForm"
validate="false"

23

Arquitectura Modelo -VistaControlador con openFWPA


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 pgina JSP que hiciera uso de esto podra ser:
<html:form action="menu/busca">
Busca artculos 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 informacin 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 parmetros almacenados en la request utilizando la notacin ${<nombre del parmetro>}.
La PrincastParameterAction buscar, en el path (definido en el forward) la cadena
"${<parmetro>}" y la sustituir por <parmetro>=<valor de parmetro>". Si, por
ejemplo, el valor del parmetro "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.

Actions Compuestas (Dispatch)


En muchas ocasiones interesa tener juntas aquellas acciones que se encargan de tareas relacionadas. Los
mtodos que se encargan de la ejecucin de tales tareas son encapsulados en una misma clase. Para estos
casos estn pensadas las acciones que se presentan en este apartado: PrincastDispatchAction,
PrincastCRUDAction.
PrincastDispatchAction
Esta clase es una especializacin de la PrincastAction. Mantiene la misma estructura de mquina
de estados que su clase padre pero se puede decir que cada una de las acciones que encapsula dispone de
su propia mquina de estados.
Si por ejemplo queremos encapsular juntas las acciones update e insert tendramos:
updatePreProcess, updateExecuteActionLogic, etc. - y tambin insertPreProcess,
insertExecuteActionLogic, etc. A pesar de que cada accin pueda tener su propia mquina de
estados, puede interesar que las acciones compartan determinada funcionalidad. Para estos casos estn los
mtodos defaultPreProcess, defaultExecuteActionLogic, etc.

24

Arquitectura Modelo -VistaControlador con openFWPA


Cmo identificar los mtodos a ejecutar?
A la hora de seleccionar los mtodos a ejecutar la PrincastDispatchAction hace uso del valor
que se le pasa en el parmetro parameter del ActionMapping asociado. Si lo que queremos es ejecutar
los mtodos de la mquina de estados asociada a la accin update, entonces este parmetro debe ser
<action-mapping parameter="method" .. />, donde el valor del parmetro method,
ser update. Si no se da implementacin a alguno de los mtodos update<estado_mquina>,
por ejemplo updatePreProcess(), la PrincastDispatchAction ejecutar el mtodo
defaultPreProcess(). De igual modo ocurre con el resto de mtodos.
Es posible desacoplar el valor del parmetro del nombre del mtodo. Se pueden establecer mapeos
{valor_de_parameter, nombre_de_mtodo} extendiendo el mtodo getMethodKey() de la clase
PrincastDispatchAction.
La PrincastDispatchAction permite, por defecto, una salida de xito (success), otra de error
(error) y para cada mtodo de la Action. Por convenio, en la PrincastDispatchAction, la
salida de xito de un mtodo ser un forward cuyo nombre ser el mismo que la clave del mtodo. El
forward de error equivaldr al nombre del mtodo concatenado con la cadena -failure. Para el
forward de advertencia se concatenar la cadena -warning al nombre del mtodo.
<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
mtodos: method1 y method2. Cuando se ejecute con xito el mtodo method1, se redireccionar
al path: success.path. Si hay algn error, la redireccin se realizar al path: failure.form.
Por el contrario, cuando se ejecute el mtodo method2, en caso de xito la redireccin se har
al path: success.dos.path y cuando se produzca un error, el path de redireccin ser:
failure.path (ya que, aunque no ha sido definido un forward de error especfico, se ha definido el
forward de error por defecto: failure).

Figura 2.9. 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 mtodos de dispatch. Al igual que ocurre con
otros mtodos de la Action (executeActionLogic(), catchException(), etc.) es posible
redefinir los mtodos de redireccin (findSuccess(), findAlert() y findFailure()). El
sistema es exactamente el mismo: prefijar cada mtodo con la clave (MethodKey). Por ejemplo:
method1FindSuccess(), method2FindFailure(), etc.
PrincastLookupDispatchAction
La clase PrincastLookupDispatchAction pemite implementar un tipo especial de Dispatch
Actions para formularios con mas de un botn (submit). Es este escenario, el botn que se utilice para
el envo del formulario (submit) ser quien determine el mtodo que se ejecutar en la Action.

25

Arquitectura Modelo -VistaControlador con openFWPA


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 botnoes del formulario
y los claves para seleccionar los mtodos de la Action.
Para extender LookupDispatchForm se debe implementar el mtodo getButtonKeys(),
devolviendo un array que contendr las posibles claves que se contemplan para seleccionar el mtodo a
ejecutar. Por otro lado, el formulario maneja otro array (buttons), del mismo tamao, con una posicin
reservada para cada botn.
Al enviarse el formulario, el array buttons, tendr todos sus campos nulos, salvo el correspondiente
al botn utilizado para el envo (submit). Para seleccionar el mtodo a ejecutar, se utilizar la clave
almacenada, en el array de claves, en la misma posicin que el botn activo.
En el ejemplo que se muestra a continuacin, se presenta un formulario con tres botones "Aceptar",
"Volver" y "Cancelar". Cada uno de estos botones ejecuta un mtodo distinto: "foo1" para "Aceptar",
"foo2" para "Volver" y "foo3" para "Cancelar".
public class FooLookupForm extends LookupDispatchForm {
public String[] getButtonKeys() {
return new String[]{"foo1", "foo2", "foo3"};
}
}
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 implementacin son
exactamente iguales que las PrincastDispatchAction habituales.
<html:form action="test">
<html:submit property="buttons[0]" value="Aceptar"/>

26

Arquitectura Modelo -VistaControlador con openFWPA


<html:submit property="buttons[1]" value="Volver"/>
<html:submit property="buttons[2]" value="Cancelar"/>
</html:form>
En la JSP cada botn submit se debe asignar, por orden, a una entrada del array "buttons".
PrincastCRUDAction
Esta Action est pensada para la gestin del ciclo de vida de entidades del modelo de la aplicacin. Esta
dos Action define los mtodos del ciclo de vida de una entidad:
new

Este mtodo debe precargar los campos necesarios para mostrar el formulario de creacin
de una nueva entidad.

retrieve

Este mtodo permitir recuperar una entidad.

list

Este mtodo debe obtener listados de entidades.

delete

Permite borrar una entidad.

update

Permite actualizar los datos de una entidad.

create

Este mtodo servir para inserter nuevas entidades.

Atencin
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 validacin de formularios
desactivada (validate = true) y se utilziar para solicitar los mtodos que no requieren un
formulario: new, retrieve, list y delete. El otro mapeo tendr la validacin activada y
se utilizar para los mtodos 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"/>
<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 tambin soportan, adems, paginacin sin necesidad de reejecutar la lgica de negocio
(Ver Paginacin sin reejecucin de la lgica de negocio.). Basta con incluir en la request el parmetro

27

Arquitectura Modelo -VistaControlador con openFWPA


paginate. En el caso de esta Action, al contrario que la PrincastListAction, hay que registrar
el objeto que se devuelve para listar, explcitamente en la session.
Validacin de Formularios en acciones compuestas
La validacin de formularios, en el framework Struts, redirecciona de forma automtica, en caso de error,
a una pgina de input definida en el mapeo de la action (en el fichero struts-config.xml).
Este sistema tiene una limitacin y esta es que las Actions compuestas (DispatchAction) solamente
pueden definir una nica pgina de input para todos sus mtodos.
El openFWPA permite solucionar esta limitacin del framework Struts. Para ello, basta con seguir los
siguientes pasos:
1. Utilizar
el
controlador
PrincastTilesRequestProcessor
(deprecado)
o
PrincastRequestProcessor.
Para
ello,
es
necesario
incluir
la
siguiente
definicin
de
controlador
en
el
fichero
struts-config.xml:
<!-Para
poner
multiples
input
-->
<controller
processorClass="es.princast.framework.web.action.PrincastRequestProcessor"
/
>
2. En el mapeo de la action compuesta (DispatchAction) que tiene ms de una entrada, dejar la
definicin de input vaca.
3. Para cada mtodo 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">
<forward name="create" path="/action/productosAction?method=list"/>
<forward name="update" path="/action/productosAction?method=list"/>
<forward name="createInput" path="facturas.addProducto"/>
<forward name="updateInput" path="facturas.detalleProducto"/>
Actions para Listados
Un subconjunto especial de Actions son aquellas que no tienen ninguna lgica de negocio especial.
Su nico objetivo es obtener un conjunto de objetos para ser mostrados. En funcin de si el listado
se mostrar en una pgina HTML o en un PDF, se utilizar la PrincastListAction o la
PrincastPDFReportAction.

Figura 2.10. Esquema de las Actions para listados

PrincastListAction
Si una Action tiene nicamente como propsito obtener un listado, se puede utilizar la
PrincastListAction. No hace falta sobrescribir ningn mtodo del ciclo de vida de esta Action,
basta con implementar el mtodo getContentList() y devolver el objeto (o coleccin de objetos)
que sern mostrados. El objeto devuelto quedar registrado en sesin, bajo la clave que se especifique en
el atributo parameter, en el mapeo de ese action, en el fichero struts-config.xml.

28

Arquitectura Modelo -VistaControlador con openFWPA


En caso de que no se especifique ningn valor para el atributo parameter se disparar una excepcin
de tipo PrincastActionProcessException
Esta Action permite realizar paginacin sin necesidad de reejecutar la lgica de negocio (Ver Paginacin
sin reejecucin de la lgica de negocio.).
PrincastPDFReportAction
Esta Action permite obtener un listado en formato PDF utilizando las utilidades para generacin de
informes de openFWPA (Ver Generacin de Informes). Para implementar una Report Action,
basta con redefinir el mtodo 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 mtodo loadReport() que devuelve el InputStream correspondiente al fichero del
informe. Este mtodo, 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 mtodo
getRelativePathToReportFolder().
PrincastDispatchPDFReportAction
Este Action es la versin dispatch de la PrincastPDFReportAction, permite definir varios mtodos
para obtener el PDFProvider, por ejemplo, si el parmetro pasado al Action es myMethod se ejecutara
el mtodo myMethodGetReport. Para ms informacin, consultar el Javadoc de la clase y la Actions
Compuestas (Dispatch).
PrincastXMLAction
Este Action permite servir contenido XML. Para servir una respuesta XML, basta con implementar el
mtodo getXMLProvider, que retorna un proveedor de contenido XML.
El proveedor de contenido XML, ser una clase que implemente el interfaz XMLProvider, el cual, obliga
implementar el mtodo writeXML(Writer writer). Donde simplemente se escribir el XML, a
servir.
PrincastDispatchXMLAction
Este Action es la versin dispatch de la PrincastXMLAction, permite definir varios mtodos para
obtener el XMLProvider, por ejemplo, si el parmetro pasado al Action es myMethod se ejecutara
el mtodo myMethodGetXMLProvider. Para ms informacin, consultar el Javadoc de la clase y la
Actions Compuestas (Dispatch).

Action Forms
El 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 automtica al hacer
un forward entre diferentes acciones, establezca el valor de mutable a true y asegrese
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 sesin de Struts siempre que se llame a reset(). Para actualizar el locale de la sesin
debe usarse putSessionLocale().

29

Arquitectura Modelo -VistaControlador con openFWPA


En cuanto a los mtodos:
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.

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 sesin e la peticin en curso bajo la clave
Globals.LOCALE_KEY.
putSessionLocale(HttpServletRequest)
Cambia el atributo Globals.LOCALE_KEY de la sesin 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 cdigo de lenguaje ISO dado. Recibe


como atributo un String con el cdigo del pas.

isBlank(String)

Comprueba si el String que se le pasa es null o la cadena vaca.

describe()

Devuelve
un
Map
con
las
propiedades
de
esta
PrincastActionForm.
Se
usa
el
mtodo
PropertyUtils.describe(). Sobrescriba el mtodo si
considera que alguna propiedad no debera ser mostrada de este
modo, o si un nombre de una propiedad debera ser cambiado. Este
mtodo devuelve las propiedades pblicas.

set(PrincastValueObject)

Rellena las propiedades de la clase con las del


PrincastValueObject que se le pasa como parmetro. Se
proporciona una implementacin vaca de este mtodo para que sea
sobrescrito.

populate(PrincastValueObject)
Permite cargar los datos del formulario sobre un Value Object. Este
mtodo recibe como parmetro 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 definicin de ActionForms dinmicos, se incluye en el openFWPA una clase base:
PrincastDynaActionForm. Se incluye adems 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 mtodo de dispatch que se ejecutar para
procesarlo. Las clases para la implementacin de formularios se encuentran en el paquete:
es.princast.framework.web.form.
La clase LookupDispatchForm permite disponer de formularios con ms de un botn de
submit. Para obtener ms informacin acerca de este tipo de forms, vase el apartado
PrincastLookupDispatchAction en la seccin dedicada a las Actions.

30

Arquitectura Modelo -VistaControlador con openFWPA

Desarrollo de lgica de negocio


Es importante disponer de un buen diseo tcnico antes de programar la lgica de negocio. En este rea
intervienen dos tipos de objetos: Business Delegates y Business Managers. Los objetos Delegate se
encargarn de crear y gestionar los objetos de lgica de negocio y proporcionarn un interfaz, para la
aplicacin web, de los mtodos de negocio. Los objetos "Manager", se encargarn de implementar la propia
lgica de negocio.

Figura 2.11. Estructura de la capa Modelo

Utilizando esta estructura, se puede modificar la implementacin del servicio sin que sea necesario
modificar el resto de la aplicacin. Un ejemplo de implementacin puede verse en la aplicacin de ejemplo
(Sample App). En ningn caso la lgica de negocio ha de tener dependencias con el protocolo http (como
por ejemplo hacer uso de la sesin), 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).

Service Locator
El patrn de diseo Service Locator permite encapsular, en una clase, la localizacin y acceso a objetos de
servidor. El openFWPA incluye un componente que implementa este patrn: la clase ServiceLocator.
El ServiceLocator proporciona los siguientes mtodos para la bsqueda de objetos:
getDataSource()

Permite instanciar un DataSource definido en el servidor (En


OC4J, en el fichero data-sources.xml)

getLocalHome()

Obtiene un interfaz ejbHome (local) para la creacin de un EJB.

getRemotelHome()

Obtiene un interfaz ejbHome (remoto) para la creacin de un EJB.

getQueue()

Obtiene una cola de mensajes JMS.

getQueueConnectionFactory()
Obtiene una factory de conexiones a colas de mensajes JMS.
getTopic()

Obtiene un Topic JMS.

getTopicConnectionFactory()
Obtiene una factory de conexiones a Topics JMS

Session EJBs
Habitualmente, es necesario, cuando se trabaja con Session EJBs, gestionar, para cada uno de ellos,
de forma especfica el mantenimiento del contexto de la sesin (SessionContext). Para evitar la
obligacin de implementar los mtodos de mantenimiento de la sesin, se ha incluido en el openFWPA,
una clase base para los Session EJBs: PrincastSessionEJBTemplate. Esta clase implementa los
mtodos setSessionContext() y unsetSessionContext(), dejando la instancia del contexto
en la variable protegida context.

Value Objects
Los objetos de datos (Patrn Value Object), en las aplicaciones desarrolladas sobre el openFWPA, deben
implementar el interfaz PrincastValueObject.

31

Arquitectura Modelo -VistaControlador con openFWPA

Figura 2.12. Diagrama de Value Objects

Esta interfaz define el mtodo toXML() que permite ver una descripcin del objeto en formato XML.
Para facilitar la implementacin de Value Objects, se han includo dos clases base: BasePrincastVO,
que realiza una implementacin por defecto para el mtodo toXML() basada en reflectividad, y
BasePrincastLazyLoadingVO, que debe ser utilizada si los Value Objects de la aplicacin se van
a usar en conjuncin con Lazy loading de los Value Objects.
Ambas clases extienden la clase AbstractBasePrincastVO, que define otro mtodo de utilidad:
toPropertyBeans().
En la clase BasePrincastVO, este mtodo permite "desmenuzar" un VO, mapendolo a una lista
de objetos de tipo PropertyBean. El nombre de la propiedad se asignar al campo "value" del
PropertyBean. El valor se asignar al campo "label".
Si alguna de las propiedades del VO es un objeto compuesto (una lista, una tabla, un array u otro VO)
estos sern, a su vez, descompuestos. Se seguir el siguiente convenio de nombrado para las propiedades:
Propiedades de tipo VO
(PrincastValueObject)

Si una propiedad es de tipo PrincastValueObject, el nombre


de cada una de sus propiedades se mapear siguiendo
el patrn: <nombre
de
la
propiedad
de
tipo PrincastValueObject>.<nombre de cada
propiedad del VO>

Propiedades de tipo List o arrays

El nombre de este tipo de propiedades se compone como sigue:


<nombre de la propiedad>[<posicin de cada una
de las propiedades de la lista>]

Propiedades de tipo Map

El nombre de este tipo de propiedades se compone como sigue:


<nombre de la propiedad>(<clave en el Map>).

Tambin se ha empaquetado en el Framework un tipo de Value Object muy habitual: PropertyBean.


Este objeto es un Value Object que almacena pares {valor-etiqueta}. La clase PropertyBean tambin
dispone de un mtodo esttico: pupulateList() que recibe como parmetro un Map y lo transforma
en una lista de PropertyBeans.
Debe tenerse en cuenta que la clase BasePrincastLazyLoadingVO tiene implementaciones vacas
para los mtodos toPropertyBeans() y toXML(), por lo que debern ser sobreescritos por los Value
Objects de la aplicacin en caso de necesitar un comportamiento diferente.

Excepciones
El openFWPA dispone de su propia jerarqua de excepciones. La poltica general de manejo de excepciones
en el openFWPA es que se utilicen excepciones Runtime (no manejadas estticamente).

Figura 2.13. Jerarqua de Excepciones

La clase base para la creacin de excepciones es PrincastException. Existen dos ramas en esta
jerarqua de excepciones runtime: excepciones de sistema (PrincastSystemException), reservadas
para el openFWPA y sus componentes y excepciones de modelo (PrincastModelException), que
son disparadas por las excepciones.

32

Arquitectura Modelo -VistaControlador con openFWPA


Como norma general, las aplicaciones no berin nunca extender las excepciones del sistema. Siempre
deben extender PrincastModelException.
Adems, el openFWPA tambin tiene una clase base para la creacin de excepciones gestionadas:
PrincastRequiredHandlingException.
La excepcin DeprecatedAPIException se reserva para ser disparada desde mtodos deprecados
en los que no sea posible implementar una lgica alternativa.

Utilidades
Junto con las excepciones, se incluye una clase (ToXMLExceptionHelper) auxiliar para facilitar el
fromateo de las mismas y su traduccin a XML.

Otras clases de utilidad


Junto a las Actions, en el paquete web se incluyen algunas clases de utilidad para los componentes de
la capa de aplicacin.

PrincastMessageFmtter
Clase para facilitar el formateo de cadenas de caracteres (mensajes, etc). Esta clase permite:
Reemplazar tokens en un String. Mtodo replace().
Formatear un mensaje, siendo ste una cadena con parmetros del tipo {0}, {1}, {n}. Este
mtodo (format()) recibir como parmetros una cadena de texto y un array de objetos. El objeto en
la posicin 0 se introducir en lugar de la subcadena {0} y as sucesivamente.

PrincastUtils
Contiene mtodos de utilidad general. Actualmente nicamente implementa el mtodo
normalizePath() que tiene como objetivo normalizar los paths en los distintos sistemas operativos.

ParameterCaster
Clase de utilidad para la capa web. Permite traducir el tipo (casting) de los parmetros que se reciben de
una request http.

ServletPathUtils
Clase de utilidad del paquete web que permite gestionar paths de peticiones http. Los mtodos que define
son:
match()

Valida si un path se ajusta a un patrn URL (url-pattern)


determinado.

extractRelativePath()

Obtiene el path relativo a partir de un path absoluto.

getCompleteURL()

A partir de una request, obtiene la URL solicitada completa,


incluyendo los parmetros GET.

getURLParametersSeparator()
A partir de una URL, determina si los parmetros que se vayan
a aadir a continuacin se preceden de un carcter ? &,

33

Arquitectura Modelo -VistaControlador con openFWPA


en funcind e si dicha URL ya tena, o no, parmetros GET
anteriormente.

DateDecorator
Clase que facilita la escritura de fechas y horas con un formato determinado. Esta clase implementa
el patrn Decorator sobre la clase java.util.Date, sobrescribiendo su mtodo toString().
La clase es.princast.framework.core.util.DateDecorator permite definir el patrn
de formato que se aplicar al obtener la representacin textual de la fecha utilizando el mtodo
Date.toString().
Adems, tambin define los patrones para los formatos de fecha ms comunes:
/**
* Formato corto para las fechas tomando como separador el caracter /.
*/
public static final String SHORT_DATE = "dd/MM/yyyy";
/**
* Formato corto para las fechas tomando como separador el caracter -.
*/
public static final String SHORT_DATE_DASH = "dd-MM-yyyy";
/**
* Formato para mostrar slo horas, minutos y segundos. Las horas varan en
* el rango 0..24.
*/
public static final String ONLY_TIME = "HH:mm:ss";
/**
* Formato largo para la fecha, tomando como caracteres de separacin el
* caracter / para da, mes, ao y el caracter : para horas, minutos y
* segundos.
*/
public static final String LONG_DATE = "dd/MM/yyyy HH:mm:ss";
/**
* Formato largo para la fecha, tomando como caracteres de separacin el
* caracter - para da, mes, ao y el caracter : para horas, minutos y
* segundos.
*/
public static final String LONG_DATE_DASH = "dd-MM-yyyy HH:mm:ss";

PrincastPathResolver
El objetivo del PrincastPathResolver es ofrecer, al programador de aplicaciones, un punto
centralizado para resolver paths (a recursos) uniformemente.
Este objeto (que implementa el patrn Singleton) define los siguientes mtodos:
resolvePath(path)

Resuelve un path, que se especifica por parmetro, devolviendo el path


absoluto.

resolveToFile(path)

Resuelve un path, devolviendo el objeto File correspondiente.

34

Arquitectura Modelo -VistaControlador con openFWPA


resolveToStream(path)

Resuelve un path, devolviendo un stream de lectura sobre el recurso


que se halle en dicho path. Si no encuentra ninguno, dispara una
FileNotFoundException.

Existen varios tipos de "path resolvers" en el openFWPA, en funcin del tipo de


aplicacin. En general, se puede asignar cualquier tipo de "path resolver" definido por
el usuario. Para ello, basta con extender la clase PrincastPathResolver y utilizar el
mtodo PrincastPathresolver.registerResolver(). Los resolvers implementados en el
openFWPA son:
DefaultPathResolver

Implementacin por defecto. Resuelve paths absolutos y relativos al


classpath y al "working dir" de la aplicacin.

WebAppPathResolver

Implementacin por defecto en aplicaciones web (siempre que utilicen el


PrincastStartupListener). Resuelve paths absolutos y relativos
al classpath y al directorio de despliegue de la aplicacin.

PrincastOSCacheInterceptor
Esta clase permite a travs de Spring y OSCache, realizar cacheos transparentes de las llamadas a cualquier
mtodo de cualquier bean de Spring. Esto es til, por ejemplo para cachear las llamadas al sistema de
Genricos del Gobierno del Principado de Asturias.
El uso de esta clase est documentado en la Javadoc. La funcionalidad por defecto establece una cach
por mtodo cacheado, donde la clave para buscar en la cache es la concatenacin del toString, de los
argumentos. Si dos llamadas al mismo mtodo tienen el mismo toString concatenado de los argumentos
se devuelve el resultado cacheado. Este comportamiento se puede sobreescribir heredando de la clase.
El tiempo de refresco se establece en la definicin de bean, por defecto son 600 segundos se recomienda
ver la Javadoc, para ver la sintxis de los tiempos de refresco en funcin del mtodo.

Providers
Para aislar la capa de acceso a datos de otras capas de la aplicacin, habitualmente es buena idea definir
interfaces providers. Estos interfaces proporcionan datos a la capa del controlador, o directamente a la
vista, sin indicar donde ni cmo se obtienen esos datos. El controlador (o la vista) pueden manipular los
providers directamente sin preocuparse de cmo stos se han obtenido.
Desde la versin 1.5 del openFWPA, los providers
es.princast.framework.facilities.providers.

se

encuentran

en

el

paquete:

El openFWPA define un conjunto de providers habituales:


EntityContentProvider

Se trata de un proveedor de entidades. Este interfaz devuelve una


sola entidad que puede ser utilizada directamente. Por ejemplo, para
mostrar sus datos en un formulario.

ListContentProvider

Provee conjuntos de entidades. Este interfaz devuelve listas de


entidades. Se pueden utilizar para listados.

PaginatedContentProvider

Provee listas paginadas de entidades. Este interfaz proporciona


listas que pueden recorrerse de forma paginada. Se pueden utilizar
en listados en los cuales toda la lista no cabe en una sola pgina
HTML

35

Arquitectura Modelo -VistaControlador con openFWPA


PDFProvider

Provee documentos en formato PDF. Este interfaz proporciona un


array de bytes que contienen un documento PDF. Se puede utilizar
para la realizacin de informes o documentos.

XMLProvider

Provee contenido en formato XML. Este interfaz proporciona


un mtodo writeXML(Writer writer), donde se escribir
directamente el XML. Se puede utilizar para servir contenido XML,
junto con la PrincastXMLAction
.
Un ejemplo de este tipo de Provider, incluido en el openFWPA, es
el PrincastVelocityXMLProvider que provee contenido,
a travs del motor de plantillas Velocity. Su principal objetivo es
la generacin de contenido XML basado en plantillas, aunque se
puede usar para generar cualquier tipo de contenido. Para mayor
informacin acerca de su uso, se recomienda leer la Javadoc

PropertyBeansProvider

Es una implementacin del ListContentProvider que


provee a la aplicacin de beans de propiedades (PropertyBean).
El provider puede cargar estos beans de objetos Map o de ficheros
de properties (.properties).

Para conocer con mayor detalle el interfaz de cada uno de los providers, consltese la documentacin
Javadoc del openFWPA.

36

Captulo 3. Implementacin de la
Arquitectura de Referencia con
openFWPA
Inversin de Control en la Arquitectura de
Referencia
A partir de la versin 1.5 de openFWPA, se hace un uso intensivo de la inversin de control (IoC), para
implementar la arquitectura de referencia, en las aplicaciones realizadas con el openFWPA.
Para ello, se hace uso de Spring Framework, que ofrece la implementacin del patrn
AbstractFactory basado en ficheros XML. Esto permite, eliminar los elementos de unin en las
aplicaciones, como las factoras, y singletons. Adems, permite tener la arquitectura modularizada en
"piezas", que por estar definidas en un fichero XML, son intercambiables. Lo que deriva, en un sistema
dbilmente acoplado, ms tolerable a cambios y modificaciones.

Introduccin al manejo de la Arquitectura con


Spring
Para manejar la Arquitectura de referencia con Spring, se hace uso de una serie de ficheros XML, donde se
definen los beans que forman parte de la arquitectura del sistema. Estos ficheros estn ubicados en src/
java/beans y sigue la estructura de directorios, propuesta para la arquitectura.

Figura 3.1. Ficheros de configuracin de Beans

Los ficheros siguen la sintaxis de definicin de beans de Spring, al igual que el fichero de inicializacin
de openFWPA (princast-init-script.xml).
Para hacer uso de la inversin de control, es necesario seguir una serie de pasos. Como ejemplo, se va a ver
cmo se construye una clase Action dependiente de una clase Delegate desde cero. El proceso de inyectar
la dependencia se ha denominado "enlazado", tomndolo como traduccin libre del trmino "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
Manager, se introduce un campo o propiedad (privado o protegido), en la clase Action. Adems, 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 inversin de control se encarga de inicializarlo.
public class GetListaProductoAction extends PrincastListAction {
// inyeccion de dependencia (/beans/web/action-beans.xml)
protected CarritoDelegate carritoDelegate;

37

Implementacin de la Arquitectura
de Referencia con openFWPA
public void setCarritoDelegate(CarritoDelegate carritoDelegate) {
this.carritoDelegate = carritoDelegate;
}

protected Object getContentList(ActionMapping mapping, ActionForm form, HttpServle


//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.GetListaProdu


<property name="carritoDelegate"><ref bean="carritoDelegate" /></property>
</bean>

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 definicin es de un Delegate, por lo que estar definido en el fichero
delegate-beans.xml.

<bean id="carritoDelegate" class="es.princast.sampleapp.web.delegate.CarritoDelega


<property name="carritoManager"><ref bean="carritoManager"/></property>
<property name="formasPagoManager"><ref bean="formasPagoManager"/></property>
<property name="agenciasManager"><ref bean="agenciasManager"/></property>
</bean>

Estableciendo el Datasource
La inversin 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 continuacin se muestra un ejemplo de definicin del mismo:

<!-- JNDI Datasource -->

38

Implementacin de la Arquitectura
de Referencia con openFWPA
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/MySQLDS</value>
</property>
</bean>

En el caso de la aplicacin en blanco, para que una aplicacin pueda desplegar sin necesidad de datasource,
se ha definido un datasource nulo. Este datasource, sirve para poder enlazar las dependencias sin la
necesidad de un datasource real. En el momento que se disponga de uno real, es recomendable cambiarlo
por el datasource JNDI.

<!-- Datasouce Nulo, BORRAR cuando se use un datasource real -->


<bean id="dataSource" class="es.princast.framework.facilities.dao.PrincastNullD

Para realizar las pruebas unitarias, es necesario disponer de un datasource para realizar los test. En la
aplicacin de ejemplo, se suministra un test sobre una clase DAO, que utiliza un datasource para test. Un
ejemplo de definicin de datasource de test, es el siguiente:

<!-- DataSource para Test Unitarios -->


<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerD
<property name="driverClassName"><value>org.gjt.mm.mysql.Driver</value></pr
<property name="url"><value>jdbc:mysql://localhost/carrito</value></propert
<property name="username"><value>admin</value></property>
<property name="password"><value></value></property>
</bean>

Para ms informacin sobre la realizacin de pruebas sobre los DAOs, ver Pruebas unitarias de objetos
que acceden a bases de datos.

Enlazando con los DAOs


Una vez definido el datasource, se definen los DAOs, para ello se utiliza el fichero dao-beans.xml.
A continuacin se muestra un ejemplo de definicin:

<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.MySQLFormaPagoDA


<property name="dataSource"><ref bean="dataSource"/></property>
</bean>

39

Implementacin de la Arquitectura
de Referencia con openFWPA
Se recuerda que para que se produzca la inyeccin de la dependencia, la clase que implementa el DAO,
debe disponer de un setter para el campo dependiente, como se observa en el siguiente ejemplo:

public class MySQLCarritoDAO implements CarritoDAO, PrincastDAO {


// La conexion se injecta en /beans/business/dao-beans.xml
protected DataSource dataSource;
...
// Este setter es necesario para la injeccion de la conexion en
// la configuracion de los beans
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
...

Enlazando con los Managers


Para enlazar los DAOs con los Managers, se realiza en el fichero manager-beans.xml. Hay que tener
en cuenta, si el manager que se est definiendo, est sujeto a transacciones. A continuacin, se muestra
la declaracin 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.Agenci
</bean>

En el caso de estar sujeto a transacciones, la definicin del bean es un poco ms 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 definicin propiamente dicha de la clase Manager, se realiza dentro de la propiedad target, y se le
inyecta las dependencias normalmente. A continuacin, se muestra la definicin 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>

40

Implementacin de la Arquitectura
de Referencia con openFWPA

Como en los casos anteriores, la dependencia se establece por medio de la definicin de un setter, para
cada campo dependiente.

Gestin de transacciones
Desde el fichero transaction-bean.xml se controla la gestin de transacciones. Esta gestin se
realiza de forma declarativa, por lo que los Managers que hereden de estas plantillas de transacciones, no
tendrn que implementar cdigo para la gestin de transacciones, ni conexiones.
Antes de la definicin de la plantilla se establece un transactionManager sobre el datasource a
utilizar. Un ejemplo de definicin es el siguiente:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSou


<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 definicin de beans, los Manager que esten sujetos a transacciones
(mediante el atributo parent, visto en el apartado anterior). Se podran definir varias plantillas, en funcin
de las necesidades. Un ejemplo de plantilla para la gestin de transacciones es el siguiente:

<bean id="transactionTemplate" abstract="true"


class="org.springframework.transaction.interceptor.TransactionProxyFactoryB
<property name="transactionManager"><ref bean="transactionManager"/></prope
<property name="transactionAttributes">
<props>
<!-- Los metodos que comiencen por get en los Manager seran readOnl
<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 transaccin. Las transacciones se definen
a nivel de mtodo de un Manager, por lo que, cada ejecucin de un mtodo de un Manager establecera
una transaccin.
Adems se pueden establecer patrones, de forma que definiendo el patrn 'get*', las propiedades
establecidas para ese patrn, afectar a todos los mtodos del Manager que comiencen por 'get'.
De esta manera definiendo las propiedades, 'PROPAGATION_REQUIRED,readOnly' se tendr una
transaccin por mtodo, y adems estar optimizada para slo lectura.

41

Implementacin de la Arquitectura
de Referencia con openFWPA
El comportamiento por defecto, para la poltica de rollback, define que si se produce una excepcin de
tipo Runtime durante la ejecucin del mtodo, se har un rollback.
Algunas de las propiedades que se pueden establecer son:
PROPAGATION_LEVEL: Nivel de propagacin. Por defecto se establece el nivel de propagacin a
PROPAGATION_REQUIRED, esto significa que crear una nueva transaccin, slo si se necesita.
ISOLATION_LEVEL: Nivel de aislamiento. Por defecto trendr el valor ISOLATION_DEFAULT.
readOnly: Optimizacin de slo lectura. Se optimiza la transaccin para las operaciones de slo
lectura.
Lista de Excepciones: Establece la poltica de rollback o commit, al margen del comportamiento por
defecto. Por ejemplo, si se le aade la cadena '-MiExcepcion', se hara rollback en caso de que
dispare la excepcin de nombre 'MiExcepcion', aunque el tipo de excepcin no sea Runtime. Si se
aade la cadena '+OtraExcepcion', se har commit aunque la excepcin sea Runtime.
Para ms informacin sobre las propiedades disponibles consultar el manual de referencia de Spring.

Enlazado con los Delegates


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.CarritoDelega


<property name="carritoManager"><ref bean="carritoManager"/></property>
<property name="formasPagoManager"><ref bean="formasPagoManager"/></property>
<property name="agenciasManager"><ref bean="agenciasManager"/></property>
</bean>

Se recuerda que la clase CarritoDelegate debe disponer de un setter para cada dependencia.

Enlazado con las 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 definicin de beans para las Actions es el siguiente:

<bean id="viewlistaproducto" class="es.princast.sampleapp.web.action.GetListaProdu


<property name="carritoDelegate"><ref bean="carritoDelegate" /></property>
</bean>

En el caso de las Actions es importante establecer el atributo singleton="false", as se crear una


nueva instancia del action, por cada peticin de struts.

42

Implementacin de la Arquitectura
de Referencia con openFWPA
Una vez definidos los beans para las Actions deben ser referenciados desde el fichero strutsconfig.xml, la referencia se har mediante el atributo type. Hasta ahora, ese atributo referenciaba el
nombre cualificado de una clase, a partir de la versin 1.5, se buscar primero por id de bean definido
en el fichero action-beans.xml, si no encuentra ningn bean definido, tomar el nombre como el de
una clase, tal y como se haca en versiones anteriores.
Un ejemplo de un Action referenciando a una definicin de bean en struts-config.xml, es el
siguiente:

<action path="/viewdetalleproducto" name="detalleProductoForm" input="/index.jsp" t


<forward name="success" path="carrito.detalleprod" />
</action>

Se observa que el atributo type tiene el valor type="viewdetalleproducto" que coincide con
el id del bean definido en action-beans.xml.

Acceso directo al ApplicationContext


Otra forma de acceder a los beans (menos recomendable que las anteriores) declarados en cualquier
fichero de definicin de beans, cargado por la aplicacin, es utilizar el GlobalApplicationContext
(GlobalApplicationContext.getInstance().getApplicationContext()).
Este
contexto de aplicacin global es una clase singleton que da acceso directo al ApplicationContext
de Spring cargado por la aplicacin.

Atencin
En aplicaciones Struts, nicamente se puede acceder, por este mtodo, a los beans cargados por
el mdulo por defecto (mdulo sin prefijo).

BeanDoc para obtener la grfica de


arquitectura
Como la arquitectura esta reflejada en ficheros XML, se dispone de una herramienta para generar una
grfica de arquitectura, Spring BeanDoc, que es un subproyecto de Spring Framework.
Se dispone de una tarea Ant en la aplicacin de ejemplo para ejecutar esta herramienta, aunque deber estar
previamente instalada. Para instalarla, se debe ir a la pgina principal del proyecto Spring Framework, y
seleccionar el subproyecto BeanDoc, donde se indica cmo instalarla y configurarla.

Figura 3.2. Ejemplo de grfica generada con BeanDoc

Plugin SpringIDE para Eclipse


Para facilitar el desarrollo, y el tratamiento de ficheros de Spring, existe el plugin para Eclipse, SpringIDE
[http://springide.org/project].

43

Implementacin de la Arquitectura
de Referencia con openFWPA
Este plugin, permite ver de una forma visual la definicin de beans, adems incluye caratersticas como el
autocompletado de clases y el acceso directo desde el grfico de visualizacin, a la definicin del bean o
de la clase. Para su instalacin y primeros pasos, se debe acudir a la pgina del proyecto SpringIDE.

Figura 3.3. Spring IDE para visualizar ficheros de Spring

44

Captulo 4. Componentes para acceso


a datos
Acceso a Bases de Datos Relacionales
Un componente bsico de la capa de modelo Modelo es el acceso a datos (generalmente, a bases de datos
relacionales). Tal y como se especifica en la Gua de Aceptacin de Aplicaciones, no est
permitido el acceso a datos desde cualquier componente de la aplicacin que no pertenezca a esta capa
(pginas JSP, Actions, etc.). La herramienta clave para la implementacin de esta capa es el patrn de
diseo DAO (Data Access Object).

El patrn DAO
Para realizar el acceso a datos se utilizar el patrn DAO (Data Access Object). El openFWPA dispone de
una interface base PrincastDAO que deben de implementar todos los DAOs, o extender de una clase que
la implemente. Esta interfaz posee dos mtodos, getDataSource y setDataSource que permiten
obtener y establecer, el DataSource que utliza el DAO, para acceder a Base de Datos.
El framework tambin dispone de una clase de utilidad para facilitar la implementacin de objetos DAO: la
clase PrincastDAOHelper. Un objeto PrincastDAOHelper siempre debe estar asociado con un
objeto DAO (que se llamar OwnerDAO). Solamente los OwnerDAOs de un HelperDAO podrn acceder a
sus mtodos. Es altamente recomendable, que para mejorar el rendimiento general de la aplicacin, todos
los DAO de una misma clase puedan acceder al mismo DAOHelper a travs de una variable static.
La caracterstica ms interesante que proporcionan los DAOHelpers es la capacidad de cargar consultas
SQL desde un fichero .properties. Este fichero debe cumplir las normas de ficheros properties Java.
Cada propiedad del fichero se corresponder con una consulta SQL identificada por una etiqueta.
Las consultas SQL del fichero de properties pueden tener parmetros, utilizndose para ello el carcter
? de forma anloga a los PreparedStatement.
Los mtodos pblicos de esta clase DAOHelper son:
PrincastDAOHelper(Class)

Constructor del DAOHelper que recibe como parmetro el


OwnerDAO

getQueries()

Devuelve un Properties con las consultas manejadas por el


DAOHelper

getQuery(String)

Devuelve un String con la consulta cuya clave en el fichero de


properties se le pasa como parmetro.

getStament(String,
Object [])

Devuelve un String con la consulta construida, cuya clave en el


fichero de properties se le pasa como parmetro, haciendo uso de
los parmetros estructurales, que tambin se pasan como parmetro.

executeQuery(String,
Object[], Object[],
DataSource)

Devuelve una List de


consulta cuya clave en
como parmetro. Utiliza
le pasan en dos arrays:

45

Map con el resultado de ejecutar la


el fichero de properties se le pasa
como parmetros los objetos que se
a) El primero de los arrays contiene

Componentes para acceso a datos

parmetros estructurales. Se utilizan para componer una consulta


y se identifican por nmeros entre { y } (por ejemplo:
SELECT * FROM {0}; ). Este tipo de parmetros pueden
considerarse como comodines para todas aquellas situaciones
en las que no se puedan utilizar los parmetros estndar de la
clase java.sql.PreparedStatement. b) El segundo array
de parmetros contendr los valores de los parmetros estndar
(identificados por caracteres ?).
executeQueryForList(String,
Es equivalente a executeQuery.
Object[], Object[],
DataSource)
executeQueryForList(String,
Es equivalente a executeQueryForList. Salvo por el
Object[], Object[],
parmetro PrincastRowMapper, que permite mapear un
PrincastRowMapper,
ResultSet, a una clase de negocio (VO), esto permite que el
DataSource)
mtodo devuelva una lista de VOs.
executeUpdate(String,
Object[], Object[],
DataSource)

Ejecuta la consulta de actualizacin cuya clave en el fichero de


properties se le pasa como parmetro.

reload()

Refresca la tabla de consultas releyndolas del fichero properties


correspondiente.

Desde la versin 1.5 del framework, se ha introducido la posibilidad de mapear los ResultSet a clases de
negocio, generalmente VOs. Para ello se necesita crear una clase que herede de PrincastRowMapper,
e implemente el mtodo mapRow. Desde una clase DAOHelper se podr, usar y reutilizar estos
mapas, mediante llamadas al mtodo executeQueryForList que acepta como parmetro un
PrincastRowMapper. Un ejemplo de mapeo se puede observar en la clase ProductosMapper, en
la aplicacin Sample App.
public class ProductosMapper extends PrincastRowMapper{
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
ProductoVO producto = new ProductoVO();
producto.setId(rs.getInt("id"));
producto.setName(rs.getString("nombre"));
producto.setDescription(rs.getString("descripcion"));
producto.setSmallImageURL(rs.getString("smallImageURL"));
producto.setBasePrice(rs.getDouble("basePrice"));
return producto;
}
}
La aplicacin en blanco (App Blank) dispone de plantillas para la realizacin de DAOs (concretamente en
la clase DAOTemplate), y la aplicacin de ejemplo ( Sample App) dispone de un ejemplo de utilizacin
en la clase MySQLCarritoDAO.
public class MySQLCarritoDAO implements CarritoDAO, PrincastDAO {
...
protected static PrincastDAOHelper helper = new PrincastDAOHelper(
MySQLCarritoDAO.class);
...

46

Componentes para acceso a datos

/**
* Devuelve una List con todos los productos que maneja la aplicacin.
*/
public List getListaProducto() {
List listaProducto;

listaProducto = helper.executeQueryForList("listaProducto", null, new Object[] {}


new ProductosMapper(),dataSource);
return listaProducto;
}
...
}

Loggeo de las Excepciones en los DAO


Como se ha visto en captulos anteriores, a partir de la versin 1.5 no hace falta capturar las excepciones
producidas en el acceso a datos, sin embargo si que es recomendable imprimir en el log de la aplicacin, la
excepcin 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 automticamente.

<!-- Con estas dos definiciones se auditan todas las expcepciones que
se produzcan en los DAOs a nivel de log de ERROR-->
<bean id="loggerThrowsAdvice" class="es.princast.framework.facilities.interceptor.
<property name="level"><value>ERROR</value></property>
</bean>

<bean id="daoBeanAutoProxy" class="org.springframework.aop.framework.autoproxy.Bea


<property name="beanNames"><value>*DAO</value></property>
<property name="interceptorNames">
<list>
<value>loggerThrowsAdvice</value>
</list>
</property>
</bean>
La primera definicin de bean loggerThrowsAdvice, indica la clase de log que se va a usar. La
propiedad ms importante es el nivel de log, en el ejemplo se indica que las excepciones se van a loggear
a un nivel de ERROR (son vlidos los mismos niveles de log que para log4j).
La segunda definicin 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 patrn "*DAO", esto quiere decir que el log se aplica a todos los mtodos
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 definicin de bean de spring, por ejemplo todos los "Delegate"
con el patrn "*Delegate".

Listas clave/valor
Existe un tipo especial de DAO que permite acceder y manipular a informacin estructurada como listas
de pares clave/valor sobre una tabla de una base de datos. Se trata de la clase PropertiesTableDAO.
El principal uso de este tipo de objetos DAO es facilitar el acceso a listas de valores que puedan ser
utilizadas para cargar componentes de interfaz de usuario como inputs HTML de tipo select.

47

Componentes para acceso a datos

Esta clase devuelve objetos (o listas de objetos) del tipo PropertyBean, que tiene dos campos value
y label correspondientes a la clave y su valor asociado respectivamente.
Los mtodos pblicos de esta clase son:
PropertiesTableDAO(DataSource,
Constructor. Recibe un DataSource, el nombre de la tabla,
String, String, String)
nombre de la columna donde se almacenan las claves y nombre de
la columna que tiene los valores.
getAllProperties()

Devuelve una List de PropertyBeans con todos los pares de


la tabla.

getProperties(String)

Devuelve una List de PropertyBeans con los pares de la


tabla que se cumplen una determinada condicin especificada por
parmetro.

findProperty(String)

Devuelve el PropertyBean cuya clave se pasa como parmetro.

insertProperty(String,
String)

Inserta en la tabla de la base de datos un nuevo registro con la clave


y el valor que se pasan como parmetro.

updateProperty(String,
String)

Actualiza en la base de datos el valor de la clave especificada.

deleteAllProperties()

Elimina todos los pares clave/valor de la tabla.

deleteProperty(String)

Elimina el par cuya clave se pasa como parmetro.

getReportIterator(Object[])
Devuelve un Iterator con todos los pares de la tabla. Si el array que
se le pasa esta vaco o es nulo devolver todos los valores de la
tabla. Sin embargo, si contiene valores se buscarn todos los pares
cuya clave est en el array
Puede verse un ejemplo de utilizacin en la clase MySQLFormaPagoDAO, de la aplicacin de ejemplo
(Sample App).
public class MySQLFormaPagoDAO implements FormaPagoDAO, PrincastDAO {
...
protected static List formasPago = null;
public MySQLFormaPagoDAO() {}
/**
* Devuelve una List con las formas de pago existentes
*/
public List getFormaPago() {
// se mantiene en memoria las formas de pago en una variable static
if (formasPago==null){
PropertiesTableDAO propsTable = new PropertiesTableDAO(dataSource,
"formapago", "id","descripcion");
formasPago = propsTable.getAllProperties();
}
return formasPago;
}
...
}

48

Componentes para acceso a datos

Otra forma de crear listas de beans con pares atributo/valor (PropertyBean) es a partir de
un Map. La propia clase PropertyBean dispone de un factory method esttico que, recibiendo como
parmetro una referencia a un objeto Map, crea una lista de pares atributo / valor (PropertyBeans).
public static List populateList(Map props)

LookupPropertyBean
Una situacin habitual es aquella en la que se necesita navegar una relacin entre entidades. En esta
situacin, se dispone de una clave y se necesita obtener el valor de dicha clave.

Figura 4.1. Ejemplo de necesidad de lookup

Si en el modelo de la figura, se necesita hacer un listado con: {ARTICULO, DESCRIPCION} , es


necesario realizar una acceso a base de datos para cada entrada de la lista, o bien modificar el diseo
de la aplicacin, cambiando los campos de la clase ArticuloVO. Una forma ms sencilla es utilizar
el componente LookupPropertyBean, que proporciona el openFWPA. Este bean permite, recibiendo una
clave, obtener el valor asociado a dicha clave.

Figura 4.2. Navegacin de una relacin en BD con un LookupPropertyBean

En ocasiones, los datos sobre los que hay que hacer " lookup ", no estn almacenados en una base de
datos. Estos datos pueden estar en memoria, en un Map o en una lista de PropertyBeans . Para poder
manejar todas estas situaciones, el componente LookupPropertyBean , dispone de los siguientes
constructores:
LookupPropertyBean(DataSource
Constructor estndar para este tipo de objetos. Asocia el lookup
dataSource, String
bean con una base de datos. Como parmetros debe recibir: el
tableName, String
dataSource de la base de datos, la tabla en la que se almacenan los
keyColumn, String
datos de la relacin, el nombre de la columna de las claves y el
valueColumn)
nombre de la columna de los valores.
LookupPropertyBean(Map
props)

Utilizando este constructor, la relacin lookup se realiza sobre los


datos almacenados en un Map.

LookupPropertyBean(List
beans)

Este constructor debe recibir como parmetro una lista de objetos de


tipo PropertyBean. Las claves de la asociacin se corresponden
con la propiedad " value" de los beans y los valores, con al
propiedad " label". Cualquier objeto en la lista que no pertenezca a
la clase PropertyBean ser ignorado.

Providers
A partir de la versin 1.5 del openFWPA, los providers estn ubicados en el
paquete: es.princast.framework.facilities.providers. Los providers del paquete
es.princast.framework.dao.providersestn deprecados. Ver Providers.

Generadores de Secuencia
Otra utilidad incluida en el openFWPA son los generadores de secuencia. Este tipo de objetos permiten
generar secuencias de nmeros consecutivos. Su utilidad ms habitual es la generacin de claves primarias.

49

Componentes para acceso a datos

La clase base para generadores de secuencia, en el openFWPA, es SequenceGenerator, cuyo mtodo


ms relevante es: generateId().
Se
proporcionan
dos
implementaciones:
MySQLSequenceGenerator
OracleSequenceGenerator que utilizan bases de datos MySQL y Oracle respectivamente.

Pools de conexiones
La configuracin de Pools de conexiones en el contenedor oc4jse realiza en el fichero
datasources.xml. El propio fichero trae un ejemplo de configuracin para base de datos Oracle, y en la
aplicacin de ejemplo (Sample App) se puede encontrar la definicin de un DataSource para el servidor
MySQL.[17]
<data-source
class="com.evermind.sql.DriverManagerDataSource"
name="MySQLDS"
location="jdbc/CarritoDS"
xa-location="jdbc/xa/CarritoXADS"
ejb-location="jdbc/MySQLDS"
connection-driver="org.gjt.mm.mysql.Driver"
username="admin"
password=""
url="jdbc:mysql://localhost/carrito"
inactivity-timeout="30"/>
</data-sources>
Para opciones avanzadas de configuracin (nmero mnimo y mximo de conexiones del Pool, nmero
mximo de intentos de conexin, etc.) consultar el DTD de dicho fichero, disponible en la direccin
http://xmlns.oracle.com/ias/dtds/data-sources.dtd.

50

Captulo 5. Construccion de informes


con openFWPA
Generacin de Informes
La generacin de informes se basa en el proyecto JasperReports [20]. JasperReports es una librera
de clases que puede verse como un motor de reporting para desarrollos java. El principal objetivo de
este proyecto es facilitar la construccin de documentos con contenido dinmico y su visualizacin en
diferentes formatos.
JasperReports organiza la informacin que le servir para generar los documentos en forma de fichero
XML. El fichero XML, de acuerdo al DTD http://jasperreports.sourceforge.net/
dtds/jasperreport.dtd, es visto como el diseo del informe. Una vez en disposicin de un diseo
XML vlido, es necesario realizar un proceso de compilacin, que generar un objeto que es serializado,
y podra ser almacenado en disco con extensin .jasper. La compilacin validar todas las expresiones
java que pudieran estar embebidas en el XML. Una vez compilado, y para proveer al informe con datos
dinmicos, 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 librera de JasperReports) o fuentes de datos
personalizadas, extendiendo el interface JRDataSource. Otra forma de pasar informacin dinmica a
los documentos es a travs de parmetros de informe, que forman parte del diseo XML y pueden ser
establecidos por programacin, e incluso tener valores por defecto en diseo.
Este proceso puede verse en la siguiente figura (obtenida del libro [The JasperReports Ultimate Guide])

Figura 5.1. Proceso de generacin de informes

Creacin de los diseos XML.


El proyecto JasperReports no provee de ninguna herramienta adicional que facilite la labor de la creacin
de los ficheros XML. En este punto, un desarrollador que pretenda crear el diseo XML de un documento
necesario para su aplicacin, debera crearse el fichero XML desde un editor de texto, o editor XML.
Evidentemente, esto es una tarea tediosa y poco operativa. Ms bien se necesitara otra herramienta que
facilitara la labor de visualizar, compilar y generar el XML del documento que se est diseando. Una
herramienta visual del tipo WYSIWYG.
Existen varias herramientas de este tipo desarrolladas como proyectos abiertos. Algunas de ellas pueden
verse en http://jasperreports.sourceforge.net/gui.tools.html. El desarrollador es
libre de elegir su herramienta preferida; el openFWPA no provee de ninguna de ellas, aunque se han
realizado pruebas con el proyecto iReport-Designer for JasperReports [21]

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 (aplicacin de ventana de java) y tiene un interfaz
claro. En la pgina del proyecto http://ireport.sourceforge.net puede obtenerse una amplia
documentacin sobre como manejar esta herramienta, e incluso un video tutorial que muestra algunos de
los aspectos ms interesantes sobre ella.

51

Construccion de
informes con openFWPA
Al estar estrechamente relacionada con JasperReports, es necesario conocer los aspectos en que
este ltimo organiza su informacin (bandas, grupos, subreports, parameters, fields, variables)
para optimizar el manejo de la herramienta visual. Una vez descargado el proyecto y ejecutado, se
abrir una ventana como la de la siguiente figura, donde se ha abierto un fichero XML llamado
solicitudQuemaEnBlanco.xml.

No es objeto de este manual mostrar el manejo detallado de iReports. No obstante, se introducen algunos
conceptos sobre la herramienta. Una vez se tiene un diseo cargado, o bien se ha optado por un diseo
nuevo a partir de cero al cual se le van aadiendo elementos, se puede compilar el diseo, tal y como la
hara JasperReports a travs de su motor. Con esto se asegura que el diseo que se est generando es vlido
y no producir errores de compilacin en el momento de que la aplicacin a desarrollar tome el fichero
XML para compilarlo y mostrarlo en pantalla. Para esto se dispone del icono Compliar (1) a la derecha
en la barra del men. Tambin es posible observar como se vera el documento que se est diseando
con alguno de los visores predeterminados, previa configuracin de los programas externos que maneja la
herramienta, de dos modos distintos: con una fuente de datos vaca o con la fuente de datos actual (previa
configuracin de las fuentes de datos).

Establecer los programas externos.


Men # Tools # Options # Pestaa External Programs Desde esta ventana se pueden establecer los
ejecutables para los programas externos que puede usar la herramienta para visualizar los informes.

Crear fuentes de datos.


Men # Datasource # Connections / Datasources Desde esta ventana se pueden gestionar las fuentes de
datos (crear, borrar y modificar)

Admite cuatro tipos diferentes de fuentes de datos:


DataBase JDBC Connection
XML file DataSource
JavaBeans set DataSource (Collection o Array de Beans)
Custom JRDataSource
Las ms interesentas son las conexiones JDBC y las colecciones de Beans. El framework de programacin
de JasperReports provee de una serie de implementaciones de referencia para conjuntos de Beans.
Son clases que extienden el interface base JRDataSource. Tambin existe la prosibilidad de que el
desarrollador extienda su propia implementacin del interface, con lo que conseguira una fuente de datos
CustomJRDataSource, la cual podra probar utilizando la herramienta iReports (creando una fuente
de datos de este tipo y configurando la clase asociada)

Establecer la fuente de datos actual


Men # Build # Set active connection Desde esta opcin se establecer la fuente de datos que la herramienta
utilizar cuando se visualice el diseo usando una fuente de datos (icono en la barra de navegacin u
opcin de men Men # Build # Execute report (using active conn.)

52

Construccion de
informes con openFWPA

Establecer la vista del informe


Men # Build Desde este grupo de opciones se tiene la posibilidad de establecer como obtener la salida
visual del documento que se est diseando, seleccionando alguno de los 7 radio-buttons disponibles.
Se deberan tener correctamente establecidos los programas externos para poder utilizar correctamente
las vistas. La opcin JRViewer preview funciona en cualquier caso, al ser el visor por defecto de
JasperReports, que ya incluye la herramienta iReports.

Report Wizard
Men # Report Wizard Esta opcin permite la creacin de nuevos diseos a partir del wizard de iReports.
El proceso consta de una serie de pasos que se detallan a continuacin:
1. Introducir la consulta que obtendr los datos de la fuente de datos.

2. : Seleccionar los campos que se desean visualizar en el documento a generar.

3. : Agrupar por algn campo si se desea. No es obligatorio agrupar.

4. Elegir una plantilla para el layout. iReports viene con una serie de plantillas que se pueden utilizar, o
bien el desarrollador podra construir sus propias plantillas.

Con esto finaliza el proceso, y se genera un informe en vista diseo como el siguiente:

Que puede ser compilado y visto en PDF, pulsando el icono correspondiente:

En este ejemplo se ha utilizado una fuente de datos JDBC Connection. No se han realizado pruebas
para obtener datos de collecciones de Beans (fuente de datos JRDataSource) aunque el proceso no
debera diferir sustancialmente de lo aqu expuesto.

Report Parameters
Men # View # Report Parameters Los parmetros son una buena forma de aadir datos dinmicos al
informe y parametrizar ste, de forma que se puedan visualizar elementos segn el valor o rango de algn
parmetro, e incluso modificar la consulta SQL segn parmetros. Los parmetros aaden ms flexibilidad
a la generacin de los informes, hasta el punto de que es posible crear informes sin fuente de datos, y que
toda su informacin llegue por parmetros.
Un parmetro tiene un nombre, un tipo (clase java seleccionable de una lista) y opcionalmente un valor
por defecto (expresin java que ser compilada en el proceso de compilacin y evaluada en el proceso
de completado del informe) Los parmetros son referencias a objetos que son pasadas al proceso de
completado (fill) del informe. Su uso, como ya se ha comentado, servir para enviar informacin al
motor de reporting que no puede ser encontrada en la fuente de datos (DataSource)
Los parmetros se identifican en el fichero XML por construcciones similares a la siguiente:
<parameter name="ejemplar_para" isForPrompting="false" class="java.lang.String">

53

Construccion de
informes con openFWPA
<defaultValueExpression >
<![CDATA[new String("Ejemplar para ... por defecto")]]>
</defaultValueExpression>
</parameter>
En el entorno de iReports, se puede hacer referencia a este parmetro mediante la construccin
$P{ejemplar_para}

Consultas parametrizadas
Men # View # Report quey Es posible parametrizar la consulta que lanzar el informe segn el valor de
uno o varios parmetros en tiempo de ejecu-cin. Para hacer referencia a un parmetro definido se utiliza
la construccin $P{nombre_de_parametro} y estas construcciones se pueden insertar en las propia
consulta, de forma que sean evaluadas durante el proceso de completado. Un ejemplo puede verse en la
siguiente imagen, donde se observa la intrusin de los parmetros fecha_inicio y fecha_fin
como parte de la sentencia SQL. El objetivo de esta consulta es filtrar la bsqueda entre dos fechas, que
posi-blemente el usuario introduzca en algn formulario de la vista de su aplicacin. Una forma de hacer
llegar dinmicamente estos valores a la consulta es utilizando parmetros de informe, cuyos valores sern
asignados por programacin en tiempo de ejecucin y pasados como informacin adicional al proceso de
completado del informe.

Fields
Los fields representan la forma de mapear campos en el diseo 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 colleccin de Beans, el mapeo se realizar con las property
s de stos.
Un Field se puede idetificar en el XML por una construccin como: <field name="DL_FINALIDAD"
class="java.lang.String"/> En el entorno de iReports se le puede hace referencia como
$F{DL_FINALIDAD}

Variables
Se declaran como expresiones en java, y ms tarde pueden ser usadas de forma masiva. Pueden servir
como forma de no repetir cdigo. Tamben se utilizan para realizar clculos. Exiten funciones builtin que facilitian algunas tareas de clculo, como Count, Sum, Average, Lowest, Highest y
StandardDeviation. Las variables sern reinicializadas segn la jerarqua 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.
PAGE_NUMBER
REPORT_COUNT
COLUMN_COUNT
En el entorno de iReports se les puede hace referencia como $V{NOMBRE_DE_VARIABLE}

54

Construccion de
informes con openFWPA

El diseo XML
Ya sea con la herramienta iReports o con cualquier otra disponible, el objetivo ser obtener un fichero
XML que se considerar el diseo del documento. Este fichero ser pasado al proceso de compilacin,
completado y visualizacin de las aplicaciones construidas bajo el framework, en la forma que se ver
ms adelante.
El cdigo XML generado es extenso y pesado de tratar con herramientas de edicin de texto o editores
XML. Es por esto la necesidad del uso de herramientas como iReports para disear los informes de las
aplicaciones. A continuacin se pueden ver trozos de XML que generan las herramientas:

<?xml version="1.0" encoding="UTF-8" ?>


<!-- Created with iReport - A designer for JasperReports -->
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasp
<jasperReport
name="listadoTipoQuema"
columnCount="1"
printOrder="Vertical"
orientation="Portrait"
pageWidth="595"
pageHeight="842"
columnWidth="535"
columnSpacing="0"
leftMargin="30"
rightMargin="30"
topMargin="20"
bottomMargin="20"
whenNoDataType="AllSectionsNoDetail"
isTitleNewPage="false"
isSummaryNewPage="false">
<property name="ireport.scriptlethandling" value="2" />
<parameter name="P_Titulo" isForPrompting="false" class="java.lang.String">
<defaultValueExpression ><![CDATA["ESPACIO PARA EL TITULO DEL INFORME"]]></defaul
</parameter>
<parameter name="P_AmpliacionTitulo" isForPrompting="false" class="java.lang.Strin
<defaultValueExpression ><![CDATA["Descripcin extendida del propsito del info
</parameter>
<parameter name="fecha_inicio" isForPrompting="false" class="java.lang.String">
<defaultValueExpression ><![CDATA["01/01/1900"]]></defaultValueExpression>
</parameter>
<parameter name="fecha_fin" isForPrompting="false" class="java.lang.String">
<defaultValueExpression ><![CDATA["31/12/2999"]]></defaultValueExpression>
</parameter>
<queryString><![CDATA[select f.dl_finalidad, c.dl_concejo, r.cn_tiporesol, s.ca_pe
from quesolicitud s,
queresolucion r,
quefinalidad f,
queconcejo c
where s.ca_permiso = r.ca_permiso and
s.cn_finalidad = f.cn_finalidad and
s.cn_concefin = c.cn_concejo and
(s.fe_registro between to_date($P{fecha_inicio},'dd/mm/rrrr')
and to_date($P{fecha_fin},'dd/mm/rrrr'))
ORDER BY f.dl_finalidad asc, c.dl_concejo asc, r.cn_tiporesol asc]]></queryString>

55

Construccion de
informes con openFWPA

<field name="DL_FINALIDAD" class="java.lang.String"/>


<group name="DL_CONCEJO" isStartNewColumn="false" isStartNewPage="false"
<groupExpression><![CDATA[$F{DL_CONCEJO}]]></groupExpression>
<groupHeader>
<band height="23" isSplitAllowed="true" >
<rectangle radius="3" >
<reportElement
mode="Opaque"
x="13"
y="3"
width="515"
height="17"
forecolor="#8080FF"
backcolor="#B6CBEB"
key="element-25"
stretchType="NoStretch"
positionType="FixRelativeToTop"
isPrintRepeatedValues="true"
isRemoveLineWhenBlank="false"
isPrintInFirstWholeBand="false"
isPrintWhenDetailOverflows="false"/>
<graphicElement stretchType="NoStretch" pen="Thin" fill="Solid" />
</rectangle>
<staticText>
<reportElement
mode="Transparent"
x="20"
y="4"
width="65"
height="14"
forecolor="#6666FF"
backcolor="#FFFFFF"
key="element-26"
stretchType="NoStretch"
positionType="FixRelativeToTop"
isPrintRepeatedValues="true"
isRemoveLineWhenBlank="false"
isPrintInFirstWholeBand="false"
isPrintWhenDetailOverflows="false"/>
<textElement textAlignment="Left" verticalAlignment="Middle" lineSpacing="Sing
<font fontName="Verdana" pdfFontName="Helvetica-Bold" size="10" isBold="true"
</textElement>
<text><![CDATA[Concejo de]]></text>
</staticText>

Bugs en el XML generado por iReport


Se han detectado una serie de problemas que hacen que el XML generado por iReports no responda
directamente a lo que JasperReports espera encontrar, producindose fallos de compilacin del XML una
vez se intenta visualizar el informe en las aplicaciones construidas bajo el framework. Si el desarrollador
se encuentra con este problema, intente lo siguiente:
1. Editar el XML en un editor de texto

56

Construccion de
informes con openFWPA
2. Utilizar como encoding UTF-8 en lugar de ISO-8859-1. El XML debera comenzar con la siguiente
lnea: <?xml version="1.0" encoding="UTF-8"?>
3. Eliminar todas las referencias al atributo pdfEncoding. Los elementos de texto son
generados por defecto con el atributo pdfEncoding=CP1252. Borrar todos los literales
pdfEncoding=XXXXXX del fichero XML.
4. Si se utilizan imgenes en los informes, modificar todas las rutas. La herramienta introduce rutas
absolutas para mapear las imgenes. Deber cambiar estas rutas a relativas de acuerdo a la estructura
de las aplicaciones que se estn desarrollando.
5. El creador de iReports ha introducido una opcin para que las expresiones puedan ser multilnea
(una facilidad para el diseador del informe) Esta posibilidad se controla en Men # Tools # Options
(Pestaa General) # CheckBox Using multi line expresions. Si est habilitada, en el XML aparecer el
atributo isCode en ciertos elementos. Este atributo no forma parte del DTD, por lo que no ser posible
parsear el XML convenientemente y mucho menos compilar el diseo por JasperReports. Eliminar el
atributo isCode del XML.Es posible que en futuras versiones de JasperReports el atributo isCode
forme parte del DTD, si fructifican las conversaciones a este respecto entre el creador de JasperReprots
y el de iReports.
6. Si no se va a utilizar una clase Scriptlet en el informe, no ser necesario que
esto conste en el diseo. Es posible que al generar un nuevo diseo con la herramienta
iReport se aada por defecto la clase dori.jasper.engine.JRDefaultScriptlet.
En la versin de jasperreports actualmente utilizada (0.6.0) esta clase no existe, con lo
que si se intenta compilar el informe ocurrir una excepcin ClassNotFoundException.
Para eliminar esta referencia se puede editar el XML y eliminar la siguiente lnea
scriptletClass="dori.jasper.engine.JRDefaultScriptlet del elemento raz
<jasperReport>. Tambin se puede hacer directamente con la herramienta iReport mediante
Project # ProjectOptions # Pestaa Scriptlety configurando aqu la clase que se desea utilizar, o
indicando que no se va a usar una clase Scriptlet.
En la versin 0.4 de la herramienta iReports, estos bugs estn resueltos, por lo tanto, no es necesario
realizar ninguna modificacin al fichero XML generado.

Compilacin de Reports
Para poder utilizar los reports generados con la herramienta iReports, en las aplicaciones que utilizan el
framework, es necesario que los ficheros XML obtenidos sean compilados al formato .jasper. Para ello,
se puede utilizar la clase JasperCompilerManager o, mejor an, el propio programa editor iReports.

Clases en el openFWPA para la renderizacin de


informes.
En el openFWPA se han incluido dos clases para la generacin de informes: PrincastReport y
PrincastMultiReport. La primera permite generar informes simples y la segunda de ellas, crear
multi-reports a partir de la agregacin de varios informes sencillos.

Informes simples
Para crear un informe simple se usar la clase PrincastReport. Para poder crear un
PrincastReport, es necesario indicarle, en su constructor, los parmetros:
Nombre del informe

El informe debe tener un nombre. Este nombre puede ser el que se utilice
para generar un fichero PDF.

57

Construccion de
informes con openFWPA
Fuente de datos

El origen de datos para cargar el informe tambin 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 definicin compilada del informe. Este stream debe estar abierto sobre un
fichero .jasper.

Adems, si en el diseo del informe se han definido parmetros, sus valores deben ser especificados al
PrincastReport utilizando el mtodo setParams(Map).

Atencin
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 mtodo
process().
Para obtener un informe de un PrincastReport (correctamente creado y con los parmetros que
necesite asignados) se puede utilizar uno de los siguientes mtodos:
a. getReportToPrint(). Devuelve el objeto jasper imprimible: JasperPrint. Este objeto puede
ser manejado por las clases de Jasper Reports (se puede exportar a mltiples formatos, imprimir, etc.)
b. 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.)
c. exportPDF(OutputStream). Exporta el informe, en formato PDF, al OutputStream que se
pasa como parmetro.
A continuacin se muestra un ejemplo de construccin 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.MESSAGE
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();

Multi Reports
Los Multi-reports son informes compuestos de informes simples. El objetivo de los multi-reports es
agrupar un conjunto de informes para que puedan ser volcados en un mismo fichero PDF.
El openFWPA incluye la clase PrincastMultiReport para la generacin de informes compuestos.
Esta clase es muy simple de manejar: basta con especificarle un nombre (para el fichero PDF) y aadir
todos los informes simples que se quieran adjuntar.

58

Construccion de
informes con openFWPA
Los multi-reports tambin deben ser procesados, al igual que los informes simples, utilizando el mtodo
process().
El informe se puede obtener con el mtodo 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. Tambin se puede exportar con el mtodo exportPDF(OutputStream).
Si, durante la composicin de un multi-report, se produce un error en la generacin de alguno de los
informes que componen, existen dos posibles polticas para su tratamiento:
a. Ignorar el error. Se trata del comportamiento por defecto. El multi-report se compondr normalmente,
se ignora el informe defectuoso.
b. Propagar el error. En este caso, se interrumpe la generacin del multi-report y se eleva una excepcin
PrincastReportException. Para activar esta poltica, el multi-report se debe crear utilizando el
constructor: PrincastMultiReport(String name, bolean failOnError), asignando
el valor true al parmetro failOnError.

Las fuentes de datos de los informes.


Los informes visualizarn contenido dinmico, provenientes de dos tipos diferentes de fuentes de datos.
1. DataSources JDBC Connection: conexin con una base de datos relacional.
2. JRDataSources: fuentes de datos JasperReports. La librera de clases de Jasper Reports provee
de una serie de implementaciones de este tipo de fuentes de datos. Las ms 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 encapsulacin de las capas de la aplicacin.

Utilizando JasperReports en Linux / Unix sin X11.


ADVERTENCIA: No es posible generar informes con imgenes (escudos, marcas de agua, cdigos de
barras, etc.) en un entorno Unix/Linux sin las libreras X11.

Clase para la generacin de tablas en PDF.


El openFWPA incluye la clase PDFTableExporter para la generacin 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
en combinacin con una PrincastPDFReportAction, sobrescribiendo el mtodo getReport().
Un ejemplo de su uso es el siguiente:
// nmero de columnas de la tabla, las filas se ajusta automticamente
int columnas = 3;
// nombre del report
String REPORT_NAME = "tabla";
PDFTableExporter tableExporter = new PDFTableExporter(REPORT_NAME, columnas);
// se establece el ttulo del report
tableExporter.setTitle("Mi ttulo");
// se aaden celdas de cabecera (aparecen sombreadas)
tableExporter.addCellHeader("Enero");
tableExporter.addCellHeader("Febrero");
tableExporter.addCellHeader("Marzo");
// se aaden las celdas de la tabla
tableExporter.addCell("1");

59

Construccion de
informes con openFWPA
tableExporter.addCell("2");
tableExporter.addCell("3");
// se retorna el objeto
return tableExporter;

60

Captulo 6. Operaciones
Sistema de Inicializacin y Arranque
El ncleo del openFWPA se construye sobre un sistema de inicializacin que permite definir, de forma
declarativa, los componentes que deben ser creados, configurados e iniciados durante el perodo de
arranque de las aplicaciones. Generalmente estos componentes son objetos de utilidad que tienen alcance
global a toda la aplicacin, como el sistema de logging, de configuracin, monitorizacin, contadores,
consola de administracin, etc.
A partir de la versin 1.3 del openFWPA el Sistema de Inicializacin se basa en el framework IoC Spring
(www.springframework.org).

Declaracin de objetos inicializables


El fichero de arranque de las aplicaciones que utilizan el openFWPA es: princast-initscript.xml. En este fichero se deben definir los objetos que sern accesibles durante el periodo de
inicializacin.
La estructura del fichero princast-init-script.xml se ajusta a la DTD de los ficheros de inicializacin 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 mtodo que empiece por la cadena set y tenga un solo
parmetro. Ver documentacin oficial de Java Beans de Sun en: java.sun.com).
Este sistema para dar valor a propiedades de mtodos 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 id=>).

<bean id="securityRulesPlugin" class="es.princast.framework.web.filter.security.cor


<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.configurat


<property name="plugin"><ref bean="baseConfigurationPlugin"/></property>
</bean>
Existen muchas otras etiquetas que permiten: especificar valores para los parmetros del constructor,
asignar colecciones a propiedades de los objetos, definir variables al estilo ANT (${name}), etc.
Para mas informacin al respecto consulte la pgina web del framework Spring o consulte la gua de
referencia incluida en la documentacin del openFWPA.

61

Operaciones

Variables ${} en el fichero de inicializacin


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 princastinit.script.xml, el siguiente bean:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.Prope


<property name="location"><value>ruta del fichero</value></property>
</bean>

Donde ruta del fichero es el path del fichero de properties del que se cargarn l
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>
Es posible utilizar rutas de fichero absolutas. Para ello, es necesario utilizar la construccin de Spring
FileSystemResources, tal y como se indica en el siguiente ejemplo:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.Prope


<property name="location">
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg><value>c:/deploy.properties</value></constructor-arg>
</bean>
</property>
</bean>

Desarrollo de objetos inicializables


Es posible implementar objetos para que sean arrancados de forma automtica, durante la inicializacin,
por el openFWPA. Todos los objetos que estn definidos en el fichero princast-init-script.xml
pueden ser inicializados y arrancados automticamente. No es necesario que los objetos implementen
ningn interfaz especfico pero se tendr en cuenta:
a. Si los objetos implementan el interfaz Configurable, adems de ser creados sern configurados de
forma automtica por el framework.
b. Si los objetos implementan el interfaz Launchable, sern creados de forma automtica (ejecutndose
cualquier tarea que tengan implementada bajo el mtodo create()).
c. Si los objetos implementan el interfaz RegistrableMBean, stos sern registrados bajo el sistema
de gestin JMX.
El sistema de inicializacin siempre arranca los siguientes objetos:
Manager de logging.
Factora del sistema de control y gestin JMX. ManagementFactory.
Sistema de condiguracin. FrameworkConfigurator

62

Operaciones

Arranque de aplicaciones web


A partir de la versin 1.3 del openFWPA, el componente inicialziador de las aplicaciones
es: PrincastStartupListener. El servlet de inicialziacin: PrincastStartupServlet,
utilizado en versiones anteriores, debido a problemas de estabilidad en los ClassLoaders del servidor de
aplicaciones, ha quedado deprecado.
El startup-listener implementa el interfaz ServletContextListener y, por tanto, debe ser declarado
en el fichero web.xml. Adems, tambin se debe declarar un parmetro de contexto (<contextparam>) que indique la ruta del fichero de arranque princast-init-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</li
</listener>

Arranque manual
El arranque automtico de los servicios del openFWPA (configuracion, management, etc.) unicamente
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 del openFWPA es necesario lanzar la inicialziacin de forma manual.
Para realizar esta tarea, se incluye la clase PrincastStandaloneInitializer. Esta clase se debe
iniciar (utilizando el mtodo esttico init()) al arrancarse la aplicacin. Durante la ejecucin pone
a disposicin de la aplciacin todos los beans declarados en el fichero de inicializacin (princastinit.script.xml), a travs del PrincastApplicationContext, que se obtiene con el mtodo
getInitScriptContext().

InputStream stream = this.getClass().getClassLoader().getResourceAsStream(INIT_SCRI


//Default configuration properties
Properties props = new Properties();
props.put("myProp", "myValue");
PrincastStandaloneInitializer.init(stream, props);
Para finalizar la aplicacin se debe llamar al mtodo esttico finish().
El mtodo init() tambin permite tamabin cargar todos los ficheros XML de definicin de beans
(de Spring) que sean necesarios para la aplicacin. Para especificar los ficheros a cargar se indicarn los
patrones correspondientes (siguiendo el convenio de nombrado habitual en Spring), teniendo en cuenta
que se tomarn relativos al classpath.

Sistema de Configuracin de Aplicaciones


Otro de los sistemas del ncleo del openFWPA es el Sistema de Configuracin. El sistema de configuracin
permite, tanto a los componentes de las aplicaciones como del propio framework, recibir parmetros de

63

Operaciones

configuracin de forma completamente transparente, sin necesidad de preocuparse por la forma o el lugar
en que stos estn almacenados.

Figura 6.1. Estructura del sistema de configuracin

El Sistema de Configuracin acta como un almacn centralizado de parmetros de configuracin. En la


configuracin de aplicaciones intervienen los siguientes componentes:
Plugins de configuracin (ConfigurationPlugin). Se trata de objetos que pueden acceder a un
almacn de parmetros de configuracin, ya sea para nicamente recuperar sus valores, o tambin para
actualizarlos.
Contextos de configuracin. Los contextos son conjuntos de parmetros agrupados por su funcionalidad.
Los parmetros agrupados en un mismo contexto sirven, habitualmente, a objetos relacionados entre s.
Configurador de aplicaciones (FrameworkConfigurator). Es el componente central del sistema
de configuracin. Se encarga de cargar los parmetros 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 configuracin de la aplicacin cambia.
Los listeners son, generalmente, objetos de aplicacin que necesitan acceder a los parmetros que
proporciona el Sistema de Configuracin del openFWPA.

Implementacin de objetos configurables


Para que un objeto pueda acceder a los parmetros del sistema centralizado de configuracin del
openFWPA debe:
1. Implementar el interface Configurable.

Atencin
El interface ConfigurationListener ha sido marcado como "deprecated". En su lugar,
se debe utilizar el interface Configurable.
2. Registrarse en el configurador: FrameworkConfigurator.

Implementando el interface Configurable


El interface Configurable define una serie de mtodos para la gestin del ciclo de vida del objeto
configurable. Los tres mtodos definidos son, en realidad, mtodos callback. nicamente van a ser
utilizados por el sistema de configuracin y no se deben invocar directamente desde objetos de la
aplicacin.
Estos mtodos son:
configure()

Se invoca cuando el objeto se configura por primera vez. Cuando se llama a


este mtodo, se presupone que el objeto no ha sido configurado con anterioridad.
Este mtodo recibe como argumento un conjunto de parmetros de configuracin
(ConfigurationParameters).

reconfigure()

Se invoca cuando el valor de algn parmetro que pueda ser relevante para la
configuracin del objeto, es actualizado. Este mtodo recibe como parmetro un
evento de configuracin (ConfigurationEvent).

64

Operaciones

En la implementacin de estos mtodos, el objeto configurable debe obtener, bien del conjunto de
parmetros (ConfigurationParameters), bien del evento (ConfigurationEvent) los datos
que necesite para su configuracin.
Conjunto de Parmetros de Configuracin (ConfigurationParameters)
Se trata de un almacn que contiene todos los parmetros de configuracin de la aplicacin, agrupados
en contextos. Es responsabilidad del objeto configurable seleccionar aquellos parmetros que le puedan
ser de utilidad.
Se pueden obtener todos los parmetros de un conjunto utilizando el mtodo getKeys(). Este mtodo
devuelve una enumeracin (Enumeration) con los nombres (String) de todos los parmetros
existentes en el sistema. Otra opcin es buscar nicamente los parmetros clasificados bajo un contexto
determinado. En este caso, se utilizar el mtodo getKeys(String), pasndo como argumento el
nombre del contexto cuyos parmetros se quieren enumerar.
Para obtener un parmetro del conjunto ConfigurationParameters, se utilizar el mtodo
getParameter(String), si se sabe con certeza que el valor del parmetro es una cadena de
caracteres, o el mtodo getConfigurationObject(String) si se quiere recuperar un Object
genrico. Ambos mtodos reciben como argumento el nombre del parmetro a localizar.
Utilizando estos mtodos, si dos parmetros coinciden en nombre, se devolver el primero que
se encuentre. Para evitar colisiones de nombrado, se pueden utilizar los mtodos 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 parmetro.
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;
}
}

Eventos de Configuracin (ConfigurationEvent)


Los eventos de configuracin se disparan cuando se produce una actualizacin en los valores de los
parmetros de configuracin. Cuando un evento de configuracin se dispara se invocan los mtodos
reconfigure() de los objetos configurables.
Es responsabilidad del desarrollador de los objetos configurables implementar la respuesta que tendrn
sus objetos ante determinados eventos.
En realidad, el mtodo reconfigure(), son dos mtodos:
reconfigure(ConfigurationEvent). Recibe un evento de configuracin de carcter general.
No existe una causa concreta que peda disparar este evento: reinicio del sistema, recarga de
un fichero de configuracin, etc. El objeto event proporciona: nombre del contexto afectado

65

Operaciones

por el evento (getContextName()) y conjunto de parmetros de configuracin actualizados


(getParameters()).
reconfigure(ConfigurationParameterUpdatedEvent). Recibe un evento de
reconfiguracin ms especfico que indica la actualizacin de un nico parmetro de configuracin. El
objeto event, adems de la informacin suministrada por la superclase (ConfigurationEvent),
proporciona,: nombre del parmetro 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());
}
}

Registro de un objeto en el FrameworkConfigurator.


Por ltimo, para que un objeto (que implemente Configurable) pueda ser gestionado por el sistema de
configuracin, ste debe ser registrado en el configurador del openFWPA. Para registrar un objeto, basta
con llamar al mtodo configureMe() del FrameworkConfigurator.
public MyClass() {
FrameworkConfigurator.getConfigurator().configureMe(this, true);
}
Este mtodo recibe dos parmetros: el objeto configurable y un valor booleano que indica si el objeto
quiere escuchar, o no, eventos de reconfiguracin.

Plugins de Configuracin
Los plugins de configuracin son los componentes que proporcionan los parmetros que maneja el Sistema
de Configuracin. Un plugin de configuracin se encarga de gestionar un nico almacn de datos (un
fichero, una base de datos, etc.), sin embargo, un plugin puede servir parmetros a varios contextos de
configuracin. Los plugins de configuracin, implementan el interface ConfigurationPlugin.

Aadir un plugin de configuracin


Si una aplicacin tiene alguna necesidad de configuracin, la mejor opcin suele ser definir plugins de
configuracin especficos. Para ello, es necesario seguir los siguientes pasos:
1. Seleccionar, de los tipos de plugins que contiene el openFWPA, el ms adecuado.

66

Operaciones

2. Si no se encuentra ninguno que se ajuste a las necesidades, implementar uno propio.


3. Escribir los parmetros de configuracin en el almacn seleccionado.
4. Declarar el plugin en el fichero de arranque de la aplicacin (princast-init-script.xml).
5. Opcionalmente, definir un bean manager para la gestin del plugin a travs de la consola JMX.
6. En el propio fichero princast-init-script.xml, registrar el plugin en la declaracin del bean
FrameworkConfigurator.

Declaracin de plugins en el fichero de inicailizacin.


Antes de poder utilizar un plugin de configuracin es necesario definirlo en el fichero de arranque de la
aplicacin (princast-init-script.xml).
Los plugins de configuracin son objetos inicializables del openFWPA (Ver Declaracin de objetos
inicializables) y se deben definir como beans en el fichero de arranque.

<bean id="baseConfigurationPlugin" class="es.princast.framework.core.configuration.


<constructor-arg><value>basePlugin</value></constructor-arg>
<property name="priority"><value>12</value></property>
<property name="file"><value>${base.module.file}</value></property>
<property name="contexts">
<list>
<value>SECURITY</value>
<value>ROOT.CONTEXT</value>
<value>ACTION.CONTEXT</value>
<value>JMX.CONTEXT</value>
</list>
</property>
</bean>
Los parmetros 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 identificativo del
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 parametros de igual nombre (es decir, en case de que
haya conflicto de nombres de los parmetros), se tomarn primero los parmetros ofertados por el plugin de prioridad mas alta (numero ms bajo). Si no se establece ningn valor, por defecto, la prioridad
de todos los plug-ins es 10 (un valor intermedio).
La prioridad permite definir jerarquas de plug-ins de configuracin. De esta forma, se permite
definir plug-ins a nivel de contenedor (con parmetros comunes a todas las aplicaciones) que pueden
sobreescritos para definir parmetros especficos para cada aplicacin.
<property name="file">. Algunas propiedades se deben definir, o no, en funcin del tipo de
plugin. En este caso, el plugin PropertiesFileConfigurationPlugin, exige la definicin 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 parmetros. En este caso, el plugin sirve parmetros al

67

Operaciones

contexto raz (ROOT.CONTEXT), al contexto de seguridad (SECURITY) , al contexto del sistema de


gestin JMX (JMX.CONTEXT) y al contexto de las Actions de la aplicacin (ACTION.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 aplicacin (Ver Consola de gestin).
Si se define un adaptador, ser posible, a travs de la consola, actualizar o referescar, en caliente, los valores
de los pa-rmetros de configuracin del plugin (siempre y cuando el plugin soporte estas operaciones).

<bean id="jmxBasePluginCap" class="es.princast.framework.core.management.configurat


<property name="plugin"><ref bean="baseConfigurationPlugin"/></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.
Para finalizar, es necesario registrar el plugin en la definicin del FrameworkConfigurator (que no
es ms que otro bean en el fichero princast-init-script.xml). Se debe aadir la referencia al
plugin en la propiedad: plugins.

<bean id="configurationManager" class="es.princast.framework.core.configuration.Fra


factory-method="getConfigurator" lazy-init="false" singleton="true">
<property name="plugins">
<list>
<ref bean="baseConfigurationPlugin"/>
<ref bean="jaasConfigPlugin"/>
<ref bean="securityRulesPlugin"/>
</list>
</property>
</bean>

Plugins en openFWPA.
En el openFWPA se incluyen algunos plugins de configuracin listos para ser utilizados. Adems, se
proporcionan clases para facilitar el desarrollo de plugins por parte de los usuarios.

Figura 6.2. Jerarqua de Plugins

Plugins basados en Properties


Los plugins basados en Properties almacenan parmetros como pares {atributo, valor}. En el
openFWPA se empaquetan dos clases para gestionar este tipo de parmetros:
PropertiesConfigurationPlugin, para cargar los datos de configuracin de un objeto
java.util.Properties en memoria.

<bean id="myPropsConfigurationPlugin" class="es.princast.framework.core.configura


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

68

Operaciones

</entry>
<entry key="PARAMETRO.DOS">
<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 parmetros de un fichero de
properties.

<bean id="baseConfigurationPlugin" class="es.princast.framework.core.configuratio


<constructor-arg><value>basePlugin</value></constructor-arg>
<property name="priority"><value>12</value></property>
<property name="file"><value>${base.module.file}</value></property>
<property name="contexts">
<list>
<value>SECURITY</value>
<value>ROOT.CONTEXT</value>
<value>ACTION.CONTEXT</value>
<value>JMX.CONTEXT</value>
</list>
</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 aplicacin web, o al classpath (siempre que empiece por la cadena
classpath://).
Plugins basados en XML
Este tipo de plugins obtienen la configuracin de un documento XML. Este documento puede estar en
memoria (en un String, por ejemplo), o en un fichero.
XMLStringConfigurationProperties. Carga la configuracin directamente de un String.

<bean id="xmlStringConfigurationPlugin" class="myapp.MyXMLStringConfigurationPlug


<constructor-arg><value>xmlStringPlugin</value></constructor-arg>
<property name="priority"><value>12</value></property>
<property name="xml">
<value> <![CDATA[
<elements>
<element value='myId' label='bar'/>
<element value='myId2' label='bar2'/>
</elements>
]]>
</value>
69

Operaciones

</property>
<property name="contexts">
<list>
<value>EXAMPLE.CONTEXT</value>
</list>
</property>
</bean>
Para configurar este plugin, debe escribirse el documento XML (que contiene la configuracin) en la
propiedad xml. Es importante observar que debe escribirse en una seccin CDATA, de lo contrario,
el fichero de inicio no sera valido de acuerdo a su DTD. Este plugin es de solo-lectura.
XMLFileConfigurationPlugin. Carga la configuracin de un fichero xml.

<bean id="xmlFileConfigurationPlugin" class="myapp.MyXMLFileConfigurationPlugin">


<constructor-arg><value>xmlFilePlugin</value></constructor-arg>
<property name="priority"><value>12</value></property>
<property name="file">
<value>classpath://myfile.xml</value>
</property>
<property name="contexts">
<list>
<value>EXAMPLE.CONTEXT</value>
</list>
</property>
</bean>
Para configurar este plugin, se debe indicar el fichero xml de configuracin en la propiedad file. El
path de este fichero puede ser absoluto, relativo respecto al contexto de la aplicacin 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 anlisis del documento, y la
gestin de los parmetros de configuracin, en un objeto auxiliar: XMLConfigContentHandler.
Para definir un plugin de configuracin XML, es necesario
XMLConfigContentHandler. Se deben implementar mtodos para:

extender

la

clase

Analizar el documento XML. El anlisis del documento se realiza utilizando el API Apache Commons
Digester. Los mtodos a implementar son: setDigesterRules(Digester), en el que se definirn
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 parmetros de configuracin. Adems, se deben implementar mtodos que permitan
obtener un determinado parmetro (getParameter()), escribir un valor (setParameter()), etc.
/**
*
* El esquema de la configuracin que acepta es:
*
* <elements>
*
<element value="myId" label="bar"/>
*
<element value="myId2" label="bar2"/>
* </elements>
*/
public class FooContentHandler extends XMLConfigContentHandler {
70

Operaciones

public FooContentHandler(String name) {


super(name);
}
protected void setDigesterRules(Digester digester) {
digester.addObjectCreate("elements", "java.util.ArrayList");
digester.addObjectCreate("elements/element",
"es.princast.framework.core.vo.PropertyBean");
digester.addSetProperties("elements/element");
digester.addSetNext("elements/element", "add",
"es.princast.framework.core.vo.PropertyBean");
}
public void setParameter(String key, String value) {
throw new UnsupportedOperationException();
}
public List getConfigurationObjects() {
return (List) getXMLObject();
}
public String getParameter(String key) {
PropertyBean pb = (PropertyBean) getConfigurationObject(key);
return (pb != null) ? pb.getLabel() : null;
}
public Enumeration getKeys() {
List objects = getConfigurationObjects();
Vector keys = new Vector(objects.size());
Iterator it = objects.iterator();
while (it.hasNext()) {
PropertyBean pb = (PropertyBean) it.next();
keys.add(pb.getValue());
}
return keys.elements();
}
public Object getConfigurationObject(String key) {
List objects = getConfigurationObjects();
Iterator it = objects.iterator();
while (it.hasNext()) {
PropertyBean pb = (PropertyBean) it.next();
if (key.equals(pb.getValue())) {
return pb;
}
}
return null;

71

Operaciones

}
public void setConfigurationObject(String key, Object value) {
PropertyBean pb = (PropertyBean) getConfigurationObject(key);
if (pb != null) {
if (value instanceof PropertyBean) {
pb.setLabel(((PropertyBean) value).getLabel());
} else {
pb.setLabel(value.toString());
}
} else {
List objects = (List) getXMLObject();
if (value instanceof PropertyBean) {
objects.add(pb);
} else {
objects.add(new PropertyBean(key, value.toString()));
}
}
}
public String getParameter(String path, String key) {
return getParameter(key);
}
public Object getConfigurationObject(String path, String key) {
return getConfigurationObject(key);
}
protected void registerDTDs(Digester digester) {
//No se registran DTDs
}
}

Logging
Para la gestin de las sentencias de log, en el openFWPA, se utiliza la librera: Log4j [18] (http://
logging.apache.org/log4j/). Log4j tiene tres componentes principales: loggers, appenders y
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 ejecucin la
forma en que estos mensajes se formatean y donde se escriben.

Log4J. Componentes
Loggers
Son entidades con nombre. Sus nombres son sensibles al contexto y siguen una regla de
nombrado jerrquica. 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 jerarqua de logres. Siempre existe y no puede ser recuperado por
nombre. Para recuperarlo se ha de invocar a mtodo esttico 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 depuracin

72

Operaciones

INFO

para mostrar informacin sobre lo que est haciendo la aplicacin

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 aplicacin, pero que lo permiten seguir
funcionando (por ejemplo, algn error en un parmetro de configuracin)
FATAL para mostrar mensajes crticos del sistema, generalmente despus del mensaje la aplicacin
finalizar
Si a un logger no se le asigna un nivel, lo hereda de su antecesor ms cercano que tenga asignado uno.
Para asegurarse que todos los loggers tienen un nivel, el logger raz siempre tiene asignado un nivel.
Las escrituras se realizan invocando a alguno de los mtodos de impresin del logger: debug, info, warn,
error, fatal y log. El mtodo de impresin 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.

Appenders
Log4j permite que los mensajes se impriman en mltiples 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


polticas de rotacin para que no crezca indefinidamente

DailyRollingFileAppender

escribe los mensajes de log en un fichero a que se le puede definir


polticas de rotacin basadas en la fecha

SocketAppender

escribe los mensajes de log hacia un servidor remoto de log

SMTPAppender

enva un correo electrnico 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

Para ms informacin sobre las opciones de configuracin de los Appenders, consultar la


documentacin de Log4j.

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:

73

Operaciones

SimpleLayout

prioridad del mensaje seguida por - y luego del mensaje de log

PatternLayout

especifica el formato de salida de acuerdo a unos patrones de conversin similares


a los de la funcin printf del lenguaje C (para ms informacin consultar la
documentacin)

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, categora y NDC, cualquiera de estos cuatro campos


puede ser deshabilitado y habilitado individualmente

Configuracin
En el diagrama de la Figura 6.3, Estados del Sistema de Logging se puede ver el ciclo de vida de la
configuracin del Sistema de Log de una aplicacin que utiliza openFWPA. Los estados por los que puede
pasar son los que siguen:
1. No Log: En este estado no hay configuracin alguna cargada. Si se lanza alguna sentencia de log,
aparecer un WARNING en la salida estndar del servidor OC4J. Este estado no debera producirse pero
se puede dar en caso de que se inicialicen componentes antes que el framework (listeners, ejbs, etc.)
2. Arranque: Se carga la configuracin de arranque del openFWPA. Esta configuracin se definir en
el fichero log4j.properties ubicado en el classpath de la aplicacin. En este fichero se puede
definir una configuracin de log, nicamente activa durante el proceso de arranque de la aplicacin.
3. Runtime: En este estado se supone activa la configuracin de log de la aplicacin. Esta configuracin
se define en el fichero xml indicado en el parmetro de configuracin LOGGING_XMLCONF, o en el
fichero de properties, cuyo path se indica en el parmetro de configuracin, LOGGING_PROPERTIES.

Figura 6.3. Estados del Sistema de Logging

Ejemplo de Configuracin
El sistema de logging se configura a travs de, por ejemplo, el fichero WEB-INF/log4j.xml (path que
se especifica bajo la constante de configuracin: LOGGING_XMLCONF). Este fichero debiera estar dentro
del fichero war de la aplicacin. Puede verse un ejemplo de utilizacin en la aplicacin en blanco (App
Blank) y en la de ejemplo (Sample App).
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "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="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<appender name="HTML" class="org.apache.log4j.DailyRollingFileAppender">

74

Operaciones

<param name="File" value="carrito-log.html" />


<layout class="org.apache.log4j.HTMLLayout">
</layout>
</appender>
<appender name="AUDIT" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="carrito-audit.html" />
<layout class="org.apache.log4j.HTMLLayout">
</layout>
</appender>
<category name="es.princast.framework">
<appender-ref ref="HTML" />
</category>
<category name="PISTA_AUDITORIA">
<priority value ="INFO" />
<appender-ref ref="AUDIT" />
</category>
<root>
<priority value ="info" />
<appender-ref ref="HTML" />
</root>
</log4j:configuration>

Atencin
Obsrvese que a pesar de haberse definido el appender STDOUT, no se est utilizando en ningn
caso. Este "no uso" es intencionado para evitar que, por descuido o por accidente, se vuelque
indiscriminadamente el log de las aplicaciones en la consola de los servidores, ya que se puede
producir un error por desbordamiento, en caso (muy probable) de que los administradores hagan
una redireccin a fichero de la salida.
En este fichero se definen varios Appenders (o destinos donde el logger va a escribir). La salida estndar,
un fichero Html (que cambiar todos los dias) y otro Appender de nombre Audit similar al anterior. Para
cada uno de ellos se define tambin el layout o plantilla que se utilizar para escribir la salida.
Tambin se definen categoras, donde se especifica para cada logger el nivel que tendr y los Appenders
que utilizar.
A continuacin se muestra la salida de un Appender que escribe en un fichero Html.

Para ms informacin sobre la configuracin del logger consultar la documentacin del mismo en la
direccin http://logging.apache.org/log4j/docs/manual.html

Componentes del openFWPA para Logging.


LoggingManager
En el ncleo (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)

75

Operaciones

Obtener los loggers estndar del framework: Pista de Auditora y Pista de Rendimiento.
El LoggerManager se puede gestionar desde la consola JMX.

PrincastHTMLLayout
Adems de los layouts incluidos en Log4J (Ver Layouts), las aplicaciones tambin pueden utilizar
PrincastHTMLLayout. Este objeto es igual que el HTMLLayout estndar, con la diferencia de que
muestra la fecha y hora en que se escribe la sentencia de log.

Pista de auditora
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 direccin IP desde la que se realiz la operacin
(registro NDC), ms una descripcin de la operacin 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 da se mueve el contenido de este log a un fichero con la
extensin .YYYY-MM-DD. El siguiente ejemplo se ha sacado de la aplicacin de ejemplo, y muestra la
ejecucin de dos operaciones marcadas como auditables:

Un ejemplo de cdigo que escribe informacin en la pista de auditoria sera el siguiente:

LoggingManager.getLogging().getAuditingTrack().info("[" + NDC.peek() + "] Aadiendo


Se hace uso de la clase LoggingManager de openFWPA, la cual se obtiene mediante el mtodo esttico
getLogging(). El mtodo 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
informacin sobre el usuario y la IP desde la que esta accediendo, informacin disponible mediante el
mtodo peek de la clase NDC de Log4j.
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 aplicacin, 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 auditora se puede configurar en el fichero de inicializacin del 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 auditora es: PISTA_AUDITORIA.

76

Operaciones

Pista de Rendimiento
La Pista de Rendimiento es un logger, muy similar a la Pista de Auditora, que permite escribir las
mediciones de rendimiento que se realicen en la aplicacin. La configuracin 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>
<category name="PISTA_RENDIMIENTO">
<priority value ="INFO" />
<appender-ref ref="AUDIT" />
</category>
El nombre del logger de rendimiento se puede configurar en la definicin 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.

Ficheros de Configuracin
Para la implementacin de aplicaciones web, utilizando el openFWPA, es necesario definir correctamente
los ficheros web.xml y struts-config.xml. En los apartados siguientes, se describe el contenido
que stos deberan tener.

web.xml
Como ejemplo de fichero web.xml, se tomar el incluido en la aplicacin en blanco (Blank App).
El primer bloque que se encuentra es el referente a la configuracin de filtros. Se define el filtro Gzip
(llamado GZIPFILTER), y se indica que todas las peticiones servlet de nombre action (que es el
ActionServlet) pasen por dicho filtro.
<!-- filtro GZip -->
<filter>
<filter-name>GZIPFILTER</filter-name>
<filter-class>es.princast.framework.web.filter.gzip.GZIPFilter</filter-class>
</filter>
<!-- Mapear el filtro GZip con el ActionServlet -->
<filter-mapping>
<filter-name>GZIPFILTER</filter-name>
<servlet-name>action</servlet-name>
</filter-mapping>
Otro filtro que se proporciona en la aplicacin en blanco es el de control de autenticacin. Para su activacin
es necesario incluir los siguientes elementos XML:

77

Operaciones

<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>es.princast.framework.web.filter.security.corp.PrincastSecurityFilte
</filter>
<!-- Mapeo del filtro de seguridad -->
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<servlet-name>/action/*</servlet-name>
</filter-mapping>
El siguiente conjunto de elementos hacen referencia al arranque e inicializacin de la aplicacin. Se
trata de la variable de contexto que indica la ubicacin del fichero de arranque (princast-initscript.xml) y el listener de inicializacin:
<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</li
</listener>
En el siguiente bloque se configura el ActionServlet. Se le pasan como parmetros:
config

nombre del fichero de configuracin.

debug

el nivel de detalle de debug que controla cuanta informacin se escribe en


el log. Acepta como valores: 0 apagado, y de 1 (menos detalle) a 6 (ms
detalle).

detail

el nivel de detalle del Digester que se usa para procesar los ficheros de
configuracin de la aplicacin. Acepta los mismos valores que el parmetro
debug.

application

el nombre del fichero de recursos que contendr los mensajes de la


aplicacin.

validating

especifica si se debe usar un parser validador de XML para procesar el


fichero de configuracin.

definitions-config

nombre del fichero donde se especifican las definitions de pantallas.

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>es.princast.framework.web.action.PrincastActionServlet</servle
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>

78

Operaciones

<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>application</param-name>
<param-value>resources.ApplicationResources</param-value>
</init-param>
<init-param>
<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>
El siguiente bloque indica al contenedor que debe redirigir cualquier peticin que contenga /action/
al ActionServlet, es decir, al servlet configurado en el bloque anterior.
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
En este bloque se indica que fichero servir por defecto la aplicacin. Tiene que ser un fichero fsico, no
es posible indicar una accin. Si se desea, en el propio fichero se puede redirigir a una accin como se
hace en la aplicacin de ejemplo (Sample App).
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
A continuacin se configuran las libreras de tags que utiliza la aplicacin. A partir de la versin del
Framework 1.5, se utiliza la versin de Struts 1.2, por lo que no se necesitan configurar las tags de Struts.

<taglib>
<taglib-uri>/WEB-INF/princast.tld</taglib-uri>
<taglib-location>/WEB-INF/princast.tld</taglib-location>
</taglib>

struts-config.xml
En este apartado se explicar el formato del fichero struts-config.xml incluido en la aplicacin
en blanco (Blank App). Este fichero est dividido en varios bloques: form-beans, globalexceptions, global-forwards, action-mappings, message-resources y plug-ins.
<form-beans>
Aqu se definen los beans de formulario, es decir, clases que heredan de
es.princast.framework.web.action.PrincastActionForm, y que sirven para almacenar

79

Operaciones

las propiedades introducidas en formularios enviados mediante peticiones Http. Estos formularios sern
utilizados por las acciones.

<form-bean name="loginForm" type="es.princast.framework.blankPA.forms.LoginForm" />


Otro
tipo
de
beans
de
formulario
con
las
es.princast.framework.web.action.PrincastDynaActionForm. Sirven para definir un
bean de formulario a travs del fichero de configuracin sin tener que escribir una clase para ello. Sus
propiedades son visibles con mtodos get y set de la misma forma que un bean convencional.

<form-bean name="detalleProductoForm"
dynamic="true"
type="es.princast.framework.web.action.PrincastDynaActionForm">
<form-property name="detalle" type="es.princast.framework.carrito.vo.ProductoVO" />
</form-bean>
<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
es.princast.framework.exceptions.PrincastException, sean reenviadas a la pgina
indicada en el atributo path (en este caso se trata de una definition). El mensaje de error que
se mostrar en la pgina 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.
Mediante el atributo handler se especifica qu manejador de errores se utilizar para tratar la excepcin.
En este caso se trata del manejador por defecto de Struts (que en el mtodo execute no realiza nada), pero
podra definirse un manejador que heredase de l y sobrescribiese el mtodo execute.
Se recomienda utilizar el mtodo catchException() de las acciones para tratar las excepciones y no
recurrir a excepciones globales.

<exception key="global.princastexception" type="es.princast.framework.exceptions.Pr


<global-forwards>
Son ActionForwards (asociaciones entre nombres lgicos y URIs) disponibles para todas las acciones.
Cuando una accin finaliza, devuelve un ActionForward o null. Si la accin no devuelve null, el
ActionServlet redirige el control al path que sea devuelto por la ActionForward.
<forward name="welcome" path="/action/login" />
<action-mappings>
En esta seccin se definen los mapeos de las acciones que manejar la aplicacin. Los parmetros comunes
a los diferentes tipos de acciones existentes son:
path

Path relativo al mdulo de la accin, comenzando por el carcter /, y sin


la extensin del nombre de archivo si se utiliza sta para el mapeo (por
ejemplo, para un mapeo del tipo accion.do, el path sera /accion).

type

Nombre de la clase, totalmente calificado, de la accin que procesar las


peticiones para este mapeo. El atributo no es vlido si se especifican los
atributos forward o include.

scope

El contexto (request o session) que se utiliza para acceder a los beans de


formulario.

80

Operaciones

validate (def. true)

Poner a true si el mtodo validate del bean de formulario debe ser llamado
antes de llamar a este mapeo.

A continuacin se comentarn de forma ms detallada los distintos tipos de acciones que maneja el
framework.
PrincastAction

Clase abstracta de la que deben heredar todas las acciones del


openFWPA. A continuacin se muestra un ejemplo de mapeo:

<action path="/login" type="es.princast.framework.carrito


<forward name="success" path="/action/viewperfil" redirec
<forward name="failure" path="/action/login" redirect="tr
</action>
La accin lleva anidadas dos ActionForwards a los que se
redirigir en funcin de que la accin 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 mtodo execute
de la accin local a la propia accin, se buscar la misma a nivel
global. Es necesario que a mbito local o global haya definidos dos
forwards success y failure.
Una accin tambin puede llevar anidadas excepciones. La sintaxis
es la misma que la de las Global Exceptions. En el caso de no
tener mapeada una excepcin local a la accin, se intentara buscar
a nivel global.
PrincastDispatchAction

Encapsula diferentes mtodos de ejecucin de una accin en una


misma clase. Para ello, se especifica en el atributo parameter del
mapeo de la accin en el fichero struts-config.xml, el
nombre del parmetro cuyo valor ser el nombre del mtodo que
ejecutar la accin.
El siguiente ejemplo muestra el mapeo de una accin que hereda
de PrincastDispatchAction. La accin ejecutar el mtodo
cuyo nombre se le pase en el parmetro method.

<action path="/carrito" type="es.princast.framework.carri


<forward name="success" path="carrito.viewcarrito" redire
</action>
PrincastCRUDAction

Hereda de la PrincastDispatchAction. Est pensada para


manejar mtodos de creado, consulta, actualizado y borrado (New,
Create, Retrieve, List, Update y Delete). Los posibles
nombres de los mtodos a ejecutar estn defini-dos 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
81

Operaciones

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 accin. Un ejemplo de
utilizacin de una accin de este tipo es el siguiente:

<action path="/welcome" parameter="carrito.login" type="e


La accin redirecciona a la definition de nombre carrito.login.
PrincastParameterAction

Busca un parmetro en la request de nombre dispatch y lo usa para


obtener un ActionForward. Una vez conseguido esto, va en
busca de un segundo parmetro en la request cuyo nombre debe
ser especificado en la propiedad parameter del mapeo de la accin.
Este valor se concatena con la URI obtenida de la propiedad path
del ActionForward que se busc con el valor del parmetro
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 accin 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 parmetros 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 idntica a la de la
PrincastExistsAttributeAction.
<controller>
En
el
siguiente
bloque
se
configura
el
controlador (RequestProcessor). Se recomienda utilizar
el
controaldor
proporcionado
por
el
openFWPA
(PrincastTilesRequestProcessor). El uso de este
controlador permite aadir alguna funcionalidad extra que no
implementa el controaldor por defecto (por ejemplo, mltiples
input por action, forwards a entradas de men, etc.)

<controller processorClass="es.princast.framework.web.act
El uso de este RequestProcessor limita los posibles
mapeos que se pueden hacer sobre el ActionServlet (ver a
continuacin). Las Actions nicamente se pueden mapear a un path
del tipo: /path/*. No se permiten mapeos del tipo: /path/
*.do.
<message-resources>

82

Operaciones

Indica
que
fichero
contiene
los
mensajes
que
mostrar
la
aplicacin.
En
este
caso
se
trata
del ApplicationResources.properties del paquete
resources.

<message-resources parameter="resources.ApplicationResour
<plug-in>
Aqu se indica que plug-ins va a utilizar la aplicacin. En primer
lugar se indica que se utilizar el validador de Struts, y que las reglas
de validacin 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.Validator
<set-property property="pathnames" value="/WEB-INF/valida
</plug-in>
A continuacin se indica que se utilizara tiles, y que las definitions
se describirn en el fichero tiles-defs.xml.

<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config" value="/WEB-I
<set-property property="moduleAware" value="true" />
<set-property property="definitions-parser-validate" valu
</plug-in>
Y por ltimo se indica que se utilizara el Struts Menu [16] y que su
configuracin residir en el fichero menu-config.xml.

<plug-in className="net.sf.navigator.menu.MenuPlugIn">
<set-property property="menuConfig" value="/WEB-INF/menu</plug-in>

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.

Filtros del openFWPA. PrincastFilter.


Todos los filtros (Servlet Filters) proporcionados por el openFWPA extienden del filtro base:
PrincastFilter. Este filtro extiende la jerarqua bsica 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.

Implementacin de un nuevo filtro


El proceso de implementacin de un nuevo filtro que haga uso de la infraestructura facilitada por el
openFWPA es muy sencillo. A continuacin se detallan los pasos a seguir:

83

Operaciones

1. Crear una clase Java que extienda la clase PrincastFilter.


2. Sobrescribir el mtodo filter() para aadir la lgica de negocio del filtro.

Atencin
El mtodo que se debe sobreescribir es filter() y no doFilter() como se hara para
escribir un filtro normal. El mtodo doFilter() es final en la clase PrincastFilter.
3. 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 [19] aportadas por el openFWPA para la gestin de los filtros.
No es necesario que el nuevo interfaz tenga mtodos.
4. Si se quiere implementar alguna lgica al inicializar el filtro, se debe extender el mtodo
initFilter().

Atencin
A partir de la versin 1.5, el mtodo init() de la clase PrincastFilter es final, por lo
tanto ya no se puede extender dicho mtodo.

Gestin de los filtros de forma dinmica


Una de las caractersticas ms novedosas aportadas por el openFWPA en cuanto a la gestin 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 aplicacin, en base a determinadas mtricas de rendimiento,
puede decidir en un momento dado si desea tener un filtro que comprima la respuesta enviada al cliente,
arrancndolo o apagndolo sin necesidad de tener que para la aplicacin para aplicar la nueva configuracin
en el fichero web.xml.

Filtros activables por reglas


A partir de la versin 1.4 del openFWPA, los filtros que extienden PrincastFilter pueden ser
desactivados para un conjunto determinado de URLs.
Este tipo de filtros se pueden mapear sobre un patrn de URL (como cualquier otro filtro) pero es posible
definir un subconjunto de patrones de URL, para las cuales el filtro no entrar en accin.
Cada uno de los patrones de URL excluidos de la accin del filtro se definir utilizando un init
param, en el fichero web.xml. Estos parmetros deben cumplir el siguiente convenio de nombrado:
EXCLUDED.URL.<Identificador descriptivo del patrn>.
<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>

84

Operaciones

<param-name>EXCLUDED.URL.LOGOUT </param-name>
<param-value>
/action/logout
</param-value>
</init-param>
</filter>
Adems, utilizando la consola JMX, es posible actualizar, en caliente, los patrones de URLs que se
excluirn del efecto del filtro.

Configuracin del filtro GZIPFilter


openFWPA tiene integrado un filtro (GZIPFilter) que se encarga de comprimir la respuesta usando
compresin gzip siempre que est est soportada por el navegador.
Para poder hacer uso del filtro que viene integrado con el openFWPA es necesario definirlo en el fichero
de configuracin web.xml. Un ejemplo de la configuracin a aadir en este fichero se presenta a
continuacin:

<!-- filtro GZip -->


<filter>
<filter-name>GZIPFILTER</filter-name>
<filter-class>es.princast.framework.web.filter.GZIPFilter</filter-class>
</filter>
<!-- Mapear el filtro GZip con el ActionServlet -->
<filter-mapping>
<filter-name>GZIPFILTER</filter-name>
<servlet-name>carrito</servlet-name>
</filter-mapping>

Configuracin del filtro SecurityFilter


Para el control de acceso de las aplicaciones que usen el openFWPA se facilita un filtro al efecto. Para
poder hacer uso de este filtro es necesario definirlo en el fichero de configuracin web.xml. Un ejemplo
de la configuracin a aadir en este fichero se presenta a continuacin:
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>
es.princast.framework.web.filter.security.corp.PrincastSecurityFilter
</filter-class>
</filter>
El filtro de seguridad se enmarca dentro del sistema de seguridad del openFWPA. Para mas informacin,
refirase al apartado: Seguridad, de este mismo documento.

Filtro de navegacin
El Filtro de Navegacin (clase NavigationFilter) tiene dos objetivos:
1. Mantener siempre el conocimiento de las entradas de men (y submenu) activas, evitando la necesidad
de utilizar tecnologas del lado del cliente como JavaScript y Cookies.

85

Operaciones

2. Mantener el estado de la barra de navegacin (Ver ???).

<filter>
<filter-name>NavigationFilter</filter-name>
<filter-class>es.princast.framework.web.filter.navigation.NavigationFilter</filter
</filter>
<filter-mapping>
<filter-name>NavigationFilter</filter-name>
<url-pattern>/action/*</url-pattern>
</filter-mapping>
El Filtro de Navegacin debe estar mapeado a todas las URLs referenciadas por alguna entrada de men
o submenu.
El Filtro de Navegacin, extrae de la Request los valores de los parmetros GET que indican la entrada
de men y submenu activas y, a partir de ellas, se encarga de mantener el estado del men y de la barra
de navegacin, manteniendolos siempre sincronizados.
Para conocer los nombres de los parmetros GET a los que tiene que acceder, el Filtro de Navegacin
implementa el interface ConfigurationListener (es decir, es un objeto configurable por el sistema
de configuracin del openFWPA) que escucha el contexto del men (MENU.CONTEXT), lo que significa,
que no se requiere ninguna configuracin especial para el Filtro de Navegacin, siempre y cuando, se
configure convenientemente el men.

Filtro de activacin
El Filtro de Activacin (clase AppActivationFilter) permite definir, cuando una aplicacin est
activa y cuando no. Este filtro tiene dos funciones:
1. Implementar lgica para activar/desactivar las aplicaciones en funcin de la fecha actual.
2. Servir como clase base para la implementacin de otros filtros que permitan determinar nuevas
condiciones para la activacin/desactivacin de aplicaciones.

Activacin de aplicaciones en funcin de fechas


El Filtro de Activacin permite determinar cuando, en funcin de la fecha actual, y de unos determiandos
intervalos de actividad, est activa la aplicacin. Si la fecha actual no encaja en ninguno de los intervalos
determinados, se redireccionar a una URL de advertencia y no se dejar entrar a la aplicacin.
El filtro acepta los siguientes parmetros de inicializacin (init-params en web.xml):
CONTEXT

Nombre del contexto de configuracin que se utilzar para especificar los intervalos de
actividad de la aplicacin. Por defecto vale: ACTIVATION.FILTER.

DATE.FORMAT

Formato (aceptado por SimpleDateFormat) que se utiliza para especificar el


formato de fechas de los intervalos. Por defecto vale: "dd/MM/yyyy HH:mm:ss".

ERROR.URL

URL a la que se redirigir en caso de no estar activa la aplicacin para la fecha actual.
Este atributo es obligatorio.

Los intervalos de actividad de la aplicacin se definirn en el contexto de configuracin (ver Sistema


de Configuracin del openFWPA) cuyo nombre se indica en el parmetro de inicializacin del filtro de
nombre: CONTEXT (por defecto: ACTIVATION.FILTER).
El nombre de cada parmetro de configuracin para estos intervalos debe seguir el patrn:
ACTIVE.INTERVAL.X. Donde X es un identificador que diferencia a cada intervalo del resto.

86

Operaciones

Los intervalos se definen utilizando dos fechas separadas por el caracter "-". El formato de las fechas se
define con el parmetro de inicializacin: DATE.FORMAT.
Si el extremo de un intervalo est indeterminado, se puede utilizar el caracter "?".
Por ejemplo:
ACTIVE.INTERVAL.1:
ACTIVE.INTERVAL.2:
ACTIVE.INTERVAL.3:
ACTIVE.INTERVAL.4:

22/10/2005 11:11:11 - 22/10/2006 11:11:15


22/10/2005 11:11:11 - ?
? - 22/10/2006 11:11:15
?- ?

Extensin del Filtro de Activacin


Es posible extender el Filtro de Activacin para definir nuevas condiciones de activacin y/o un nuevo
tratamiento para el caso en que la aplicacin no est activa. Basta con extender los mtodos:
isActive()

Determina si la aplicacin est activa. Recibe como parmetro la request.

handleInactive()

Se encarga de realizar la lgica adecuada en caso de que la aplicacin no est


activa.

Filtros de Activacin
En ocasiones, es necesario poder activar (o desactivar) una aplicacin o determinadas partes de la misma,
de forma declarativa. El openFWPA, desde la versin 1.5, incluye una clase base (ActivacionFilter)
que facilita la implementacin de filtros web para la gestin de la activacin de las aplicaciones.
Bsicamente este tipo de filtros tienen dos responsabilidades: a) determinar cuando la aplicacin est activa
(o no) y b) en caso de que la aplicacin est inactiva ejecutar alguna operacin (generalmente redireccionar
a una pgina de aviso).
Para implementar filtros de activacin es necesario extender la clase ActivationFilter. Los mtodos
ms relevantes de esta clase son:
isActive()

Determina cuando el recurso solicitado (URL) est activo. Este mtodo


devolver true si el recurso est activo. Se trata de un mtodo abstracto y, por
tanto, es de implementacin obligatoria por parte de las subclases.

handleInactive()

Realiza la lgica correspondiente en caso de que el recurso solicitado por el


cliente no est activo. La implementacin por defecto redireccionar a una
pgina previamente configurada.

configure()

Los filtros de activacin pueden ser configurados mediante el Sistema de


Configuracin de openFWPA. Por defecto, todos los filtros de activacin toman
parmetros del contexto "ACTIVATION.FILTER". Es posible cambiar el
nombre del contexto utilizando el parmetro de inicializacin del filtro (initparam en web.xml) de nombre: "CONTEXT".
Dentro de este contexto, se puede definir una pgina de redireccin (en caso de
que el recurso no est activo), utilizando el parmetro "ERROR.URL".

Filtro de Temporalidad
El Filtro de Temporalidad permite activar/desactivar una aplicacin (o partes de la misma) en funcin de
la fecha en la que se produzca el acceso.

87

Operaciones

El Filtro de Temporalidad (clase TimingFilter) es un filtro de activacin y, por tanto, tiene todas sus
caractersticas.
El Filtro de Temporalidad permite que los recursos que protege estn activos nicamente durante
determinados intervalos temporales, definidos como parmetros de configuracin. Estos parmetros
seguirn 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:
a. Con una fecha, especificada segn cualquier formato estndar vlido (SimpleDateFormat). El
formato concreto a utilizar se define con el parmetro de configuracin: DATE.FORMAT. Por defecto
vale: ."dd/MM/yyyy HH:mm:ss".
b. Utilizando el caracter "?". En este caso, se supone que se trata de un intervalo abierto, cuyo extremo
est inespecificado.
Algunos ejemplos de intervalos pueden ser:
ACTIVE.INTERVAL.1
ACTIVE.INTERVAL.2
ACTIVE.INTERVAL.3
ACTIVE.INTERVAL.4

=
=
=
=

22/10/2002 11:11:11 - 22/10/2004 11:11:15


22/01/2005 11:11:11 - ?
? - 22/10/2106 11:11:15
? - ?

Consola de gestin
Los componentes del openFWPA, estn diseados para que puedan ser monitorizados y gestionados, en
tiempo de ejecucin, utilizando una consola de gestin. A travs de la consola de gestin, el administrador
de sistemas puede arrancar, detener y reconfigurar en caliente los componentes del framework que
estime conveniente.
Para la implementacin de la consola de administracin se utiliza el API JMX (Java Management
Extensions). Este API permite la gestin y configuracin de objetos de la aplicacin.
El sistema de gestin JMX del openFWPA se configura utilizando el contexto de configuracin de nombre
JMX.CONTEXT. Los parmetros necesarios para activar la consola de gestin son los siguientes:
MBEAN.SERVER.NAME

Nombre del servidor JMX. Por defecto, su valor es frameworkpa. Cada


aplicacin debera poner su propio nombre como nombre de servidor.

JMX.SERVER.ADAPTOR

Existen varias implementaciones del estndar JMX y no todas son


completamente compatibles entre s. Cada implementacin tiene sus
particularidades (criterio de nombrado de MBeans, consola HTML
integrada, etc.). Por esta razn, es necesario incluir una capa de abstraccin
que permita a las aplicaciones, sin necesidad de recompilar, ejecutarse
correctamente con cualquier implementacin de JMX. Esta capa de
abstraccin es un adaptador para el servidor de MBeans. En funcin de la
implementacin JMX del entorno de ejecucin, se debe utilizar un adaptador
u otro. En el parmetro de configuracin JMX.SERVER.ADAPTOR, se
indicar el nombre completamente cualificado de la clase que actuar como
adaptador para el servidor JMX. Los posibles valores son:

es.princast.framework.core.management.adapters.NullMBeanServe
Para no utilizar ningn servidor. La consola de administracin JMX
aparecer desconectada.

88

Operaciones

es.princast.framework.core.management.adapters.JMXRIMBeanServ
Para conectar con la implementacin JMX de referencia (JMX-RI). Este
adaptador se debe utilizar con el contenedor OC4J 9.0.3. Si se va a utilizar
este adaptador, se deben definir, adems, los siguientes parmetros de
configuracin.
JMX.HTTP.PORT. Puerto donde escuchar la consola HTML.
JMX.HTTP.USERNAME. Nombre de usuario vlido para acceder a la
consola.
JMX.HTTP.PASSWORD. Contrasea vlida para acceder a la consola.

es.princast.framework.core.management.adapters.OC4JMBeanServe
Para conectar con la implementacin incluida en el servidor OC4J 10g. Si
se utiliza este adaptador, todo el sistema de operacin de las aplicaciones
estar integrado en la consola de administracin del contenedor.
Para conocer ms detalles a cerca de la consola de gestin, consultar el Manual de Operaciones.

89

Captulo 7. Seguridad en aplicaciones


con openFWPA
Seguridad
En el apartado Seguridad se contemplan todas las polticas y herramientas que permiten, tanto controlar
(y monitorizar) el acceso a determinadas partes de una aplicacin, como aquellas que permiten garantizar
la integridad y confidencialidad de los datos que se transmiten.
Los conceptos ms importantes dentro del control de acceso a una aplicacin son la Autentificacin y la
Autorizacin.
La Autentificacin 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 aplicacin. Dentro de la autentificacin se pueden
distinguir diferentes alternativas, siendo las ms recurridas la bsica (Basic authentication) y la basada en
formulario (Form-based authentication).

Autentificacin bsica
La autentificacin bsica delega el control de acceso al servidor Web. El usuario podr navegar libremente
por el sitio Web sin necesidad de facilitar una contrasea. Sin embargo, cuando se intente acceder a una
pgina protegida ser el propio navegador el que solicite al usuario un nombre de usuario (username) y
una contrasea (password) mostrndole una ventana de dialogo.
Tanto el nombre de usuario como la contrasea son enviados sin encriptar al servidor Web, quien se
encarga de validar-los 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
basndose en ciertas polticas definidas, por ejemplo, en un fichero tipo http.conf. Si la comprobacin
es positiva se sirve la pgina al cliente. En caso contrario, se le solicita de nuevo la combinacin usuario/
contrasea o se le muestra una pgina de error denegando el acceso.

Autentificacin basada en formulario


Suele ser la alternativa ms usada por los sitios Web dada su sencillez. Al igual que en la autentificacin
bsica, 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 pgina de login con un formulario con los
campos nombre de usuario y contrasea.
Para distinguir qu reas estn protegidas y cules no se emplean patrones de URLs. Dado que las
aplicaciones desarrolladas sobre el openFWPA deben correr en el servidor de aplicaciones OC4J [7] el
control de acceso se deja en manos de un proveedor de seguridad que viene integrado con el servidor
llamado XMLUserManager. Esta integracin est implementada como un filtro de URLs y se integra
con las APIs Java de Seguridad (JAAS).

Autentificacin basada en el Filtro de Seguridad del


openFWPA
La autentificacin basada en el Filtro de Seguridad, es la opcin estndar propuesta por openFWPA para
el control de acceso. Este tipo de autenticacin 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.

90

Seguridad en aplicaciones
con openFWPA

Figura 7.1. Esquema del sistema de autenticacin


Como resultado del proceso de autenticacin y autorizacin, el Filtro de Seguridad del openFWPA, pone
a disposicin de las aplicaciones todos los datos obtenidos en dicho proceso.
Para utilizar la autenticacin del openFWPA , se tendrn que tener en cuenta los siguientes puntos:
1. Configuracin 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).
2. Uso de la seguridad web j2ee estndar. En la clase HttpServletRequest, se puede interrogar por
las credenciales del usuario para realizar la autenticacin.
3. Configuracin. Es necesario definir los plugins de configuracin adecuados.
4. Paso de credenciales. Usando una extensin de la clase Principal, donde se proporcionan a la
aplicacin todos los parmetros que se recogieron durante el proceso de autenticacin.
5. Diseo de pginas de login. Las aplicaciones necesitan mostrar a los usuarios pginas que les
permitan introducir todos los datos necesarios para su autentificacin. Estas pginas deben tener unas
caractersticas determinadas para poder integrarse con la seguridad del openFWPA.

Integracin con seguridad web J2EE


En la clase javax.servlet.http.HttpServletRequest hay tres mtodos para controlar el
acceso a recursos de la aplicacin. Los siguientes prrafos se han extrado de la documentacin de la
versin 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 mtodo getRemoteUser devuelve el nombre del usuario que realiza la HttpRequest. Es
equivalente a ((PrincastIdentifier)getUserPrincipal()).getId()(ver abajo).
El mtodo getUserPrincipal devuelve el Principal ms importante (DNI) en este caso,
como una instancia de la clase PrincastIdentifier. Soporta el mtodo getName() (definido en
Principal) y getId() (definido en PrincastIdentifier). getName() devuelve la cadena DNI
y getId() devuelve el DNIdel usuario.
Para la gestin de roles (isUserInRole()) se emplean los roles asignados en el esquema de empleado
pblico. Los roles son tanto para ciudadanos como para empleados pblicos.

Configuracin
El sistema de seguridad estndar se configura utilizando el Sistema de Configuracin del openFWPA.
Todo el sistema tomar parmetros del contexto de seguridad llamado SECURITY, por lo tanto, es
importante recordar que cualquier plugin que sirve parmetros al sistema de seguridad debe registrarse
para el contexto SECURITY.

91

Seguridad en aplicaciones
con openFWPA

Parmetros bsicos
Los parmetros bsicos son:
app-config

Bajo este parmetro debe indicarse el nombre de la aplicacin. Este es el nombre


de la configuracin JAAS que se utilizar para realizar la autenticacin.

http.PORT

Puerto http que se utiliza para acceder a la aplicacin. Si no se especifica este


parmetro, se utilizar el puerto por defecto (80).

https.PORT

Puerto https que se utiliza para acceder a la aplicacin. Si no se especifica este


parmetro 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 aplicacin. Si no se especifica este parmetro se utilizar el puerto SSL (443)
por defecto.

http.IP

Direccin IP (o nombre DNS) del servidor que atiende peticiones http. Si no


se especifica este parmetro, la redireccin se realizar sobre la IP del propio
contenedor.

https.IP

Direccin IP (o nombre DNS) del servidor que atiende peticiones https (SSL v2),
con certificado de servidor. Si no se especifica este parmetro, la redireccin se
realizar sobre la IP del propio contenedor.

https/cert.IP

Direccin IP (o nombre DNS) del servidor que atiende peticiones https (SSL v3),
con certificado de cliente. Si no se especifica este parmetro, la redireccin se
realizar sobre la IP del propio contenedor.

Por ejemplo:

<bean id="baseConfigurationPlugin" class="es.princast.framework.core.configuration.


<constructor-arg><value>basePlugin</value></constructor-arg>
<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 ejemplo.properties, el que sigue:

#
#Fri Jan 07 10:08:36 CET 2005
HIT.COUNTER=es.princast.framework.core.management.mcounters.historic.HistoricalCoun
ACTION_MGMT=es.princast.framework.web.action.monitoring.PrincastActionMgmtInterface
LOGGING_XMLCONF=/WEB-INF/log4j.xml
app-config=EjemploApp
http.PORT=8888
https.PORT=4443
https/cert.PORT=8844
https/cert.IP=192.168.7.7
JMX.SERVER.ADAPTOR = es.princast.framework.core.management.adapters.OC4JMBeanServer

92

Seguridad en aplicaciones
con openFWPA

Configuracin JAAS
El sistema de autenticacin del openFWPA est basada en el estndar JAAS (Java Authentication and
Authorization Service). En realidad, el Filtro de Seguridad, no realiza ninguna tarea de autenticacin.
Estas funciones son delegadas en un Mdulo de Login JAAS (LoginModule). La configuracin del
mdulo a utilizar para autenticar y autorizar usuarios se realiza a travs del plug-in de configuracin JAAS
(JAASConfigurationPlugin), que debe ser declarado en el fichero de inicializacin princastinit-script.xml. Por ejemplo:

<bean id="jaasConfigPlugin" class="es.princast.framework.facilities.security.jaas.c


<constructor-arg><value>jaas-config</value></constructor-arg>
<property name="file"><value>WEB-INF/jaas-config.xml</value></property>
<property name="contexts">
<list>
<value>SECURITY</value>
</list>
</property>
</bean>
Los mdulos JAAS se configuran, en el openFWPA, mediante el fichero jaas-config.xml:

<!DOCTYPE jaas
PUBLIC "-//Framework PA - Team//DTD JAAS Configuration 1.3F//ES"
"jaas-config.dtd">
<jaas>
<application name="Carrito" controlFlag="required">
<module>es.princast.framework.modules.security.standalone.StandaloneLoginModule</
<options>
<option>
<name>USERS.FILE</name>
<value>/WEB-INF/authorized-users.xml</value>
</option>
</options>
</application>
</jaas>
En este fichero se definen los mdulos de configuracin a utilizar. Cada mdulo se define con la etiqueta
<application ..>. Cuando se vaya a autenticar a un usuario, se utilizar el mdulo cuyo valor del
atributo name coincida con el parmetro app-config (de los parmetros bsicos de autenticacin,
ver seccin anterior).
Eventualmente, el atributo controlFlag est desactivado. No se tiene en consideracin el valor
especificado para realizar la autenticacin.
Para cada mdulo, es obligatorio indicar el nombre de la clase que implementa la lgica de autenticacin,
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 configuracin especficas del mdulo JAAS que se vaya a utilizar.

Reglas de Seguridad
Por ltimo, es necesario configurar las reglas de seguridad que definirn que recursos de la aplicacin
estn protegidos, y de que forma.
Un recurso slo 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 patrn ms restrictivo.

93

Seguridad en aplicaciones
con openFWPA
Para configurar las reglas de seguridad, se debe definir, en el fichero princast-init-script.xml,
un plug-in de configuracin de tipo: SecurityRulesConfigurationPlugin. Por ejemplo:

<bean id="securityRulesPlugin" class="es.princast.framework.web.filter.security.cor


<constructor-arg><value>security-rules</value></constructor-arg>
<property name="file"><value>WEB-INF/princast-security-rules.xml</value></propert
<property name="contexts">
<list>
<value>SECURITY</value>
</list>
</property>
</bean>
Las reglas de seguridad se definirn, por su lado, en el fichero princast-security-rules.xml.
<!DOCTYPE resources
PUBLIC "-//Framework PA - Team//DTD Security Rules Configuration 1.3F//ES"
"princast-security-rules.dtd">
<resources>
<!-- Acceso para ciudadanos -->
<resource actor="CITIZEN" level="0" protocol=https>
<url-pattern>/*</url-pattern>
</resource>
<resource actor="CITIZEN" level="1">
<url-pattern>/action/*</url-pattern>
<forwards>
<forward name="login" path="/pages/login.jsp"/>
<forward name="no-login" path="/pages/login.jsp"/>
<forward name="no-roles" path="/pages/login.jsp"/>
<forward name="error" path="/pages/login.jsp"/>
</forwards>
<roles>
<role>EXAMPLE.ROLE.1</role>
<role>EXAMPLE.ROLE.2</role>
</roles>
<options>
<option>
<option-name>example option</option-name>
<option-value>example value</option-value>
</option>
<options>
</resource>
</resources>
En este fichero, cada etiqueta <resource> define un recurso protegido. Un recurso tiene tres atributos:
actor, nivel de seguridad y protocolo.
El atributo actor define el usuario-tipo que va a acceder al recurso. En funcin de este valor, el proceso
de autenticacin puede ser diferente. La semntica exacta de este atributo la establece el mdulo JAAS
que realice la autenticacin.
El atributo level, define el nivel de proteccin establecido para el recurso. Generalmente, hay 3: nivel
0 para recursos sin proteccin, nivel 1 para recursos protegidos bajo par usuario/contrasea y nivel 2 para
recursos protegidos con certificado digital.

94

Seguridad en aplicaciones
con openFWPA
Generalmente, un nivel de seguridad permite el login por los mecanismos para s definidos y tambin
mediante los definidos para niveles superiores. Por ejemplo, un recurso protegido bajo usuario/ contrasea
tambin ser accesible con certificado digital. La semntica exacta del nivel de seguridad, la define el
mdulo JAAS.
El protocolo (atributo protocol) define el tipo de acceso deseado al recurso. Puede tomar dos valores:
http si no se quiere ninguna encriptacin del recurso o https si se desea garantizar la privacidad de
los datos transmitidos entre el cliente y la aplicacin. Este atributo puede omitirse, en tal caso, se permite
el acceso al recurso bajo cualquier protocolo.
Un recurso protegido es, exactamente, un patrn URL que se aplica sobre el espacio de direcciones de la
aplicacin. Este patrn 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 patrn ms restrictivo de todos.
Cuando se produce un error autenticando al usuario, en funcin 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 contrasea es incorrecta, se le redirigir a una pgina 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 pgina distinta informndole de dicha situacin.
Las redirecciones se especifican bajo la etiqueta <forwards>. Cada redireccin tendr un nombre que
la identifica (name) y una url a la que se redirigir al usuario (path).
Los nombres de forwards vlidos son:
login

Se redirige a login la primera vez que un usuario trata de acceder a un recurso protegido.

no-login

Esta redireccin se ejecuta cuando no se puede autenticar al usuario por cualquier motivo
(por ejemplo, contrasea equivocada)

no-roles

Se redirige a este forward cuando el usuario, que est correctamente autenticado, no tiene
autorizacin para acceder al recurso.

error

Esta redireccin est reservada a situaciones de autenticacin no controladas por los


forwards definidos para el recurso. Si no se define forward de error, cuando se de un fallo
de autenticacin, se devolver un error http 515.

En cada recurso tambin se definirn 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 configuracin (<options>) que se estimen convenientes
para el recurso. La semntica de estas opciones depende exclusivamente del mdulo JAAS que realiza
la operacin de login.

Paso de Credenciales
Durante el proceso de autenticacin, se recaba una serie de datos del usuario. Estos datos se
guardan en la sesin http en un objeto de tipo javax.security.auth.Subject, bajo la clave
SecurityGlobals.SUBJECT.
Este objeto tiene los siguientes mtodos:
1. java.util.Set getPrincipals(). Devuelve un Set con los Principals (datos de
usuario) conocidos durante el proceso de autenticacin.

95

Seguridad en aplicaciones
con openFWPA
2. java.util.Set getPrincipals(PrincastIdentifier.class). Devuelve un Set con
el Principal ms importante, el DNI. Es equivalente a request.getUserPrincipal().
3. java.util.Set getPrincipals(PrincastCompositePrincipal.class). Devuelve
un Set con los Principal secundarios, de tipo java.util.Properties. Este objeto contiene
todas las propiedades capturadas en cada escenario en concreto, que son especficas a l (por ejemplo,
puede haber o no un IDTercero en funcin del escenario).
4. java.util.Set getPrincipals(Group.class). Devuelve un Set con todos los roles que
soporta un usuario.
5. java.util.Set getPrincipals(ScenarioPrincipal.class). Devuelve un Set que
contiene el Principal con los datos del escenario. Este Principal es un mapa que contiene
los parmetros que definen el escenario bajo el que se realiz el proceso de autenticacin (nivel de
seguridad, canal de acceso, tipo de actor, etc.)

Recuperacin de credenciales de usuario


Una vez que el usuario ha sido autenticado, sus credenciales son almacenadas en su sesin bajo la clave
SecurityGlobals.SUBJECT. ste es un objeto de tipo javax.security.auth.Subject.
Para recuperar las diferentes credenciales almacenadas en este objeto basta con emplear las diferentes
constantes definidas en la clase SecurityConstants como parmetros para las llamadas al mtodo
getPrincipal() de la clase Principals contenida en el objeto Subject .

Atencin
No es recomendable obtener los datos de autenticacin (j_username y j_password)
directamente de los parmetros de la request. No se garantiza que estos datos vayan a ser los
correctos. Adems, desde la versin 1.5, cualquier parmetro que se utilice como contrasea ser
enmascarado (reemplazado por la cadena "*********") por el filtro de autenticacin.
A continuacin se muestran diferentes ejemplos de recuperacin de credenciales.
Recuperacin del identificador de tercero de un usuario

Subject subject = (Subject)request.getSession(true).getAttribute(SecurityGlobals.SU


Set data = subject.getPrincipals(PrincastCompositePrincipal.class);
PrincastCompositePrincipal principals = (PrincastCompositePrincipal) data.iterator(
String idTercero = principals.getPrincipal(SecurityConstants.ID_THIRD_PARTY);
Recuperacin de las Unidades Organizativas asociadas a un usuario

...
PrincastCompositePrincipal principal = //Obtener el principal normalemente...
Map uniOrgs = new HashMap();
String id = principal.getPrincipal(SecurityConstants.ORGANIZATIONAL_UNIT_ID);
String name = principal.getPrincipal(SecurityConstants.ORGANIZATIONAL_UNIT_NAME);
if (id != null) {
uniOrgs.put(id, name);
}

96

Seguridad en aplicaciones
con openFWPA

int index = 1;
do {

id = princpal.getPrincipal(SecurityConstants.ORGANIZATIONAL_UNIT_ID+"_"+index);
name = princpal.getPrincipal(SecurityConstants.ORGANIZATIONAL_UNIT_NAME+"_"+index)
if (id != null) {
uniOrgs.put(id, name);
}
} while (id != null);
...
Recuperacin de los dominios de usuario.
Subject subject = (Subject) request.getSession(true).getAttribute(
SecurityGlobals.SUBJECT);
Set principals = subject.getPrincipals(PrincastRole.class);
Iterator it = principals.iterator();
while (it.hasNext()) {
PrincastRole pr = (PrincastRole) it.next();
Iterator itDom = pr.getDomains().iterator();
while (itDom.hasNext()) {
PrincastDomain pd = (PrincastDomain) itDom.next();
if (!pd.isProcedure()) {
logger.info("Nombre del dominio: " + pd.getName())
}
}
}

Diseo de pginas de login


En las aplicaciones que utilicen el Filtro de Seguridad del openFWPA, deben escribirse pginas JSP para
la obtencin de los datos de autentificacin. Estas pginas varan en funcin del tipo de autenticacin que
se quiera realizar.
A partir de la versin 1.4 del openFWPA se dispone de un nuevo diseo para las pginas de login en
aplicaciones de tramitacin (no de portal).
Con el fin de facilitar el diseo e implementacin de estas pginas, se ha incluido una etiqueta,
<ui:login>, en el fichero princast-ui.tld, as como un conjunto de clases CSS definidas en el
fichero login.css.
Los atributos permitidos por la etiqueta esta descritos en la ???
El filtro de autenticacin 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. Este atributo se puede utilizar para crear formularios de login
sin utilizar la etiqueta <ui:login>. Por ejemplo, como sigue:

97

Seguridad en aplicaciones
con openFWPA

<form action="<%=session.getAttribute(SecurityGlobals.REQUESTED_URL)%>" method="pos


//Aadir aqu los inputs necesarios para leer el username, contrasea, etc
</form>

Login de empleado pblico


En las pginas de login para el escenario de empleado pblico (tipo de actor: EMPLOYEE), deben incluise,
al menos, un campo de texto para obtener el nombre de usuario del empleado (j_username, por defecto)
y un campo de tipo password para leer su contrasea (j_password por defecto).
<?xml version="1.0" encoding="iso-8859-1"?>

<!-No se puede poner DTD. Si se pone DTD no funciona.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtm
-->
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="/WEB-INF/princast.tld" prefix="princast" %>
<%@ page import="es.princast.framework.web.filter.security.common.SecurityGlobals"
<html:html locale="es" xhtml="true" >
<head>
<html:base />
<title>
Bienvenido al Principado de Asturias
</title>
<link type="text/css" rel="stylesheet" href="css/general.css" />
<link type="text/css" rel="stylesheet" href="css/components.css" />
<link type="text/css" rel="stylesheet" href="css/login.css" />
</head>

<body onload="document.forms[0].j_username.focus()">

<princast:login>
<princast:panel layouterClass="es.princast.framework.web.view.layout.DivLayouter
<princast:panel-legend>Login</princast:panel-legend>
<princast:block cssClass="login_message">
<p>Bienvenido a la aplicacin de ejemplo SampleApp</p>
</princast:block>
<princast:block cssClass="login_inputs">
<label for="j_username">Usuario:</label>
<input type="text" name="j_username" id="j_username" />
</princast:block>
<princast:block cssClass="login_inputs">
<label for="j_password">Contrasea:</label>
<input type="password" name="j_password" id="j_password" />
</princast:block>
<princast:block cssClass="login_submit">
<p>
<input type="image" src="images/botones/enter-button.gif" alt="Entrar"/>
<input type="image" src="images/botones/right-arrow.gif" alt="Entrar"/>
</p>

98

Seguridad en aplicaciones
con openFWPA

</princast:block>
</princast:panel>
<princast:login-footer>
Por favor, si no va a utilizar la aplicacin cierre la sesion para evitar que ot
</princast:login-footer>
</princast:login>
</body>
</html:html>

Login de ciudadano a travs del portal.


Para el control de acceso de ciudadanos (tipo de actor: CITIZEN), con nivel de seguridad 1 (usuario /
contrasea), se requieren los siguientes campos:
Input de tipo text para recoger el identificador de usuario (NIF) del ciudadano. Por defecto, el
nombre de este campo ser j_username.
Input de tipo password para recoger la contrasea del ciudadano. Por defecto, el nombre de este
campo ser j_password.
Input de tipo text para recoger un CIF, en el caso de que el cuidadano represente a una persona
jurdica. El nombre de este campo ser cif

Login de ciudadano a travs de agente telefnico


En este tercer escenario, un ciudadano accede a una aplicacin a travs de un agente telefnico. En
este caso, la pgina de login no pedir la contrasea completa. En su lugar, se solicitarn caracteres
correspondientes a posiciones de la contrasea del ciudadano, seleccionados de forma aleatoria.
Los campos de entrada que se deben definir en este caso son:
Input de tipo text para recoger el identificador de usuario (NIF) del ciudadano. Por defecto, el
nombre de este campo ser j_username.
Input de tipo text para recoger un CIF, en el caso de que el cuidadano represente a una persona
jurdica. El nombre de este campo ser cif
Un campo de tipo hidden para indicar las posiciones de la contrasea que se solicitan. El nombre
para estos campos ser PASSWORD_POSITIONS.
Un campo de tipo text para recoger cada una de las posiciones de la contrasea
que se deben suministrar. Por defecto, el nombre para cada uno de estos campos ser,
PASSWORD_POSITIONS+posicin.
A continuacin se muestra un ejemplo de cmo generar los campos de solicitud de posiciones de clave
con etiquetas JSP:

<table>
<logic:iterate id="pos" name="PASSWORD_POSITIONS">
<tr>
<td>Introduzca la posicion <%=pos%><input type="hidden" name="PASSWORD_POSITIONS
<td><input type="text" name="PASSWORD_POSITIONS_<%=pos%>" size="1" maxlength="1"
</tr>
</logic:iterate>
</table>

99

Seguridad en aplicaciones
con openFWPA

Login de ciudadano a travs de colaborador


En este escenario (tipo actor COLABORADOR), un ciudandao accede a un recurso a travs de un agente
intermediario. Este escenario requiere la autenticacin tanto del ciudadano como del propio agente
intermediario. La autenticacin del agente colaborador se realiza con un par usuario/contrasea. La
autenticacin del ciudadano, se realiza con el par NIF / posiciones de la contrasea.
Los campos requeridos en este caso son:
Identificador (username) del colaborador. Se trata de un input de tipo text cuyo nombre por
defecto ser j_username.
Contrasea del colaborador. Debe ser un input de tipo password. Su nombre por defecto es:
proxyPassword.
NIF/NIE del ciudadano. Ser un input de tipo text cuyo nombre por defecto es nif.
CIF. Si el ciudadano representa a una persona jurdica, este campo recoger si CIF. Ser un campo input
de tipo text y nombre: cif.
Posiciones de la contrasea. Las posiciones de la contrasea del ciudadano se recogern en n campos
input text de nombre j_password_x, siendo x la posicin solicitada de la contrasea.
Para facilitar la implementacin de este tipo de pginas, el filtro de autenticacin deja los siguientes
atributos en el scope session:
SecurityGlobals.LOGIN_EXCEPTION. Excepcin disparada que provoca la aparicin de la
pgina de login.
SecurityConstants.USERNAME. Nombre de usuario del colaborador introducido en intentos de
login anteriores, erroneos, (si hubo).
SecurityConstants.PASSWORD. Contrasea del colaborador introducida en intentos anteriores,
erroneos, de login (si hubo).
SecurityConstants.NIFNIE. NIF del ciudadano introducido en intentos anteriores, erroneos, de
login (si hubo).
PASSWORD_POSITIONS. Lista de objetos de tipo PropertyBean que contienen, como valor
(getValue()) el numeor de posicin que se debe solicitar y como label (getLabel()) el valor
introducido en intentos anteriores, errneos, si hubo.
<?xml version="1.0" encoding="iso-8859-1"?>

<!-No se puede poner DTD. Si se pone DTD no funciona.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtm
-->
<%@
<%@
<%@
<%@
<%@
<%@
<%@

taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>


taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
taglib uri="/WEB-INF/princast.tld" prefix="princast" %>
taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
page import="es.princast.framework.web.filter.security.common.SecurityGlobals"
page import="es.princast.framework.facilities.security.SecurityConstants" %>
page import="es.princast.framework.core.vo.PropertyBean" %>

100

Seguridad en aplicaciones
con openFWPA
<%@ page import="es.princast.framework.web.filter.security.common.SecurityGlobals"
<html:html locale="es" xhtml="true" >
<head>
<html:base />
<title>
Bienvenido al Principado de Asturias
</title>
<link type="text/css" rel="stylesheet" href="css/general.css" />
<link type="text/css" rel="stylesheet" href="css/components.css" />
<link type="text/css" rel="stylesheet" href="css/login.css" />
</head>

<body onload="document.forms[0].j_username.focus()">

<princast:login>
<princast:panel layouterClass="es.princast.framework.web.view.layout.DivLayouter
<princast:panel-legend>Login</princast:panel-legend>
<princast:block>
<princast:instanceOf variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>" class
<div id="errors">
<ul>
<li>Validaci&oacute;n incorrecta de NIF/NIE y Clave personal</li>
</ul>
</div>
</princast:instanceOf>
<princast:instanceOf variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>" clas
<div id="errors">
<ul>
<li>Introduzca todos los datos que se solicitan</li>
</ul>
</div>
</princast:instanceOf>
</princast:block>
<princast:block cssClass="login_message">
<p>Bienvenido a la pgina de login de colaborador de ejemplo</p>
</princast:block>
<princast:block cssClass="login_inputs">
<p>Identificador de Colaborador</p>
<input type="text" name="j_username" id="j_username" value="<%=session.getAttri
</princast:block>
<princast:block cssClass="login_inputs">
<p>Contrasea del Colaborador</p>
<input type="password" name="proxyPassword" id="proxyPassword" value=
"<%=session.getAttribute(SecurityConstants.PASSWORD) != null ? session.get
</princast:block>
<princast:block cssClass="login_inputs">
<p>NIF/NIE del ciudadano</p>
<input type="text" id="nif" name="nif" value=
"<%=session.getAttribute(SecurityConstants.NIFNIE)!=null ? session.getAttr
</princast:block>
<princast:block cssClass="login_inputs">
<p>Si representa a una persona jurdica, introduzca su CIF</p>

101

Seguridad en aplicaciones
con openFWPA

<input type="text" id="cif" name="cif"/>


</princast:block>
<princast:block cssClass="login_inputs">
<p>Introduzca las siguientes posiciones de la contrasea del ciudadano:</p>
<logic:iterate id="pos" name="PASSWORD_POSITIONS">
<table>
<tr>
<td style="text-align: left; width:90%"><span class="textos">Introduzca la p
<td style="text-align: right; width:10%"><input type="text" name="j_password
value="<%=((PropertyBean) pos).getLabel()%>" size="1" maxlength="1"/> </td
</tr>
</table>
</logic:iterate>
</princast:block>
<princast:block cssClass="login_submit">
<p>
<input type="image" src="images/botones/enter-button.gif" alt="Entrar"/>
<input type="image" src="images/botones/right-arrow.gif" alt="Entrar"/>
</p>
</princast:block>
</princast:panel>
<princast:login-footer>
Por favor, si no va a utilizar la aplicacin cierre la sesion para evitar que ot
</princast:login-footer>
</princast:login>
</body>
</html:html>
La pgina HTML correposndiente al JSP del ejemplo anterior se puede ver en la imagen siguiente:

Excepciones durante el proceso de autenticacin


En caso de que durante el proceso de autenticacin se lance alguna excepcin, sta es almacenada
en la sesin 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 presentacin
en funcin de la excepcin que se haya producido. Para ello se proporciona un tag JSP denominada
<instanceOf> y que recibe los siguientes parmetros:
variableName

Nombre de la clave bajo la cual se busca la excepcin.

className

Nombre cualificado de la excepcin con la que se realiza la comprobacin.

Un ejemplo de uso de esta etiqueta se presenta a continuacin:


<princast:instanceOf variableName="<%=SecurityGlobals.LOGIN_EXCEPTION%>"
<div id="errores">
<ul>
<li>Validaci&oacute;n incorrecta de NIF/NIE y Clave personal</li>
</ul>
</div>
</princast:instanceOf>

102

classNam

Seguridad en aplicaciones
con openFWPA
Como
se
puede
apreciar
se
comprueba
que
la
excepcin
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 afirmativose incluyen los elementos
contenidos entre <princast:instanceOf></princast:instanceOf>. Las excepciones
que se pueden disparar durante el proceso de autenticacin, se encuentran en el paquete:
es.princast.framework.facilities.security.exceptions.

Niveles de Seguridad
Para la autenticacin se contemplan tres niveles de seguridad:
Nivel 0

Con este nivel de seguridad no se requiere autenticacin.

Nivel 1

Con este nivel es necesaria la validacin mediante usuario y contrasea. Para ello, deben
especificarse dos parmetros denominados j_username y j_password con dicha
informacin.

Nivel 2

Este nivel de seguridad se corresponde a la autenticacin utilizando certificado digital.


Debe tratarse de un certificado digital vlido de la FNMT (Fbrica Nacional de la Moneda
y Timbre). Para forzar a esta validacin debe incluirse en la peticin http un parmetro
denominado forceLevel con el valor 2.

Un ejemplo de uso de este nivel de seguridad se presenta a continuacin:


http://localhost:8888/prueba/action/suscribe?forceLevel=2
Para mayor informacin acerca de los niveles de seguridad soportados acdase a la documentacin del
Mdulo de Login que est utilizando para su aplicacin.

Single Sign On
Con el fin de facilitar la integracin de aplicaciones en un mismo portal, el Principado de Asturias dispone
de una solucin Single Sign On (SSO), basada en el producto Novell iChain.
El sistema Single Sign On permite a un usuario, acceder a varias aplicaciones autenticndose una nica
vez, valiendo esta autenticacin para todas ellas.
Actualmente, se pueden autenticar contra el sistema SSO todos los usuarios dados de alta en el LDAP
corporativo del Principado de Asturias.
El filtro de seguridad del openFWPA soporta, a partir de la versin 1.5 , de forma automtica, autenticacin
basada en el SSO del Principado de Asturias para todos los escenarios de autenticacin de Nivel 1 (salvo
los que utilizan posiciones de contrasea).

Atencin
Para que el filtro de seguridad se pueda integrar correctamente con SSO, ste debe enviar, en la
cabecera de la peticin http (header) el par usuario/contrasea codificado en Base64, utilizando
es esquema bsico (Basic) de autenticacin http.
Para utilizar el SSO en versiones anteriores a la 1.5, se debe utilizar el "parche para compatibilidad con
SSO".

103

Captulo 8. Integracin de Sistemas


Tecnologas de Integracin
Frecuentemente, las aplicaciones desarrolladas con el openFWPA se deben integrar con los sistemas
corporativos del Principado de Asturias (bases de datos, mdulos comunes, etc). El mecanismo estndar
para la interconexin de sistemas, en el Principado de Asturias, es el intercambio de documentos XML
sobre el protocolo HTTP 1.1.
La estructura de los documentos a intercambiar, se ajusta a la DTD de XML Genrico (para ms
informacin solictese documento correspondiente al Principado de Asturias).
<?xml version="1.0" encoding="ISO-8859-1" ?>
<SERVICIO siscliente="POR_DEFINIR" sisservidor="BDGENERICOS"
nomservicio="CONS_COD_PAIS" fecha="25/06/2003 13:46:46">
<ENTRADAS>
<entrada dato="CN_PAIS">108</entrada>
</ENTRADAS>
<SALIDAS>
<ERROR>
<salida dato="COD">0</salida>
<salida dato="DESC">OK</salida>
</ERROR>
<salida dato="PAIS">ESPAA</salida>
</SALIDAS>
</SERVICIO>
En el recuadro superior, se muestra un ejemplo de XML Genrico recibido como respuesta de la consulta
del pas, cuyo cdigo es 108. La respuesta, sin errores, es: ESPAA.
El openFWPA ofrece soporte para la integracin de aplicaciones con otros sistemas del Principado de
Asturias, utilizando tanto intercambio de XML Genrico, como servicios web (all donde se apliquen).
Los componentes del openFWPA que facilitan la integracin entre sistemas, implementan el interface:
es.princast.framework.facilities.backends.BackEndProxy.
Todos los clientes, que proporciona el openFWPA para la integracin con los sistemas corporativos
del Principado de Asturias son configurables. Es decir, pueden ser configurados en caliente a travs
del sistema de configuracin del openFWPA o, dicho de otra forma, implementan el interface
ConfigurationListener.

XML Genrico: Configuracin


La mayora de los sistemas del Principado de Asturias se comunican entre s mediante el intercambio de
XML Genrico, por esta razn, los componentes del openFWPA que trabajan con este tipo de documentos
XML son habituales.
Los clientes de sistemas corporativos que utilizan intercambio de XMLGenrico se configuran siguiendo
el mismo proceso:
1. Cada cliente dispone de un nombre de contexto identificativo. Por ejemplo: GENERICOS, SMS,
CLAVES, etc.

104

Integracin de Sistemas

2. Se debe definir un plug-in de configuracin de tipo PropertiesFileConfigurationPlugin


en el fichero princast-init-script.xml, que accede a un fichero de configuracin (un fichero
.properties) especfico para el cliente. Este plugin, se debe registrar para el contexto identificativo
del cliente.
3. Definir en el fichero de properties los siguientes parmetros:
CLIENT_SYS. Identificador de la aplicacin cliente. Se trata de una cadena que identifique a la
aplicacin cliente que solicita el servicio.
SERVER_SYS. Identificador del sistema servidor. Es una cadena identificativa del sistema que recibe
la peticin. El identificador de cada sistema concreto debe solicitarse al Principado de Asturias.
DTD. URL donde est publicada la DTD del documento XML Genrico que se enva. Se debe solicitar
al Principado de Asturias la URL de la DTD que se debe utilizar para cada proyecto concreto.
URL. Direccin del servicio al que se debe enviar el XML Genrico.
USER. Nombre de usuario. Se utiliza para autenticar la peticin de servicio.
PASSWORD. Contrasea de acceso. Junto al parmetro USER, se utiliza para la autenticacin de la
peticin.
CONNECTION. Nombre completamente cualificado de la clase que se utilizar para establecer la
conexin con el sistema. Este parmetro es opcional. Las conexiones existentes actualmente son:
XML_generico.ConexionXML

Establece una conexin HTTP 1.1. con el sistema servidor. Es


el tipo de conexin por defecto.

es.princast.framework.facilities.backends.genericXML.connection.
Establece una conexin con el sistema, sin efectuar validacin
FrameworkConnectionXML
de la DTD. Se recomienda su uso nicamente en entornos con
conectividad limitada.
Realiza URL encode del contenido a enviar al sistema XML
Genrico con el que interactua.
es.princast.framework.facilities.backends.genericXML.connection.
Establece una conexin con el sistema, sin efectuar validacin
FrameworkConnectionXMLNoEncoding
de la DTD. Se recomienda su uso nicamente en entornos con
conectividad limitada.
Esta conexin es igual a la anterior con la salvedad de que no
se realiza el URL encoding. Es el tipo de conexin a utilizar
cuando el sistema a conectar sea BDGENERICOS.
es.princast.framework.facilities.backends.genericXML.connection.
Si se utiliza este tipo de conexin, no se producir ninguna
MockConnectionXML
comunicacin real con el sistema cliente. La conexin ser
nicamente simulada. Este tipo de conexin se debe utilizar
nicamente para pruebas de desarrollo.

105

Captulo 9. Pruebas
Pruebas unitarias
Toda aplicacin J2EE desarrollada utilizando el openFWPA debera tener presente, en todo momento, la
realizacin de pruebas unitarias de todos sus componentes relevantes. De esta forma se tiene una batera
de pruebas que pueden ejecutarse en cualquier momento como pruebas de regresin. Debiera disponerse
de un proceso en el servidor que se encargue de lanzar tales pruebas un nmero determinado de veces y
genere un informe con los resultados de la ejecucin de las pruebas.
Todo esto se ha tenido en cuenta a la hora de desarrollar el openFWPA y se proporciona una infraestructura
basada en JUnit [11] que se puede utilizar a tal efecto. Esta infraestructura base para la implementacin
de pruebas unitarias se empaqueta en la librera de herramientas del openFWPA: fwpa-toos.jar
Se proporciona un conjunto de clases plantilla para facilitar la implementacin de pruebas unitarias. Estas
clases de prueba se pueden clasificar en dos grandes grupos:
Pruebas locales. Se ejecutan en el propio PC de desarrollo.
Pruebas en contenedor. Se ejecutan en una aplicacin web, sobre el servidor de aplicaciones. El
openFWPA proporciona soporte para la implementacin de pruebas unitarias en contenedor, utilizando
la librera Cactus, de Apache.

Jerarqua de clases para las pruebas unitarias


En funcin del tipo de prueba unitaria que se desee realizar (prueba de bases de datos, de Actions Struts,
etc.) se dispone de una clase base especfica que debe ser extendida. Las clases base para pruebas unitarias
suministradas en openFWPA se muestran en la figura que sigue:

Figura 9.1. Set de pruebas unitarias disponibles

PrincastTestCase. Se utiliza para la implementacin de pruebas unitarias para clases estndar.


PrincastContextTestCase. Se utiliza para probar beans de Spring.
PrincastJMXComponentTestCase. Para la implementacin de pruebas de MBeans JMX.
PrincastDatabaseTestCase. Se debe extender para implementar pruebas unitarias de
componentes que acceden a bases de datos.
PrincastDAOTestCase. Se debe extender para implementar pruebas unitarias de DAOs (Data
Access Objects).
PrincastReportTestCase. Se utiliza para probar generacin de reports.
PrincastMockStrutsTestCase. Se utiliza para definir pruebas unitarias de Actions fuera del
contenedor.
PrincastActionTestCase. Esta clase se utiliza para implementar pruebas unitarias de Actions
Struts que se ejecuten en contenedor.

106

Pruebas

PrincastJspTestCase. Se utiliza para implementar pruebas para pginas JSP o para etiquetas
(Custom Tags). Este tipo de pruebas se ejecuta en contenedor.
PrincastFilterTestCase. Se utiliza para pruebas unitarias de filtros (Servlet Filter). Este tipo
de pruebas se ejecuta en contenedor.
PrincastServletTestCase. Se utiliza para probar Servlets. Este tipo de pruebas se ejecuta
en contenedor.
PrincastWebTestCase. Se utiliza para probar la navegacin Web, envo y respuesta de
formularios, etc. Este tipo de pruebas se ejecuta en contenedor.

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 mtodos que implementen los diferentes casos de pruebas, se suele emplear:
public void test<nombre_caso_prueba> () {};
JUnit reconoce como casos de prueba todos aquellos mtodos que sigan esta convencin de nombrado.

Ejecucin de las pruebas unitarias


Con el fin de facilitar la labor de ejecucin de los diferentes tests, en el fichero build.xml de la
aplicacin en blanco que se proporciona con el openFWPA existe un target de Ant [10] que se encarga
de esto.
Su nombre es test.unit y se encarga de ejecutar todos los tests cuyo nombre de clase termina en Test y
genera una serie de informes HTML en la carpeta test\reports con los resultados de la ejecucin
de los mismos.
Para la ejecucin de los tests tan slo es necesario el siguiente comando en lnea de comandos:
ant test.unit
o bien, la forma anloga desde el entorno de desarrollado integrado que se use.

Consultando los resultados de los tests


Una vez ejecutadas las pruebas unitarias, se pueden consultar los resultados de las mismas en una serie de
informes HTML que son guardados en la carpeta test\reports.
En la captura siguiente, se puede ver un ejemplo de informe del resultado de la ejecucin de una batera
de tests.

En la imagen siguiente se puede ver el informe detallado de una de las pruebas pertenecientes a la batera
de pruebas anterior.

107

Pruebas

Pruebas unitarias de objetos que acceden a bases de


datos.
Para una aplicacin 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 aplicacin 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 lgico ya
que en un buen diseo nunca un componente de acceso a BD tendr dependencias respecto al contendor
donde se ejecuta.
Para realizar pruebas de clases que deben acceder a una BD, se utilizar la clase de test
PrincastDatabaseTestCase. Si estos objetos son DAOs de una aplicacin, siempre se puede
utilizar la subclase PrincastDAOTestCase que ofrece ms funcionalidad para la prueba de este tipo
de objetos.
Las pruebas unitarias de objetos que acceden a bases de datos, estn 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).

Atencin
Desde la versin 1.5 del openFWPA, las pruebas unitarias de acceso a base de datos estn basadas
en el framework Spring.
El hecho de que este tipo de pruebas unitarias est basado en Spring supone que:
1. Es necesario declarar los DataSources que se van a utilizar en un fichero de definicin de beans
de Spring.
2. No es necesario controlar las transacciones que se realicen durante el test.
3. 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 setter que tenga la clase de pruebas busca, en
los ficheros de definicin de beans, un bean que encaje en el tipo de la propiedad y se lo asigna.

Atencin
Es muy importante tener en cuenta que el autowiring de beans con la clase de test se realiza
por tipo. Si ms de un bean encaja en el tipo de la propiedad puede producirse un error. El
DataSource a utilizar tambin se asigna a la clase de test utilizando autowiring, por lo tanto,
nicamente se puede declarar un DataSource en los ficheros de definicin de beans.
Para implementar tests extendiendo PrincastDatabaseTestCase, se seguirn todas las normas
y convenciones definidos para implementar casos de prueba estndar (Ver Convenciones a seguir).
Adems, se debe implementar el mtodo:
getDataSourceFile(), que devuelve el path donde se encuentra el fichero de defincin de beans
en el que se declara el DataSource a utilizar. Por ejemplo:

protected String getDataSourceFile() {


return "classpath*:/es/princast/framework/facilities/dao/datasource-beans.xml";

108

Pruebas

}
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 mtodo 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 ms informacin sobre cmo usar esta clase, consltese el manual
de referencia del framework Spring.
onSetUpInTransaction(). Extendiendo este mtodo, se pueden realizar todo tipo de
actualizaciones (inserciones, borrados, etc.) que sean necesarios para la posterior ejecucin de la prueba.
Todas las actualizaciones que se realicen estarn disponibles, nicamente durante la ejecucin del test.
No quedar rastro de estas operaciones en la base de datos.
Este mtodo sustituye al fichero DataSet XML de dbUnit. Si se utiliza este mtodo, y se quiere utilziar
tambin dbUnit, se debe hacer una llamada a super.onSetUpInTransaction().
onSetUpBeforeTransaction(). Este mtodo es anlogo al anterior con al diferencia de que las
actualizaciones realizadas en este mtodo s que son persistentes en la base de datos.
Un ejemplo de uso de estos elementos es el que sigue:
protected void onSetUpInTransaction() throws Exception {
jdbcTemplate.execute("insert into foo values ('1', 'foo foo')");
}

Utilizando dbUnit con PrincastDatabaseTestCase.


Es posible utilizar la librera dbUnit (http://www.dbUnit.org)
PrincastDatabaseTestCase. Para ello, se deben realizar los siguientes pasos:

con

la

clase

1. Escribir el fichero XML (DataSet XML) de datos para la prueba. El fichero DataSet XML est
definido por la librera DBUnit y tiene el formato que se muestra en el siguiente ejemplo:
<dataset>
<PROPS id='1' value='pepe'/>
<PROPS id='2' value='ramon'/>
</dataset>
Cada registro de la base de datos se escribir en una etiqueta independiente, indicando, el valor de cada
campo, como atributos de dicha etiqueta.
En estos test siempre se puede suponer que la base de datos est cargada con los registros definidos
en el fichero DataSet XML. Al finalizar los tests, la base de datos, siempre volver a su estado inicial
(antes de lanzar los test).
2. Extender el mtodo getDataSetXML() para especificar el path de dicho fichero. Este path siempre
debe ser relativo al classpath.

109

Pruebas

3. Indicar la operacin a realizarse por defecto para incializar los tests. Se debe extender el mtodo
getDatabaseSetupOperation(). Las operaciones soportadas son:
DatabaseOperation.CLEAN_INSERT
Elimina todo lo que haya en la tabla e inserta los datos del fichero
XML obtenido con el metodo getDataSetXMLFile().
DatabaseOperation.INSERT

Inserta los datos del fichero XML

DatabaseOperation.UPDATE

Actualiza los datos de la base de datos con los proporcionados


por el fichero XML.

DatabaseOperation.REFRESH Inserta los registros del fichero XML que no existan en la base
de datos. Actualiza los que ya existan previamente.
DatabaseOperation.NONE
No se realiza ninguna operacin con la base de datos.
Estas operaciones solamente tienen efecto durante la ejecucin del test. No se realizarn cambios
permanentes en la base de datos.
Por defecto, este mtodo devuelve la operacin: DatabaseOperation.CLEAN_INSERT.
4. Configurar las conexiones (DataSource) como cualquier otro tipo de prueba unitaria de base de
datos.

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.
Para este tipo especfico de pruebas, se proporciona una clase
PrincastDataBaseTestCase) llamada: PrincastDAOTestCase.

(que

extiende

de

Atencin
La clase PrincastIBatisTestCase, existente en versiones del openFWPA anteriores
a la 1.5, cuyo objetivo era probar DAOs implementados con iBatis, ha sido eliminada del
openFWPA. El uso de la clase PrincastDAOTestCase permite probar cualquier tipo de
DAOs, independientemente de la tecnologa con que se implementen (por supuesto incluyendo
iBatis).
Todas las caractersticas propias de la superclase (PrincastDataBaseTestCase) se aplican a
PrincastDAOTestCase, incluyendo, por supuesto, la gestin y obtencin de DataSources.
Los objetos DAO a probar se deben declarar en un fichero de defincin de beans de Spring. La ubicacin
de este ficho se proprocionar extendiendo el mtodo: getDaoFile().

Figura 9.2. Autowiring de DAOs y DataSources


Para obtener instancias de los DAOs a probar, la clase de pruebas debe definir un mtodo setter
para cada uno de ellos. La clase base (PrincastDatabaseTestCase) se encargar de asignar a
estas propiedades los DAOs, declarados en el fichero de defincin de beans, cuyo tipo sea compatible
(autowiring por tipo).
Es importante tener en consideracin que, si ms de un bean es compatible con el tipo de una propiedad
del test, se puede producir un error.
/**

110

Pruebas

* Clase para probar DAOs (interface <code>PrincastDAO</code>).


*
* @see PrincastDAO
*
*/
public class PrincastDAOTest extends PrincastDAOTestCase {
/**
* El objeto a probar
*/
protected FooDAO2 dao;
/**
* Establece el DAO que se va a probar.
* No hace falta llamar directmente a este mtodo. Spring se encargar, al lanzar
* de asignar el DAO, utilziando autowiring por tipo
*
* @param dao el DAO a probar
*/
public void setFooDAO2(FooDAO2 dao) {
this.dao = dao;
}

protected String getDaoFile() {


return "classpath*:/es/princast/framework/facilities/dao/mock/mock-dao-beans.xml"
}
protected String getDataSourceFile() {
return "classpath*:/es/princast/framework/facilities/dao/datasource-beans.xml";
}
protected void onSetUpInTransaction() throws Exception {
jdbcTemplate.execute("insert into foo values ('10', 'foo1')");
jdbcTemplate.execute("insert into foo values ('20', 'foo2')");
}
/**
* Prueba una consulta.
*
* @throws Exception
*/
public void testSelect() throws Exception
assertNotNull(dao);
List l = dao.getFooList("20");
assertNotNull(l);
assertEquals(1, l.size());
Map m = (Map) l.get(0);
assertEquals("foo2", m.get("nombre"));
}
}

111

Pruebas

Con solamente implementar el mtodo setFooDAO2(), al ejecutar el test se asignar


automticamente cualquier bean de la clase FooDAO2.
En el mtodo getDaoFile() se debe definir la ubicacin del fichero de definicin de beans donde
se declaran los DAOs. En este caso, se llama mock-dao-beans.xml, est ubicado en el classpath
y su contenido es el siguiente:

<beans>
<bean id="foo2" autowire="byType" class="es.princast.framework.facilities.dao.
</beans>
Con el mtodo getDataSourceFile() se define la ubicacin del fichero de declaracin de beans
donde se especifica el DataSource a utilizar. En este ejemplo, el fichero se llama datasourcebeans.xml, est ubicado en el classpath y su contenido es el que sigue:

<beans>
<!-- DataSource para Test -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManager
<property name="driverClassName"><value>org.gjt.mm.mysql.Driver</value>
<property name="url"><value>jdbc:mysql://localhost/foo</value></propert
</bean>
<!-- Es necesario tambin definir un TransactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.Da
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
</beans>
Todas las operaciones realizadas sobre la base de datos en este mtodo ser unicamente visibles a
lo largo del test.
Finalmente, se puede realizar el test normalmente utilizando los beans declarados en los ficheros
correspondientes.

Pruebas unitarias de Spring Beans


Se ha incluido una clase base (PrincastContextTestCase) para la implementacin de pruebas
unitarias de objetos definidos como beans de Spring.
Este tipo de pruebas unitarias son de utilidad siempre que se quieran probar objetos (o estructuras de
objetos), creados, inicializados y construidos por Spring a travs de uno o varios ficheros de definicin
de beans.
Para definir el path (o paths) donde se realizar la bsqueda de los ficheros de definicin de beans
(estos paths siempre sern relativos al classpath, involucrados en la prueba, se debe sobreescribir el
mtodo:getDefinitionsPath(). Si este mtodo no se sobreescribe, el path de besqueda por defecto
ser: "/beans/**/*-beans.xml".
En cualquiera de los mtodos de la prueba unitaria, es posible acceder a cualquier bean (definido en
cualquiera de los ficheros de configuracin) utilizando el mtodo: getBean(), especificando como
parmetro el nombre del bean a buscar.

Pruebas unitarias de objetos Configurables


Un tipo especial de objetos son los que implementan el interface Configurable. Este tipo de objetos
requiere que, para poder ser utilizados, est activo todo el sistema de configuracin del openFWPA. En
las pruebas unitarias, el runtime del openFWPA no suele estar activo, por este motivo, es necesario,
si se quieren hacer pruebas unitarias de objetos Configurables, tener preconfigurado el objeto
FrameworkConfigurator.

112

Pruebas

Con el fun de facilitar la pre-configuracin de objetos Configurables, de cara a su prueba unitaria,


se ha incluido en el openFWPA una clase (ConfigurableObjectTestingHelper) que permite
realizar esta preconfiguracin de una forma fcil.
Esta clase dispone de las siguientes operaciones:
loadParameters

Carga en el FrameworkConfigurator un conjunto de parmetros. Este


mtodo se utiliza para establecer un estado inicial (pre-configurar) el Sistema
de Configuracin.

loadPropertiesFile

Esta familia de mtodos es similar a la anterior con la diferencia de que los


parmetros se cargan de un fichero de properties.

loadPlugin

Pre-configura el Sistema de Configuracin con un plug-in.

configureObject

Configura un objeto con un conjunto de parmetros. Estos mtodos,


pre-cargan el Sistema de Configuracin y, posteriormente, configuran el
objeto. La configuracin unicamente se puede hacer indicando un conjunto
de parmetros (como Properties), para realizar configuraciones ms
sofisticadas (varios contextos, plugins espcficos, etc.) deberan utilizanrse
los mtodos anteriores.

Properties props = new Properties();


props
.put("HIT.COUNTER",
"es.princast.framework.core.management.mcounters.simple.Sim
props
.put("EXCEPTION.COUNTER",
"es.princast.framework.core.management.mcounters.simple.Sim
props
.put(
"es.princast.ejemplo.Foo@EXCEPTION.COUNTER",
"es.princast.framework.core.management.mcounters.historic.H

ConfigurableObjectTestingHelper.configureObject(props, CounterFactory.getFac

Pruebas unitarias en contenedor


En el openFWPA, las pruebas unitarias en contenedor se realizan utilizando la librera Cactus. Las pruebas
unitarias con Cactus se ejecutan, parte en el cliente y parte en el servidor. Un breve resumen de los pasos
necesarios para ejecutar pruebas unitarias con Cactus es:
1. Escribir el fichero cactus.properties.
2. En el fichero web.xml declarar y mapear el objeto [Servlet|Filter|Jsp]Redirector.
Antes de escribir los tests, es importante recordar que los mtodos que se ajustan al patrn testXXX() se
ejecutan en el servidor (por lo tanto, todas las sentencias de log que en ellos se escriban aparecern en el log
del servidor y no en la consola) y los mtodo que se ajustan a los patrones beforeXXX() y endXXX(),
se ejecutan en el cliente (las sentencias de log aparecern en la consola y no en el log del servidor).

Pruebas de filtros
Para facilitar las pruebas unitarias de filtros, la clase base PrincastFilterTestCase, ofrece los siguientes
mtodos de utilidad:

113

Pruebas

assertPassingThruFilter() Sirve para verificar que el flujo que pasa por una cadena de filtros
no se ha interrumpido. No se ha realizado ni redirect, ni forward.
assertForwardTo()

Verifica que alguno de los filtros en la cadena ha realizado una


redireccin a travs de un forward.

Pruebas de validadores
Se ha incluido una clase base para facilitar la implementacin de pruebas de validadores de formularios.
Este tipo de pruebas se ejecutan en contenedor.
La clase base que debe ser extendida es PrincastValidatorTestCase. Esta clase pone a disposicin de sus
clases hijas los siguientes atributos:
request

La peticin http que se est utilizando

errors

Un conjunto de ActionErros de prueba

va

Una instancia de la clase ValidatorAction para probar

Estos tres atributos se pueden utilizar para realizar llamadas a los mtodos de validacin (sin necesidad
de disponer de instancias con valores reales).
Si se necesitan unos valores especficos para estos atributos, se pueden extender los mtodos
createValidatorAction() y createErrors(), de la clase base.
public void testValidateTwoFieldsOk() throws Exception {
FooForm form = new FooForm();
form.setDate1("21/11/2005");
form.setDate2("21/11/2005");
Field field = configureField();
assertTrue(FieldValidations.validateTwoFields(form, va, field, errors,
request));
}

Pruebas unitarias de informes


Las pruebas unitarias para informes permiten generar y previsualizar reports (utilizando JasperReports y
las clases del openFWPA), sin necesidad de que stos se ejecuten en el contenedor.
La clase base para este tipo de pruebas unitarias es PrincastReportTestCase. Define los siguientes
mtodos:
getReportName()

Este mtodo abstracto debe ser extendido por las subclases para especificar
el nombre del informe. El nombre del informe se utilizar para encontrar el
fichero de defincin del mismo (con el convenio de nombrado <nombre del
informe>.xml) y para nombrar el fichero PDF resultante (con el convenio
<nombre del informe>.pdf).

getOutputDir()

Las subclases pueden extender este mtodo para especificar el directorio


donde se dejar el fichero PDF generado. Por defecto, vale "" (cadena
vaca) que dejar el informe en el directorio raz del proyecto.

114

Pruebas

getInputDir()

Las subclases deberan extender este mtodo para especificar el directorio


donde se encuentra el fichero XML que define el informe. Por defecto,
este directorio ser "reports", siendo el path relativo al directorio raz del
proyecto. Es posible especificar paths absolutos o relativos al classpath
utilizando el prefijo "classpath://".

generateReport()

Gener el PDFProvider correspondiente al informe para ser utilizado en las


pruebas.

generatePDFReport()

Genera el informe y lo exporta al fichero PDF.

public class ProductosReportTest extends PrincastReportTestCase {


protected String getReportName() {
return "productosReport3";
}
protected String getInputDir() {
return "extras/sampleapp/src/reports";
}
/**
* Prueba la generacin de un informe sencillo
* @throws Exception
*/
public void testReportGen() throws Exception {
//Obtener origen de datos
List data = new LinkedList();
data.add(new ProductoVO(1, "fooName1", "fooDescr1", 1.0, "url1"));
data.add(new ProductoVO(2, "fooName2", "fooDescr2", 2.0, "url2"));
data.add(new ProductoVO(3, "fooName3", "fooDescr3", 3.0, "url3"));
//Obtener parametros
HashMap parameters = new HashMap();
parameters.put("P_Titulo", "Titulo Fooo");
parameters.put("P_AmpliacionTitulo", "Ampliacion Titulo Fooo");
generatePDFReport(data, parameters);
}
}
El cdigo superior se puede encontrar en la aplicacin de ejemplo SampleApp.

Ms informacin sobre la implementacin de pruebas


unitarias
Dado que los diferentes tipos de pruebas unitarias que se han presentado con anterioridad estn basados
en proyectos de terceros, la mejor forma de conseguir informacin detallada de los mismos es acudiendo
a los sitios web de estos.
Por ello, a continuacin se presentan los enlaces a las guas de desarrollo de cada uno de los proyectos:

115

Pruebas

Proyecto JUnit [http://junit.sourceforge.net/]


Proyecto StrutsTestCase [http://jtestcase.sourceforge.net/]
Proyecto DbUnit [http://dbunit.sourceforge.net/howto.html]
Cactus [http://jakarta.apache.org/cactus]

Pruebas de Rendimiento
Las pruebas de rendimiento de aplicaciones web, se deben realizar, de forma automatizada, utilizando
herramientas inyectoras de carga. La herramienta recomendada para aplicaciones desarrolladas con el
openFWPA es OpenSta[22].

Modo de Prueba de Rendimiento


La herramienta OpenSta no soporta la automatizacin de tests sobre el protocolo https. Es ncesario que toda
la aplicacin corra sobre http. Debido a que el protocolo utilizado (http/https) es ajeno a la programacin de
la aplicacin (en realidad, su uso est gestionado por el framework), para realizar pruebas de rendimiento,
basta con poner el parmetro de configuracin PERFORMANCE.TEST.MODE al valor ON. Este parmetro
se puede definir en cualquier plug-in de configuracin que sirva parmetros al contexto de seguridad:
SECURITY.

116

También podría gustarte