You are on page 1of 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 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

5.

6.

7.

8.

9.

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 ....................................................................... 112 113 114 115 116 116

vi

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

Entorno de desarrollo

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. 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. 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. Las aplicaciones han de ser operadas en los distintos entornos, de manera que el personal de operaciones pueda mantener la

Sistema de tiempo de ejecucin

Seguridad

Operacin

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

Soporte

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. para la automatizacin de las operaciones de compilacin, construccin y despliegue de proyectos. Conjunto herramientas libreras Java. Servidor aplicaciones Oracle. de y de de

Tabla 1.1. Componentes necesarios para la ejecucin del openFWPA Apache Ant ASF 1.6.1 Herramienta

Java SDK

Sun Microsystems

1.3.1_11 - 1.4.x

Oracle AS9i

Oracle

oc4.jar admin.jar

9.0.3.0.0 - 10.1.2

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). Sistema de Gestin de Bases de Datos. Herramienta para la generacin de informes en diferentes formatos: PDF, HTML, XLS, CSV y XML. Proporciona soporte para la conexin bajo protocolo SSL. Proporciona soporte para autentificacin y autorizacin. Proporciona soporte para uso de protocolos de encriptacin. Extensiones JDBC para la compilacin con versin 1.3.1_11 de la JDK. Framework IoC. Librera de monitorizacin y medicin de tiempos Librera de AJAX

Base de Oraclae

Datos Oracle sourceforge.net jasperreports.jar

8.1.7.3 0.6.0

Jasper Reports

JSSE

Sun Microsystems jsse.jar

1.0.3_03

JAAS

Sun Microsystems jaas.jar

1.0

JCE

Sun Microsystems jce.jar 1.2.2 local_policy.jar sunjce_provider.jar US_export_policy.jar Sun Microsystems jdbc2_0-stdext.jar 2.0

JDBC

Spring Java Monitor API

Spring Framework spring.jar JAMon API JAMon.jar

1.2.6 1.1.2

Direct Web Get Ahead Remoting (DWR)

dwr.jar

1.0

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 Capa de Acceso a Datos Descripcin Patrones relevantes

Encapsula toda la lgica de acceso Data Access Object Proxy Value a datos. Asimismo, encapsula los Object Absctract Factory accesos a sistemas remotos. Representa las entidades del Value Object modelo, como objetos JavaBean y sin lgica 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. Transforma eventos en la vista a MVC Command eventos en el modelo, y viceversa. Presenta el modelo al usuario, MVC y comunica sus acciones al controlador 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. Gestiona pools de conexiones, a fin de no crear una conexin por cliente a Base de Datos u otros repositorios. Gestiona la sesin de los clientes, de manera que desconecta a los inactivos. Representa cualquier sistema a integrar a travs de un interfaz bien definido.

Capa de Objetos de Datos

Capa de Negocio

Capa de Controlador Capa de Vista

Filtro web

Datasource

Gestin de sesin

Sistema externo

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 Vista (Presentacin) Se trata de las entidades del dominio del problema, implementadas con total independencia de su 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 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.

Controlador

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) 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. hoja de estilos para el estilo de los componentes de las etiquetas de princast para las pginas hoja de estilos para el tabbed menu. hoja de estilos exclusiva para el aspecto de las tablas generadas por el tag displaytag (Ver ???). El displaytag genera listas paginadas. Hoja de estilo para la ubicacin y formato de componentes especficos de la aplicacin de ejemplo.

position.css

princast-ui.css

tabs.css displaytag.css

carrito.css

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. Implementa la lgica de negocio de la PrincastAction. ste ser el mtodo sobrescrito de forma obligatoria por todas las acciones que hereden de PrincastAction. 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.

executeActionLogic ()

catchException()

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

findFailure()

findAlert()

findSuccess()

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() findFailure() Redirecciona a un forward etiquetado success. 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. Redirecciona a un forward etiquetado warning.

