jueves, 28 de marzo de 2013

Logging en Javascript con log4javascript

log4javascript
En esta serie de artículos que estoy escribiendo sobre varias librerías y herramientas relacionadas con el lenguaje de programación Javascript como RequireJS, Mustache y Backbone en esta ocasión voy a hablar de una librería de logging para javascript que también puede hacernos la vida más sencilla como programadores.

Sistemas de trazas hay muchos para Java y otros muchos lenguajes pero en el entorno de las aplicaciones web estos suelen usarse en la parte del servidor de las aplicaciones. Sin embargo, en el cliente también puede producirse errores y nos puede interesar tener información para averiguar la causa de forma que podamos solucionarlos más rápidamente o simplemente para tener un registro de lo que se ha ido haciendo en este caso en el cliente. Una librería de logging en el cliente también nos puede servir para tener información de errores en el navegador que de otra forma nos pasarían desapercibidos si solo tenemos trazas en el servidor, con la librería de trazas que explicaré en esta entrada podemos enviar las trazas de error al servidor de forma muy sencilla. Además, nos puede servir de utilidad en el momento de desarrollo del código javascript.

Por los motivos anteriores aunque no lo consideremos imprescindible nos puede resultar muy interesante la librería log4javascript. Los conceptos que emplea son muy parecidos a log4j con lo que si programamos en java aprenderemos fácil y rápidamente a usarla, en cualquier otro caso no nos llevará mucho tiempo aprender.

Lo primero que deberemos hacer es descargarla y una vez descomprimido el paquete incluirla en el código html de nuestra página con, haciendo uso de RequireJS:

Posteriormente deberemos usarla definiendo los appenders que determinarán a donde se envían las trazas, a los appenders les asociaremos un layout que determinará el formato de la traza y el nivel mínimo que ha de tener la traza («threshold») para ser emitido. log4javascript proporciona varios appenders según nuestras preferencias o necesidades:
  • AlertAppender: muestra las trazas usando la función alert del navegador.
  • AjaxAppender: realiza una petición ajax al servidor enviando la traza generada en el navegador, con este appender podremos tener el registro de lo que sucede en los clientes. Se ha de indicar el path de la URL que procesará las trazas en el servidor.
  • PopUpAppender: muestra las trazas en una ventana emergente en la que se pueden filtrar las trazas y en la que cada nivel aparece con un color distinto para reconocerlas más fácilmente.
  • InPageAppender: muestra la misma consola del PopUpAppender pero de forma incrustada en el pie de la página.
  • BrowserConsoleAppender: muestra los mensajes en la consola de depuración con los mensajes de javascript que incorporan los navegadores.
Con el siguiente bloque de código inicializamos el sistema de trazas, la variable log4j será la que utilicemos para emitir las trazas. En el ejemplo utilizamos el appender PopUpAppender con un layout que nos mostrará la hora, el nivel de la traza y el mensaje, el threshold del PopUpAppender es INFO con lo que todo mensaje con nivel menor prioridad como TRACE o DEBUG no aparecerán en el appender, para el caso de AjaxAppender el threshold será ERROR de modo que tampoco aparecerán en el las trazas INFO y WARN. Al emitir las trazas indicamos el mensaje más adecuado que consideremos más nos pueda ayudar y con el nivel de trazas según la importancia que tenga el mensaje, este nivel de trazas nos permitirá filtrarlos según su nivel en el popup:

El resultado que obtenemos en la consola emergente es el siguiente, los mensajes de nivel de trace y debug no aparecen por el threshold del appender PopupAppender.


Como los ejemplos de RequireJS y Mustache el código fuente completo lo puedes encontrar en mi repositorio de GitHib.

Referencia:

Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Capturar errores de Javascript

viernes, 22 de marzo de 2013

Introducción y ejemplo de Mustache


Mustache
Como comentaba en la Introducción y ejemplo sobre RequireJS el lado cliente están tomando cada vez más responsabilidad y peso en las aplicaciones. El lado cliente con los navegadores ya no se limitan a mostrar el html que se genera en el servidor de forma dinámica sino que son ellos mismos que obteniendo los datos en formato JSON probablemente mediante un servicio REST se encarga de transformar esos datos en el html que finalmente se ha de mostrar en la página. Generar el html en el cliente en vez de en el servidor tiene las siguientes ventajas:
  • Se reduce la carga del servidor.
  • La cantidad de datos devueltos es menor ya que el tamaño de la plantilla y los datos podrán ser menor que el html final generado por la combinación de ambos si una plantilla puede aplicarse varias veces sobre alguna lista de los datos.
