viernes, 14 de junio de 2013

Mantenimiento CRUD en Apache Tapestry

Apache Tapestry
El scaffolding es una ayuda que permite a partir de una descripción disponer de una funcionalidad sin escribir una línea de código o muy pocas exceptuando las necesarias para la descripción. En funcionalidades que se repiten mucho en una aplicación, no aportan mucho valor y son aburridas de programar puede llegar ahorrar una cantidad considerable de tiempo y disponer de un prototipo funcional muy rápidamente. Es utilizada por varios frameworks web en diferentes lenguajes para hacer los mantenimientos CRUD (Create, Read, Update, Delete) de las tablas de una base de datos relacional:
  • Ruby on Rails
  • Symfony
  • Grails
  • Y quizá algunos otros menos conocidos
El problema de los scaffoldings viene cuando la funcionalidad que proporcionan no es suficiente, no se adapta a lo que necesitamos o no nos gusta lo que se genera y nos vemos en la obligación de personalizarlo, los scaffolding son tan básicos que si tenemos una aplicación un poco compleja probablemente deberemos adaptarlos. En ese caso no nos quedará más remedio que programar lo que necesitemos. Algunos frameworks permiten generar un código inicial a partir del que comenzar la programación. Esto es el caso de Grails y el código generado deja bastante que desear (en mi humilde opinión), el CRUD de una tabla tiene cinco gsp, entre ellas una para el alta y otra para la modificación que son prácticamente iguales con lo que contiene bastante código repetido también en el controlador para las acciones save y update que para luego mantenerlo supone problemas. Una vez que el código está generado y lo hemos personalizado con alguna modificación al salir una nueva versión del framework (y tarde o temprano saldrá) tendremos la duda de si el código que se nos generó con una versión anterior se ha quedado obsoleto en la nueva versión, dudaremos si partir del código inicial que genera la nueva versión e incorporar las cambios que hicimos o si adaptamos el código que tenemos con los nuevos cambios.

Como resultado al final disponer de un framework que tenga scaffolding con el tiempo puede no suponer tanto ahorro de tiempo como puede parecer en un principio. Tapestry no proporciona un scaffolding para hacer estos CRUD aunque si proporciona varios componentes avanzados que ayudan mucho a realizarlos (Grid, BeanEditor). A continuación pondré un ejemplo de una funcionalidad similar a un CRUD realizada con el framework Apache Tapestry. En el ejemplo se podrá mantener una tabla de una base de datos pudiendo dar de alta una nuevos registros, eliminarlos, modificarlos y ver sus datos en una tabla con paginación Ajax. En el se verá que todo esto no supone más de 200 líneas de código Java y 80 líneas de código de presentación en tml. Necesitará solo dos archivos, uno para código Java, otro para el de presentación tml e increiblemente ninguno para código Javascript a pesar de hacer la paginación via Ajax. En estos números no estoy incluyendo varias clases de apoyo como la entidad a persistir o su DAO (Data Access Object) ya que no son propios de un único scaffolding sino que se podría utilizar para todos los que tengamos en la aplicación.

En la entrada sobre persistencia JPA usando Tapestry ya expliqué como construir el servicio y la transaccionalidad. En el siguiente código utilizaré ese servicio DAO para el acceso a la base de datos, no cambia nada. Me centraré en poner el código necesario para la página que necesita proporcionar la funcionalidad del scaffolding.

A continuación el código Java en la que principalmente Tapestry se encarga de llamar al método que actúa de escuchador para cada evento que se produzca en la página, en función del evento se llamará a la operación DAO adecuada y actualizar el estado del controlador.

Ahora el archivo tml que se encarga de generar el html que se enviará al navegador. En el mismo archivo está el código para mostrar el listado y para realizar la edición tanto en el alta como en la modificación. En función del estado de la página se mostrará uno u otro haciendo uso del componente Delegate. Para ver la paginación en funcionamiento sin necesidad de crear muchos objetos solo será necesario crear dos, esto es, las páginas solo contendrán dos elementos.

Eso es todo lo propio que necesita el scaffolding y sería lo único necesario para realizar otros similares. Sin embargo, este hace uso de unas cuantas clases de utilidad. Entre ellas la clase que proporciona la funcionalidad de paginación al acceder a la lista de entidades. A partir de los datos de paginación que el data source indica (elemento de inicio, de fin y orden) se construye el objeto que contendrá esta información y se le enviará al DAO para que haga la consulta adecuada.

Finalmente, como comenté un una entrada anterior sobre seguridad sobre XSS (Cross Site Scripting) el mantenimiento está protegido ante este tipo de ataques (puedes probar crear un producto con <script>alert(1);</script>), para ello no hemos hecho nada especial.

Y otro par de clases muy sencillitas que continenen los datos para que el DAO sepa como se quiere la ordenación y que elementos paginados se quieren.

El resultado de la lista, la modificación de un producto y el alta habiendo errores de validación es este:


Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada previamente (salvo java y git). Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace.


Referencia:
Documentación sobre Apache Tapestry