Acciones JSF basadas en clases internas de Java

Acciones JSF basadas en clases internas de Java.

  1. Resumen
  2. Introducción
  3. Acciones simples basadas en clases internas
  4. Introducción de captura de excepciones en nuestro ActionMethod
  5. Reescritura del Bean de Login usando la AccionBase con control de excepciones
  6. Añadiendo flexibilidad y acceso a datos al ActionMethod
  7. Conclusión

1. Resumen

En este tutorial aprenderemos a crear nuestros backbeans para Java Server Faces implementando las acciones de los beans como clases internas de Java. Esto nos facilitará tanto la escritura de las mismas como la claridad con la que quedan reflejadas las funciones que se realizan en cada acción.

2. Introducción

Cuando desarrollamos aplicaciones JSF gran parte de la lógica de interfaz y negocio se desarrolla dentro de las acciones de los BackBeans, las clases Java asociadas a la página JSF que está sirviendo la petición actual. Por ejemplo, cuando el usuario pulsa el botón de “Inicio” en la página de inicio de sesión, el controlador de JSF invocará a la acción asociada al botón de inicio de esta página. Dicha acción será normalmente un método del backbean de la página de login.

Un ejemplo de código para la página y el backbean podría ser:

Y su backbean:

En este ejemplo la comprobación de usuario y contraseña es muy simple. Lo normal es que en una acción se mezclen varios tipos defunciones:

  1. Verificación de las precondiciones para la ejecución de la acción.
  2. Validación con lógica de negocio de los datos de entrada. No siempre las validaciones de los datos de entrada son simples (comprobaciones de formato, de tamaños, etc.) En aplicaciones complejas la validación de los datos puede involucrar realizar llamadas a diferentes partes de la lógica de negocio.
  3. Ejecución de lógicas de negocio relativas a la acción.
  4. Comprobaciones de resultados de la lógica de negocio.
  5. Actualización de los datos de la interfaz de usuario y del estado de la sesión de aplicación.
  6. Control de las excepciones y errores, con inclusión de mensajes de error o de confirmación en la página del usuario.
  7. Selección del flujo de salida para esta página.

Todo ello se adereza con las clásicas funciones auxiliares, como pueden ser:

  • Inserción de trazas de información, depuración y error.
  • Comprobaciones de seguridad (credenciales de usuario y otras).
  • Registro de acciones de usuario en tablas de auditoría, etc.

Si aplicamos esto a una acción JSF, el código de la acción realmente se complica. Un ejemplo podría ser el siguiente: imaginemos una pantalla de una aplicación de gestión de un sistema de aprovisionamiento de servidores para un proveedor de Internet.

Si nos fijamos en el código, gran parte del mismo son líneas que vamos a repetir de manera habitual cuando creemos las acciones de nuestra aplicación, para acciones similares a ésta. Sería más interesante poder reescribir este código de manera que fuese más sencillo y fácil de escribir y mantener. A estas alturas seguro que a todos ya se os han ocurrido varias formas de hacerlo…

3. Acciones simples basadas en clases internas

Bien, voy a proponer una forma sencilla de crear nuestras acciones utilizando las clases internas de Java. Las clases internas de Java nos dan algunas ventajas que nos van a venir bien a la hora de crear métodos para las acciones: Una clase interna siempre se crea dentro del contexto de una instancia de la clase contenedora, por lo que tiene acceso a los atributos privados de la instancia de la clase contenedora.

  • Podemos crear una instancia de nuestra clase interna dentro de un método de la clase contenedora.
  • Si la clase interna no tiene atributos el coste en demora para crear dicha instancia es pequeño.
  • Normalmente vamos a trabajar sobre los métodos de la clase interna y los datos estarán en la instancia de la clase contenedora, por lo que el uso de memoria será pequeño.
  • Además las clases internas se pueden tomar como clase base para nuevas clases internas en las clases derivadas de la clase contenedora.

Pongamos un ejemplo sencillo para ilustrar esta técnica:

Veamos cómo podría quedar una acción de un bean de login implementada con esta clase:

Como vemos la acción del bean de login sólo tiene código necesario para la lógica de negocio, careciendo de código adicional para la gestión de las excepciones o para la emisión de trazas.

Cuando se ejecuta el método de login de este bean dentro del contexto de una petición JSF, se crea una instancia de la clase interna ActionLogin dentro del método login() del bean, y esta es la responsable de gestionar tanto las excepciones como el resultado devuelto por la acción para los casos en los que hay problemas. Además la acción de login se está apoyando en los métodos definidos dentro de la clase base, por lo que los métodos de utilidad comunes quedan agrupados en la clase base.