Para transformar esos datos al html mediante una plantilla hay diferentes librerías que proporcionan esa funcionalidad entre ellas Mustache y Handlebars. Mustache es más simple que Hadlebars y Handlebars es un superconjunto de Mustache por lo que si tenemos una plantilla en Mustache podremos utilizarla en Handlebars. En esta entrada comentaré un ejemplo simple y sencillo con las posibilidades de Mustache.

Mustache se caracteriza por su simplicidad evitando incluir lógica en las plantillas, es decir, sin sentencias if y bucles aunque algunas etiquetas proporcionan la misma funcionalidad. El hecho de no incluir lógica en las plantillas hace que estas sean sencillas, fáciles de desarrollar y de mantener además de obligar a no mezclar conceptos lo que hace que el código sea «limpio».

La esencia de Mustache al igual que otros sistemas de plantillas es que por un lado tenemos los datos que forman parte del modelo y por otro lado la plantilla que forma parte de la vista, juntando ambos obtenemos un resultado.

Veamos como se traduce todo esto en código javascript. Lo primero y más sencillo son las variables que en la plantilla se indican entre {{ }}, estos corchetes con forma de mostacho le dan nombre a la librería, la variable es sustituida por el valor proporcionado en el modelo:


Secciones

Otra posibilidad de Mustache con las secciones que se indican con un # delante de la variable. Si la variable de una sección es false, tiene valor null o es un array vacio, esa sección se omite en el resultado. De esta forma una sección puede hacer de lo que en un lenguaje de programación sería una condición.


Secciones lista

En el caso de hacer una sección en el que la variable sea una array o lista, la sección recorrerá cada uno de los elementos de la lista y generará un contenido por cada elemento. Esto nos proporciona la funcionalidad de un bucle.


Parciales

Si no queremos tener una plantilla muy grande o queremos rehusar cierta parte en varias plantillas la podemos dividir usando parciales. Los parciales se indican con el caracter > y son una forma de llamar a un trozo de una plantilla. En la plantilla los parciales son sustituidos por su correspondiente código del mapa de parciales y la plantilla se procesa como si fuese una completa. Este es el mismo ejemplo de la sección lista pero usando parciales:


Compilación

Para una mayor eficiencia sobre todo en dispositivos móviles las plantillas pueden compilarse con:


Esto es lo básico de Mustache, tiene alguna posibilidad más como las funciones donde se puede añadir algo de lógica, también están las secciones invertidas que se indican con ^ y generan resultado si la variable de la sección es null, false o vacía, es decir, lo contrario de una sección normal. Por defecto los caracteres html de una variable son escapados pero puede evitarse con tres llaves {{{ }}} o un & antes del nombre de la variable. También puede cambiarse el delimitador de Muchache, los {{ }}, por otra cadena pero será poco habitual que lo necesitemos.

La otra alternativa que comentaba es Handlebars con la que si tenemos una plantilla de Mustache podemos utilizarla en Handlebars sin ningún cambio ya que Handlebars soporta todas las características de Mustache y añade algunas otras. Las principales diferencias entre Mustache y Handlebars es que Mustache puede ser usada desde diferentes lenguajes como Java, Python, Ruby, D, .NET, PHP, y alguno más que puede verse en la página del proyecto, Handlebars solo se puede utilizar usando javascript. Dado que Mustache puede ser utilizado con Java puede ser una alternativa a librerías como FreeMarker de esta manera podemos hacer uso de la misma librería de plantillas tanto en el servidor como en el cliente de forma que evitemos tener que aprender y conocer varias tecnologías que hacen lo mismo y aprovechemos mejor lo que conocemos. Otra diferencia es que Handlebars añade el concepto de funciones de ayuda («helpers») mediante los cuales se puede añadir lógica si nos es necesario y aunque puede facilitarnos ciertas tareas no conviene abusar de ello ya que puede hacer que las plantillas dejen de ser tan simples y empiecen a no ser fáciles de mantener.

El código fuente completo de este ejemplo los puedes encontrar en mi repositorio de GitHub.

Referencia:

Introducción y ejemplo de RequireJS
Logging en Javascript con log4javascript
Capturar errores de Javascript

viernes, 15 de marzo de 2013

Introducción y ejemplo de RequireJS