findAlert()

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) del almacn el parmetro especificado. Borra 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. Este mtodo permitir recuperar una entidad. Este mtodo debe obtener listados de entidades. Permite borrar una entidad. Permite actualizar los datos de una entidad. Este mtodo servir para inserter nuevas entidades.

retrieve list delete update create

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;). 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().

locale

29

Arquitectura Modelo -VistaControlador con openFWPA En cuanto a los mtodos: setSessionLocale(Locale) getSessionLocale() setMutable(boolean) isMutable() reset(ActionMapping, HttpServletRequest) Establece el atributo locale. Devuelve el atributo locale. Establece el valor del atributo mutable. Devuelve el valor del atributo mutable. Las subclases que deseen resetear el valor de sus atributos deben comprobar el valor de ste atributo (if (isMutable()) ...)

resetSessionLocale(HttpServletRequest) locale al valor que tenga el objeto locale Cambia el atributo 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() setLocaleDisplay(String) Devuelve el Locale del usuario o el Locale por defecto. Cambia el atributo locale a un cdigo de lenguaje ISO dado. Recibe como atributo un String con el cdigo del pas. Comprueba si el String que se le pasa es null o la cadena vaca. 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. 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.

isBlank(String) describe()

set(PrincastValueObject)

populate(PrincastValueObject) cargar los datos del formulario sobre un Value Object. Este Permite 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) Obtiene un interfaz ejbHome (local) para la creacin de un EJB. Obtiene un interfaz ejbHome (remoto) para la creacin de un EJB. Obtiene una cola de mensajes JMS.

getLocalHome() getRemotelHome() getQueue()

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> 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>] El nombre de este tipo de propiedades se compone como sigue: <nombre de la propiedad>(<clave en el Map>).

Propiedades de tipo List o arrays

Propiedades de tipo 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. Obtiene el path relativo a partir de un path absoluto. A partir de una request, obtiene la URL solicitada completa, incluyendo los parmetros GET.

extractRelativePath() getCompleteURL()

getURLParametersSeparator() partir de una URL, determina si los parmetros que se vayan A 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) resolveToFile(path) Resuelve un path, que se especifica por parmetro, devolviendo el path absoluto. 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. 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.

WebAppPathResolver

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. 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. Provee conjuntos de entidades. Este interfaz devuelve listas de entidades. Se pueden utilizar para listados. 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 se encuentran en el paquete:

ListContentProvider

PaginatedContentProvider

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

XMLProvider

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 Devuelve un Properties con las consultas manejadas por el DAOHelper Devuelve un String con la consulta cuya clave en el fichero de properties se le pasa como parmetro. 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. Devuelve una List de consulta cuya clave en como parmetro. Utiliza le pasan en dos arrays: 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

getQueries()

getQuery(String)

getStament(String, Object [])

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

45

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, equivalente a executeQuery. Es Object[], Object[], DataSource) executeQueryForList(String, equivalente a executeQueryForList. Salvo por el Es 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) reload() Ejecuta la consulta de actualizacin cuya clave en el fichero de properties se le pasa como parmetro.

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. Devuelve una List de PropertyBeans con los pares de la tabla que se cumplen una determinada condicin especificada por parmetro. Devuelve el PropertyBean cuya clave se pasa como parmetro. Inserta en la tabla de la base de datos un nuevo registro con la clave y el valor que se pasan como parmetro. Actualiza en la base de datos el valor de la clave especificada. Elimina todos los pares clave/valor de la tabla. Elimina el par cuya clave se pasa como parmetro.

getProperties(String)

findProperty(String) insertProperty(String, String) updateProperty(String, String) deleteAllProperties() deleteProperty(String)

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) LookupPropertyBean(List beans) Utilizando este constructor, la relacin lookup se realiza sobre los datos almacenados en un Map. 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. y

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

Report compilado

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