En nuestro ejemplo hemos definido el método executeAction() como abstracto. Esto obligará a implementarlo cada vez que creemos una nueva acción dentro del bean

4. Introducción de captura de excepciones en nuestro ActionMethod

Vamos a dar un paso adicional en nuestra definición del ActionMethod. Para ello le vamos a añadir un cierto control sobre las excepciones que se generan. Ahora el método executeAction() que hay que sobrescribir en nuestras acciones puede lanzar excepciones de tipo ActionException.

Como vemos ahora durante la ejecución de nuestra acción se pueden lanzar excepciones que provocarán la navegación hacia la página de error definida en nuestro flujo de navegación. Es muy habitual que al escribir las acciones comencemos comprobando las precondiciones y realizando las validaciones oportunas para cada acción. En nuestro ejemplo de LoadServerBackbean teníamos perlas de código de tipo:

En nuestro bean de login vamos a tener también probablemente validaciones de tipo similar, por ejemplo validaciones de tamaños de nombres de usuario o contraseña y otras precondiciones. Ya sé que JSF proporciona mecanismos de validaciones sencillos, pero introducir las validaciones dentro de la acción le da robustez y nos dará más flexibilidad.

Vamos a añadir a nuestro ActionBase algunos métodos auxiliares del tipo que muestro en este ejemplo:

Nota: dejo el código de inserción de mensajes en el contexto JSF para otro artículo, aunque es sencillo.

Como vemos, ahora se pueden escribir validaciones muy simples llamando a métodos como validateEmptyField(String field, String fieldKey). Extos métodos simplemente comprueban las precondiciones de la acción y si no se cumplen, disparan una excepción, por lo que se provocará la navegación a la página de error.

Hemos creado:

  • Una clase interna SimpleActionMethod que nos serviraá como base para implemntar nuestros métodos de acción como clases internas del bean.
  • Una serie de métodos auxiliares que permitirán reescribir las funciones más comunes de la lógica de interfaz o de negocio, como pueden ser las validaciones, las trazas, la inserción de mensajes en la respuesta JSF.

5. Reescritura del Bean de Login usando la AccionBase con control de excepciones

Ahora vamos a crear un bean de ejemplo que utiliza esta clase base:

Examinemos el código:

  • Tenemos una clase interna y privada LoginAction que implementa la lógica de login para este bean.
  • Tenemos un método de acción público loginAction() que ejecuta la acción.

Las ventajas de esta forma de reescribir la lógica de interfaz y de negocio son evidentes:

  • Nuestra clase LoginAction está libre de código accesorio. Su escritura es simple, muy fácil de leer y de mantener.
  • Hemos usado un patrón de tipo “Salto de vallas” para nuestra acción, es decir, la acción se va ejecutando linealmente, evitando bifurcaciones, y si todas las etapas (obstáculos) de la acción se cumplen se retorna el “OK”. Por cierto, aquel que utilice pruebas unitarias para probar sus clases entenderá las ventajas de usar este patrón, ya que la cobertura completa de los test es más fácil de lograr, debido a la ausencia de bifurcaciones.
  • Cualquier condición no cumplida o problema que aparezca durante la ejecución se resolverá lanzando una excepción de tipo ActionException, que será capturada por la clase SimpleActionMethod, controlando la correcta finalización de la acción.

6. Añadiendo flexibilidad y acceso a datos al ActionMethod

A continuación voy a poner como ejemplo una clase de ejemplo un poco más compleja, que añade nuevas características para hacerla extensible. Dejo al lector el estudio de la misma y el pensar cómo podría reescribir nuestro problema inicial (el aprovisionamiento de un serviodr) utilizando estas clases como punto de partida. Introducimos el siguiente código dentro de nuestra clase ActionBase:

Para rizar el rizo, vamos a crear un ActionMethod interno que se encargue de la conexión a base de datos, para crear acciones que realizan consultas a base de datos de forma sencilla: más o menos podría quedar así:

Esto es una aproximación a un código real. Seguro que a todos se nos ocurre cómo mejorar este código o adaptarlo a nuestros proyectos actuales.

Dejo para el lector la tarea de adaptar los beans de ejemplo utilzando nuestro ActionBase mejorado.

7. Conclusión

En este artículo hemos aprendido una forma sencilla de escribir nuestras acciones JSF de manera que toda la funcionalidad accesoria de la acción quede encapsulada en una clase interna Java. Con ello conseguimos:

  • Una gestión uniforme de la ejecución de las acciones JSF.
  • Mayor claridad en el código de las acciones JSF, que simplifica su creación y mantenimiento.

Nos veremos pronto en esta página con otros tutoriales.