RequireJS
Las páginas web ha evolucionado mucho desde sus inicios en los que eran simples páginas estáticas hechas con el lenguaje de marcas html, podían contener enlaces e imágenes. Posteriormente adquirieron capacidad de cambiar a través un lenguaje de programación que en el servidor genera el código html de forma dinámica basándose en la información que el usuario podía enviar en un formulario, también se incorpora cierta programación en el cliente con javascript. Con las nuevas versiones del estándar html, los avances de los navegadores y una explosión de dispositivos móviles de gran capacidad las aplicaciones están evolucionando hacia el cliente, haciéndose cada vez más complejas en el lado del navegador del usuario y adquiriendo resposabilidades que antes tenía la aplicación en el lado del servidor. Cada vez hay más librerías y frameworks javascript que tratan de resolver problemas específicos de las aplicaciones de internet. Entre estas librerías algunas de las más conocidas son, muy resumidamente:
  • jQuery: para manejar los elementos de la página.
  • mustache: a partir de una plantilla y unos datos genera un resultado.
  • underscore: proporciona ciertas utilidades bastante comunes que el lenguaje javascript no proporciona.
  • Backbone: da un modelo MVC para el desarollo de las aplicaciones.
Por supuesto, para cada área hay varias opciones entre las que se puede elegir, estas no son las únicas librerías hay muchas más alternativas (hadlebars, prototype, agularjs, mootools, ...) que en esencia proporcionan la misma funcionalidad que las anteriores. A medida que vamos haciendo uso de más librerías, archivos javascript y que estas pueden tener dependencias unas sobre otras se hace necesario algo que permita gestionar esas relaciones entre las librerías para que el código javascript se cargue en el orden adecuado y funcione correctamente. Aquí surge RequireJS, que además de gestionar esas dependencias también nos proporciona otras ventajas:
  • La carga de los archivos javascript se hace de forma asíncrona evitando el resto del contenido de la página se bloque hasta que los js de la página se carguen.
  • Permitirnos optimizar los archivos javascript juntándolos en uno solo de forma que sean necesarias menos peticiones al servidor y a la vez minificándolos para hacer que ocupen menos y la transferencia sea más rápida.
  • Se evita contaminar el ámbito global de javascript evitando posibles conflictos entre archivos javascript.
Algunas de estas ventajas hacen que la página cargue más rápido que es algo que el buscador de Google tiene muy en cuenta para el posicionamiento en los resultados de búsqueda.

Con RequireJS los archivos javascript se organizan en módulos y estos pueden tener dependencias sobre otros, todos los archivos javascript necesarios son cargados por RequireJS de forma asíncrona. Haciendo uso de RequireJS en la página web solo será necesario incluir un único javascript, que será el de RequireJS, en la propia etiqueta script y con el atributo data-main le indicaremos el módulo del que va a hacer uso la página. El resto de módulos se cargarán como dependencias del módulo que especifiquemos en el atributo data-main.

En el módulo inicial que carga la página, main.js, hacemos uso de la función require cuyos parámetros son un array con la lista de dependencias sobre otros módulos y una función que será llamada cuando RequireJS haya cargado todos los módulos indicados en la lista, en este caso solo uno. Por cada dependencia la función que se llama cuando todos los módulos se han cargado recibe un objeto como parámetro, de esta manera RequireJS es como evita contaminar el ámbito global ya que no son necesarias definiciones en el ámbito global.

En el ejemplo del módulo main.js en la función require se indica una dependencia sobre el módulo figuras. El módulo de las figuras contiene la lógica de esta simple aplicación que es calcular el área de un cuadrado y un triángulo y mostrar el resultado en un diálogo emergente. Una vez que todas las dependencias del módulo de la aplicación, en este caso solo una, han sido cargadas por RequireJS se llama a la función callback del módulo de la aplicación con la referencia del módulo de figuras.

El módulo figuras no tiene ninguna dependencia con lo que el array de dependencias no es necesario y solo se indica la función de inicialización del módulo en la función define. Este módulo define los prototipos de dos objetos, un cuadrado y un triángulo, con un método cada una de ellas que permiten calcular su respectiva área. El retorno de la función de inicialización del módulo es importante ya que lo devuelto por esta función es lo que recibirán como referencia los módulos que dependan sobre el módulo de figuras.

El resultado es este:


Las funciones require y define son similares pero si un módulo va a ser usado por otros se ha de usar la función define, sino va a ser usado por otros se puede usar la función require.

En posteriores entradas hablaré y pondré un ejemplo de otros temas relacionados con javascript como mustache, backbone, REST, logging, optimización, ... que nos pueden ayudar mucho a hacer mejores aplicaciones, más complejas, de forma más sencilla, con menos errores y más rápidamente. Este artículo sobre RequireJS solo es el primero en el que se basarán el resto que escribiré sobre javascript.