reconfigure()

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 FileAppender RollingFileAppender escribe los mensajes de log en la consola escribe los mensajes de log en un fichero escribe los mensajes de log a un fichero al que se le pueden definir polticas de rotacin para que no crezca indefinidamente escribe los mensajes de log en un fichero a que se le puede definir polticas de rotacin basadas en la fecha escribe los mensajes de log hacia un servidor remoto de log enva un correo electrnico con los mensajes de log, generalmente se utiliza para los niveles ERROR y FATAL escribe los mensajes de error a una base de datos escribe los mensajes de error hacia el daemon syslog de los sistemas operativos Unix escribe los mensajes de log en los log del sistema de Windows NT serializa los eventos y los transmite como mensaje JMS de tipo ObjectMessage

DailyRollingFileAppender

SocketAppender SMTPAppender

JDBCAppender SyslogAppender

NTEventLogAppender JMSAppenders

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 PatternLayout

prioridad del mensaje seguida por - y luego del mensaje de log 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) especifica que la salida ser una tabla HTML especifica que la salida ser un fichero XML que cumple con el log4j.dtd consiste en la fecha, thread, categora y NDC, cualquiera de estos cuatro campos puede ser deshabilitado y habilitado individualmente

HTMLLayout XMLLayout TTCCLayout

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 debug nombre del fichero de configuracin. 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). 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. el nombre del fichero de recursos que contendr los mensajes de la aplicacin. especifica si se debe usar un parser validador de XML para procesar el fichero de configuracin. nombre del fichero donde se especifican las definitions de pantallas.

detail

application

validating

definitions-config

<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). 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. El contexto (request o session) que se utiliza para acceder a los beans de formulario.

type

scope

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. 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 de eliminar un atributo en alguno de los mbitos Trata 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.)

PrincastExistsAttributeAction

<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. 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". URL a la que se redirigir en caso de no estar activa la aplicacin para la fecha actual. Este atributo es obligatorio.

DATE.FORMAT

ERROR.URL

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() handleInactive() Determina si la aplicacin est activa. Recibe como parmetro la request. 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. 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. 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".

handleInactive()

configure()

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

JMX.SERVER.ADAPTOR

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 http.PORT https.PORT https/cert.PORT 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. Puerto http que se utiliza para acceder a la aplicacin. Si no se especifica este parmetro, se utilizar el puerto por defecto (80). Puerto https que se utiliza para acceder a la aplicacin. Si no se especifica este parmetro se utilizar el puerto SSL (443) por defecto. 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. 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. 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. 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.

http.IP

https.IP

https/cert.IP

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 no-login Se redirige a login la primera vez que un usuario trata de acceder a un recurso protegido. Esta redireccin se ejecuta cuando no se puede autenticar al usuario por cualquier motivo (por ejemplo, contrasea equivocada) Se redirige a este forward cuando el usuario, que est correctamente autenticado, no tiene autorizacin para acceder al recurso. 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.

no-roles

error

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 className Nombre de la clave bajo la cual se busca la excepcin. 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>

classNam

102

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 Nivel 1 Con este nivel de seguridad no se requiere autenticacin. 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. 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.

Nivel 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. sistema, sin efectuar validacin Establece una conexin con el FrameworkConnectionXMLNoEncoding la DTD. Se recomienda su uso nicamente en entornos con de 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 todo lo que haya en la tabla e inserta los datos del fichero Elimina XML obtenido con el metodo getDataSetXMLFile(). DatabaseOperation.INSERT DatabaseOperation.UPDATE Inserta los datos del fichero XML 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. Esta familia de mtodos es similar a la anterior con la diferencia de que los parmetros se cargan de un fichero de properties. Pre-configura el Sistema de Configuracin con un plug-in. 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.

loadPropertiesFile

loadPlugin configureObject

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 errors va La peticin http que se est utilizando Un conjunto de ActionErros de prueba 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). 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.

getOutputDir()

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://". Gener el PDFProvider correspondiente al informe para ser utilizado en las pruebas. Genera el informe y lo exporta al fichero PDF.

generateReport()

generatePDFReport()

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

You might also like