viernes, 1 de marzo de 2013

Integración de Apache Tapestry con RESTEasy

RESTEasy
Ahora que hemos visto en artículos anteriores como son los servicios web REST, como realizar uno empleando la librería RESTeasy, como crear un cliente para consumirlo desde el lenguaje de programación java o mediante javascript desde un navegador web y como devolver datos en formato json, xml u otro se nos plantean algunas ideas de como definir la arquitectura de una aplicación.
Apache Tapestry 5

Las aplicaciones web normalmente se organizan en tres capas, la del cliente, la que contiene la lógica de negocio y la capa de base de datos. La capa del cliente está formada por el navegador, la de negocio donde se emplea algún framework y variará según lenguaje de programación que empleemos e incluye a menudo la responsabilidad de presentación transformando los datos de la capa de base de datos en html para el cliente. La capa de base de datos contiene los datos que trata la aplicación ya sea en forma relacional o no relacionan (no-sql).

En algunas aplicaciones es requisito ofrecer una interfaz de la aplicación para que otras aplicaciones se integren con ella, aqui es donde surgen los servicios web y se nos platea la posibilidad de extraer de la capa donde esta la lógica de negocio a una entidad independiente o integrar los servicios web como una parte más de la aplicación web.

En los ejemplos que hemos visto hasta ahora estos los he puesto como una entidad independiente, es decir, que solo ofrece los servicios web. Esta forma tiene la ventaja de que las partes de la aplicación son independientes pero tiene la desventaja de que la complejidad de la aplicación aumenta ya que los servicios web necesitarán de funcionalidades como acceder a la base de datos, inyección de dependencias o de la recarga automática de clases para ver las modificaciones en caliente mientras estamos desarrollando. Todas estas funcionalidades es probable que tengamos ya en la capa de lógica de negocio, con lo que podríamos ponerlo todo junto y aprovecharnos de las funcionadades que ya tenemos en vez de proporcionalas de nuevo en otra entidad independiente. Sin embargo, para tenerlo todo junto deberemos integrar el framework que usermos con la librería o framework que usemos para la aplicación web. En el siguiente ejemplo veremos como hacerlo para el caso de RESTEasy como librería que proporciona la funcionalidad de servicios web y Apache Tapestry como framework para la aplicación web desarrollada en Java.

En Tapestry ya hay una librería desarollada que permite integrarse con RESTEasy, sin embargo, por lo que he visto en su código fuente no permite obtener el cliente javascript como explique en el segundo ejemplo de esta serie de entradas sobre RESTEasy. Con lo que partiendo de su código fuente lo he modificado para que si se permita obtenerlo.

La parte importante de esta integración está en las clases que definene el módulo de la aplicación (AppModule.java) y el filtro de RESTEasy (ResteasyRequestFilter.java) que será el que atrape las peticiones REST. El código está comentado con notas explicativas.

Con el código de AppModule.java y ResteasyRequestFilter.java conseguimos la integración de Tapestry con RESTEasy y con ella conseguimos varias características que proporciona el contenedor IoC (Inversion of Control), el mero hecho de definir los servicios REST como servicios de Tapestry obtenemos inyección de dependencias y recarga de clases en vivo («live class reloading») que evitará que durante el desarrollo tengamos que estar constantemente parando y arrancando el servidor de aplicaciones para ver los cambios que hagamos con nuestro editor a la clase del servicio, ambas cosas sin que tengamos que hacer nada más. En cuanto a la inyección de dependencias si nos fijamos en el código de servicio REST HelloWorldResourceImpl vemos que tiene un constructor con una referencia a un objeto de la interfaz ContadorService, sin esta referencia el objeto no puede ser construido. El contenedor de dependencias de Tapestry es capaz de inyectar las dependencias necesarias en el constructor para satisfacer sus necesidades sin que tengamos que darle ninguna indicación, él se encargará de buscar en el registro un servicio que implemente esa interfaz, de construirlo (y de construir las dependencias de este servicio si a su vez las tuviese) y de pasarlo como referencia al constructor, encontrará que la clase ContadorServiceImpl lo implementa ya que así lo hemos indicado en el método AppModule.bind. De esta misma forma en los servicios REST podemos hacer uso de cualquier otro servicio, como pudiera ser el servicio persistencia proporcionado por Hibernate o JPA.

La página que genera el html (Index.tml) para el navegador con varias llamadas al servicio REST (Index.tml) es prácticamente html normal excepto por un ejemplo de como se usa un componente en Tapestry (). La etiqueta script solicita el javascript con el cliente del servicio web.

Y las peticiones que veríamos en el navegador serían:


Puedes ver, descargar y probar el código fuente del ejemplo desde mi repositorio de GitHub.

Referencia:
http://es.wikipedia.org/wiki/Representational_State_Transfer
Código fuente ejemplo Integración de Apache Tapestry con RESTEasy
Documentación sobre Apache Tapestry