El código fuente completo de este ejemplo de RequireJS lo puedes encontrar en mi repositorio de GitHub.

Referencia:

Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript

sábado, 9 de marzo de 2013

Skinning de web usando Apache Tapestry

Apache Tapestry
Algunas páginas o aplicaciones web tienen la necesidad de variar su aspecto en función de determinadas variables. La aplicación puede ser la misma pero necesitar cambiar el aspecto o la imagen de marca en función de esas variables. Si los cambios a realizar solo implican cosas visuales como colores, tipos de fuentes y tamaños, imágenes, etc... con cambiar las hojas de estilo de la web puede ser suficiente, pero si es necesario modificar el html que genera la aplicación porque los elementos sean diferentes o estén en diferente posición dentro del html generado necesitaremos incluir lógica en forma de condiciones en las plantillas  que forman parte de la vista del framework que usemos. Si únicamente tenemos una variable incluir lógica en las plantillas puede ser manejable pero si son varias tarde tarde o temprano su mantenimiento será un problema y podremos tener como resultado código spaghetti en el html. Otra alternativa a usar una única plantilla con lógica es tener una plantilla distinta por variable o conjunto de variables si las plantillas generan código html suficientemente diferente de forma que manejar las diferentes plantillas por separado sea más sencillo, a pesar de que probablemente estaremos duplicando código en las diferentes plantillas. Pero para tener diferentes plantillas tendremos que inventar un mecanismo que nos permita seleccionar la plantilla adecuada en función de las variables y las cosas pueden complicarse si se puede dar combinaciones de ellas.

¿Cuales podrían ser las variables por las que una aplicación quisiese cambiar el html generado? Algunas de ellas podrían ser:
  • El nombre del dominio. Si aplicación necesita de diferente imagen de marca en función del nombre de dominio por el que se accede al servidor donde está alojada la aplicación.
  • El tipo de usuario. Aquí podría entrar cualquier información que el usuario nos envía en las peticiones http, desde el lenguaje al país de la dirección IP pero una candidata podría ser el dispositivo utilizado para acceder a la aplicación, si se tratase de un dispositivo móvil podríamos eliminar las cosas suplerfuas para aligerar en peso la página y que se cargase más rápido o para que esté más adaptada a un ambiente táctil de un table o smartphone.
  • Otra podría ser la hora o fecha en la que se accede a la aplicación por ejemplo para adaptar la aplicación a épocas navideñas o ciertos periodos relevantes para la aplicación.
Si tenemos una aplicación con esta problemática deberemos buscar la mejor forma que el framework que usemos nos posibilite. A continuación voy a explicar como conseguirlo usando el framework Apache Tapestry. Usando este framework veremos que añadiendo una pocas cosas podemos resolver el problema de forma simple, sencilla y limpia evitando tener la misma lógica desperdiga por toda la aplicación. Una vez realizada la selección de la plantilla adecuada su uso nos será transparente y nos podremos olvidar de esta funcionalidad y centrarnos únicamente en crear las plantillas.

En Tapestry a las variables se les denomina «axis» o ejes, una de ellas disponible por defecto y especial es el «locale» o idioma del usuario, de esta forma en función del idioma podemos tener una plantilla distinta y completamente diferente del resto, si no existe la más específica se usará la mejor opción al igual que ocurre con los ResourceBundle de Java. Por ejemplo, si el idioma es es_ES puede ocurrir los siguientes casos:
  • Que la plantilla de una página o componente con eje del idioma es_ES exista, si la página es Index, su plantilla es Index_es_ES.tml si existe se selecciona esta.
  • Si la plantilla Index_es_ES.tml no existe se elige la siguiente mejor opción que es Index_es.tml.
  • Si Index_es.tml tampoco existe se selecciona Index.tml que será la más general y opción de último recurso.
En Tapestry el eje del idioma se aplica también a los recursos estáticos como puede ser las imágenes, css, javascripts, etc... en el caso de las imágenes nos puede ser muy útil si estas llevan texto. Los ejes personalizados fueron introducidos en la versión de Tapestry 5.3, aunque ya era posible conseguirlos en versiones anteriores se necesitaba más esfuerzo. Podemos tener tantos ejes como deseemos pero si son muchos las combinaciones y plantillas necesarias pueden crecer en gran medida aunque al igual con el eje del «locale» si la plantilla no existe se seleccionará la de por defecto, por suerte no será necesario que definamos todas las plantillas para todos los posibles casos de combinaciones de ejes solo deberemos crear las plantillas personalizadas que nos interesen. Las combinaciones de los ejes y las plantillas puede observarse en la siguientes figuras.

