Integración de Spring Web Flow 2 con JSF2

Integración de Spring Web Flow 2 con JSF2.


0. Índice de contenidos.


1. Introducción

JSF es el estándar de JEE para la creación de interfaces de usuario basadas en componentes visuales y Spring Web Flow es una extensión de Spring basada en el patrón ApplicationController para gestionar el flujo de navegación entre pantallas y mantener el estado de los objetos que participan en las mismas a modo de “conversación”, un ámbito superior al de petición e inferior al de sesión. El ejemplo típico de conversación es el ámbito de los pasos de un carrito de la compra, un registro de usuarios o el proceso desde que seleccionamos un destino vacacional hasta que hacemos efectivo el pago del paquete en el que pueden verse implicados varios productos: hotel, vuelo, coche de alquiler,.. .

JSF también tiene su propia gestión de navegabilidad pudiendo realizarla de forma declarativa a través de XML o por convención de nomenclatura directamente en el resultado de las acciones. Si bien, antes de la versión 2 de JSF, la única manera de mantener un estado conversacional era usando el framework Jboss Seam, integrando la gestión de navegación con Spring Web Flow o ADF Tasks Flows.

Ahora, en la versión 2 de JSF, ya disponemos de un ámbito flash que, más que un ámbito, es un saco en el que ir metiendo objetos y mantenerlos de una vista a otra y, en la versión 2.2 de JSF, se introduce el concepto de Faces Flow, que introduce un ámbito de flujo de navegación (@FlowScoped), pero no estará disponible hasta Marzo de 2013.

Si no podemos esperar ;), o ya conocemos Spring Web Flow, en este tutorial vamos a ver cómo integrarlo con JSF2.

JSF proporciona puntos de extensión que permiten, en este caso, a Spring Web Flow tomar el control sobre el manejo de las reglas de navegación y manejar el estado asociado con las interacciones de usuario, esto es, las conversaciones. De este modo, con Spring Web Flow podemos:

  • implementar reglas de navegación dinánicas que puede modificarse en caliente sin necesidad de reiniciar el servidor,
  • configurar forwards, refresh, redirect y navegación recursiva en el lenguaje de definición de flujos, rompiendo con el forward en el que se centra JSF y
  • enapsular y modularizar la lógica de navegación a través del concepto de flujo.

Spring Web Flow introduce 3 ámbitos de conversación que amplian los básicos de JSF (application, session y request):

  • conversación: es el ámbito de duración de un diálogo con el usuario,
  • flow: es el ámbito de duración de un flujo dentro de una conversación, y
  • flash: es el ámbito de duración de una vista dentro de un flujo; vendría a ser el ámbito de vista (@ViewScope) nuevo en JSF2.

Se dice que estos ámbitos son manejados porque la limpieza de los objetos implicados es automáticamente gestionada por el contexto y ahí está la gracia, en poder mantener el estado de los objetos entre distintas vistas de navegación sin necesidad de usar la sesión y que sean manejados automáticamente por el contexto de Spring Web Flow.

En este tutorial vamos a analizar cómo realizar la integración de estos dos frameworks a través de un ejemplo de uso muy simple, intentado emular el escenario que proponíamos en el tutorial sobre JS2 Flash Scope.


2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.4 GHz Intel Core i7, 8GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS X Lion 10.7.4
  • Spring 3.1.1.RELEASE
  • JSF2, Mojarra Impl. 2.1.12
  • Spring Web Flow 2.3

3. Configuración.

Lo primero, como siempre, haciendo uso de maven, es declarar las dependencias de nuestro proyecto:

Spring Web Flow se integra con JSF, entre otros, a través de tres puntos de extensión:

  • un listener propio del ciclo de vida de JSF, que permite manejar la ejecución de nuevos flujos cuando se invoca una petición por un cliente y que restaura el flujo de ejecución existente cuando se restaura la vista de JSF,
  • un VariableResolver propio que hace trasparente que las referencias a los managedBean sean manejadas por el contexto de Spring Web Flow, y
  • un NavigationHandler propio que permite invocar al comportamiento adecuado y asignar la siguiente vista conforme a la definición de los flujos de navegación.