Quizá todo parezca más complicado de lo que realmente es, la implementación en código de los ejes se traduce básicamente en dos partes:
  • La lógica que determina los ejes a aplicar a una petición.
  • La lógica que en función de los ejes de la petición selecciona la plantilla adecuada.
Una de las grandes características de Tapestry es que las cosas pueden ser redefinidas, extendidas y adaptadas, todo lo que esté definido como un servicio en el contenedor de dependencias puede serlo y esto es mucha de la funcionalidad interna del framework ya que muchas cosas se definen como servicios, solo deberemos implementar la interfaz adecuada en una clase y hacer la contribución en el contenedor de dependencias para que se use.

Veamos la clase que contiene la lógica que determina el eje a aplicar en función del dominio suponiendo que la plantilla a usar sea diferente si se entra a la aplicación por el dominio .com.es o por .net, la interfaz a implementar es ComponentRequestSelectorAnalyzer:


La clase CustomComponentRequestSelectorAnalyzer para determinar si la aplicación cumple un eje necesitará información, en el caso del eje del dominio bastará con la clase HttpServletRequest que podrá ser inyectada por el contenedor IoC de Tapestry en la implementación de la clase, si necesitásemos más información será suficiente con indicar el servicio que la proporciona en el constructor. DominioAxis es un enumerado de utilidad para identificar el dominio. Si el nombre del dominio acaba en com.es o .net devuelve el enum correspondiente:


La segunda parte de los ejes es proporcionada por una clase que implementa la interfaz ComponentResourceLocator y seleccionará la plantilla adecuada en función de los ejes detectados en la petición por la clase CustomComponentRequestSelectorAnalyzer anterior. La parte importante está en el método locateTemplate:


Se obtienen los ejes por los que pueden seleccionar las plantillas, en este caso solo uno pero podrían ser múltiples y combinados de cualquier forma aunque en ese caso la lógica para selecciona la plantilla sería más complicada. Independientemente del número de ejes el resultado final ha de ser el nombre de la plantilla y si existe se usa sino se usa la plantilla que no tiene ningún eje (salvo el locale que se puede aplicar siempre incluso usando ejes personalizados). En el caso concreto del ejemplo la plantilla sigue el formato «[nombre plantilla]_[eje dominio].tml» que en el caso de la página Index podría ser Index_com_es.tml o Index_net.tml. Si la petición no tuviese ningún eje la decisión de seleccionar la plantilla se delegaría en el servicio por defecto de Tapestry.

Una vez codificadas estas clases para que se usen se han de hacer unas pocas contribuciones en el módulo de la aplicación, en concreto lo que necesitamos definir son dos métodos, contributeServiceOverride y decorateComponentResourceLocator. Si los nombres de estos métodos no son suficientemente explicativos diré que contributeServiceOverride hace que se use un servicio en vez de otro, como queremos que se use nuestro CustomComponentRequestSelectorAnalyzer en vez del de por defecto que usa Tapestry lo sobreescribimos, nuestro servicio lo definimos en el método bind. El método decorateComponentResourceLocator aplica el patrón de diseño Decorator sobre otro servicio, si la clase CustomComponentResourceLocator detecta un eje y encuentra la plantilla la selecciona sino siguiendo el patrón decorate delega en la clase que decora.


Y este sería el resultado de acceder por los diferentes dominios:

 

Estas son las plantillas que se usan en cada uno de los casos:
  • En el caso del dominio que acaba en .local se usan las plantillas de la página Index.tml y HolaMundo.tml del componente HolaMundo ya que CustomComponentRequestSelectorAnalyzer no establece el eje del dominio.
  • En el dominio .com.es si se establece el eje de dominio y se buscan las plantillas de este eje, en el caso de la plantilla de la página se Index.tml ya que no existe Index_com_es.html pero en el caso del componente se usa HolaMundo_com_es.tml ya que si existe.
  • En el dominio .net se usa Index_net.tml y HolaMundo_net.tml ya que en ambos casos existen.

El código fuente completo lo puedes encontrar en mi repositorio de GitHub. ¿Quieres saber más sobre Apache Tapestry? Visita Documentación sobre Apache Tapestry.

Referencia:
http://blog.tapestry5.de/index.php/2011/06/24/template-skinning/
Código fuente completo del ejemplo Skinning de plantillas con Apache Tapestry

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