Con todo ello, seguimos teniendo todas las ventajas de trabajar con los componentes nativos de JSF porque la integración es transparente y, además, disponemos del modelo de flujo de navegación que proporciona Spring Web Flow.

Para configurar Spring Web Flow con JSF2 no es necesario declarar nada a nivel de JSF puesto que, al incluir las dependencias de la librería spring-faces, esta incorpora su propio faces-config.xml que se carga automáticamente con la configuración necesaria para JSF.

Lo que sí es necesario es configurar a nivel de aplicación web (web.xml) ambos servlets: el punto de entrada de JSF2 y el de Spring MVC, que sirve de enlace a Spring Web Flow. Si toda la aplicación va a estar gestionada por Spring Web Flow no haremos uso directo del servlet de JSF, solo nos servirá para levantar el contexto.

Para cargar la configuración de Spring Web Flow dentro del fichero applicationContext-flow.xml que levanta en contexto de Spring MVC, debemos incluir la siguiente configuración:

Con esta configuración podemos ubicar los ficheros xml, con el sujifo -flow, con los flujos bajo el directorio WEB-INF/flows/… y, con development=true podemos incorporar o modificar la configuración de los flujos en caliente.


4. Flujo de navegación.

Como comentábamos al principio el ejemplo de uso será muy simple, este es solo un tutorial de integración y se basa en cubrir un escenario con tres vistas que manejen un mismo objeto cuyo estado se mantenga estable entre las mismas, para ello, lo primero es definir el contenido de nuestro flujo de navegación, un fichero registration-flow.xml ubicado en WEB-INF/flows/:

A diferencia del ejemplo que vimos con el ámbito de Flash propio de JSF2, quien crea el objeto y lo mantiene vivo durante el flujo de navegación es Spring Web Flow, declarado mediante la variable <var name=”usuario”…

Las vistas, por defecto, se ubican en el mismo directorio y por convención tienen el mismo nombre que las acciones (to):

El contenido de las vistas es el siguiente:

step1.xhtml

step2.xhtml

confirmation.xhtml

Los managedBeans de JSF tienen el siguiente código:

FlowRegistrationStep1.java

FlowRegistrationStep2.java

Lo que cambia en los ManagedBeans es como obtienen la referencia del objeto; la obtienen por injección de dependencias puesto que se encuentra en el ámbito de los mismos y el contexto de JSF es capaz de encontrar un objeto dentro del contexto de Spring, porque ambos están integrados, mediante la siguiente configuración en el fichero faces-config.xml:

Para arrancar el flujo de navegación debemos invocar a la siguiente url http://localhost:8080/context-web/application/registration-flow gestionada por Spring MVC; mediante las reglas de navegación cargará la primera vista generada por el ciclo de vida de JSF:

tras pulsar sobre siguiente se generará un evento de JSF que gestionará Spring Web Flow en vez de la gestión de navegación propia de JSF para redirigir al siguiente paso del flujo, las fases previas del ciclo de vida de JSF se ejecutan como una petición normal.

Del mismo modo entrará en juego la definición del flujo para navegar hacía el siguiente paso o volver atrás en el flujo; en caso de continuar se mostrará la última vista.

El ámbito del objeto del modelo se ha destruido en esta última vista, si recargamos la página nos redirecciona a la primera vista del flujo, si intentamos recuperar un id de conversación anterior nos redirecciona a la primera vista y no podemos acceder a un paso intermedio cuando la instancia del flujo, esto es, la conversación ha terminado.

Este es un punto cualitativo que diferencia este ejemplo del de Flash Scope de JSF2, en el que todos esos controles corren de nuestra cuenta.


6. Referencias.


7. Conclusiones.

Ahora solo queda abrir el abanico de posibilidades que nos proporciona Spring Web Flow:

  • integración del filtro de seguridad,
  • gestión de transacciones unida al flujo de navegación, o
  • explorar los listeners para marcar una estrategia de auditoria del uso de flujos por nuestros usuarios.

Un saludo.

Jose

jmsanchez@autentia.com