viernes, 14 de mayo de 2010

Hola mundo con Apache Tapestry (4.1)

Apache Tapestry

Voy a presentar brevemente Apache Tapestry, uno de los muchos frameworks que hay disponibles para el desarrollo de aplicaciones web en Java pero que destaca sobre el resto por algunas de sus características. También podréis ver el típico ejemplo Hola Mundo con Tapestry.

Tapestry es un framework con una curva de aprendizaje posiblemente mayor que otros frameworks pero que una vez entendido su funcionamiento se es altamente productivo. Tapestry es un framework que se basa en componentes y la alta productividad es debido a lo fácil que es desarrollar y usar nuevos componentes y a que pueden ser distribuidos para ser reutilizados en los proyectos a través de librerías jar muy fácilmente entre otras cosas.

Los componentes y la forma de distribuirlos es una de las características que destaca sobre otros frameworks. En Tapestry las librerias de componentes incluyen todo lo que necesita el componente para funcionar, desde las propias clases del componente hasta el javascript, imágenes y las hojas de estilo necesarias. Esto hace que la reutilización de las librerías de los componentes en Tapestry sea muy sencilla, basta con copiar una librería a nuestro proyecto. En otros frameworks para conseguir reutilización es necesario conocer que archivos hay que copiar de un proyecto a otro y conocer como funciona internamente la aplicación origen, si al final tenemos varios proyectos y por algún motivo modificamos alguno de esos archivos que hemos copiado lo tendríamos que distribuir en todos los proyectos. Esta forma de reutilización la hace difícil y a la larga puede provocar un problema de mantenibilidad en los proyectos. Tapestry soluciona este problema generando una nueva versión de la librería de componentes y si utilizamos alguna herramienta como Ivy o Maven para obtener las dependencias la distribución de la nueva librería se hace de forma automática en la siguiente construcción de cada proyecto.

Uno de los puntos débiles que se le suele achacar a este framework es que su documentación no es muy abundante, aún así es suficientemente para aprender como realizar las tareas típicas de una aplicación web como son validaciones, IOC, informe de errores, catálogo de componentes (I), (II) y (III), Ajax, localización, integración con Spring e Hibernate, testeo, y otras muchas.

Actualmente hay dos versiones estables de Tapestry la 4.1.x y la 5.1.x que requiere JDK 1.5 o superior (la versión 5.2 está al caer). Para este ejemplo de Hola Mundo he utilizado la versión 4.1.6.

Pero ya basta de teoría vamos a ver que aspecto tiene un componente en Tapestry y como se usan, que casi es lo principal en el desarrollo de una aplicación con Tapestry. Este ejemplo no es representativo de todo lo que se puede hacer ni utiliza la última versión del framework (en Tapestry 5.1 el desarrollo se ha hecho más sencillo incluso) pero puede servir como primer contacto. La aplicación Hola Mundo que acompaña a esta entrada muestra un mensaje de bienvenida, una imagen y un reloj que se va actualizando cada segundo con la hora del sistema.

El componente que imprime un mensaje al que he llamado HolaMundo es muy sencillo, el código se compone del archivo HolaMundo.jwc que contiene la definición del componente (donde declararíamos sus parámetros, variables, objetos a inyectar en la clase java y recursos como imágenes si los tuviese):

<?xml version="1.0" encoding="iso-8859-1"?>

<component-specification class="com.blogspot.elblogdepicodev.tapestry.helloWorld.componente.HolaMundo">
 <description>Componente que muestra un mensaje de bienvenida</description>

</component-specification>

y del archivo HolaMundo.java con el código java del componente (en este caso la generación del html se hace desde la propia clase java, el html también se puede generar mediante plantillas como más adelante veremos en la página Home):

package com.blogspot.elblogdepicodev.tapestry.helloWorld.componente;

import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;

public abstract class HolaMundo extends AbstractComponent {

    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {  
     writer.print("Hola mundo Tapestry !!!");
 }
}

El componente Reloj es un poco más complejo y se compone de los siguientes archivos Reloj.jwc:

<?xml version="1.0" encoding="iso-8859-1"?>

<component-specification class="com.blogspot.elblogdepicodev.tapestry.helloWorld.componente.Reloj">
 <description>Componente que muestra la hora del sistema</description>

    <inject object="Reloj.script" property="script" type="script"></inject>
</component-specification>

Reloj.java:

package com.blogspot.elblogdepicodev.tapestry.helloWorld.componente;

import java.util.HashMap;
import java.util.Map;

import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.IScript;
import org.apache.tapestry.TapestryUtils;

public abstract class Reloj extends AbstractComponent {

    public abstract IScript getScript();
    
    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
        writer.begin(getTemplateTagName());
        renderIdAttribute(writer, cycle);
        renderInformalParameters(writer, cycle);
        writer.end();

        Map symbols = new HashMap();
        symbols.put("c", this);
        getScript().execute(this, cycle, TapestryUtils.getPageRenderSupport(cycle, this), symbols);
    }
}

y Reloj.script (que contiene el javascript necesario para realizar la actualización de la fecha):

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE script PUBLIC "-//Apache Software Foundation//Tapestry Script Specification 3.0//EN" "http://jakarta.apache.org/tapestry/dtd/Script_3_0.dtd">

<!--
Input symbols:
  c: componente Reloj
-->

<script>
 
<include-script resource-path="/com/blogspot/elblogdepicodev/js/prototype-1.6.1.js"/>

<input-symbol key="c" class="org.apache.tapestry.AbstractComponent" required="yes"/>

<body>
<unique>
</unique>
</body>

<initialization>
    new PeriodicalExecuter(function(pe) {
        $('${c.id}').update(new Date().toString());
    }, 1);
</initialization>
</script>

Ahora vayamos a ver la página Home para ver como es el uso de estos componentes, la página Home se compone de los archivos Home.page (la definición de la página):

<?xml version="1.0" encoding="iso-8859-1"?>
 
<!DOCTYPE page-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.1//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_1.dtd">

<page-specification class="org.apache.tapestry.html.BasePage">
 <description>Página inicial de la aplicación</description>
 <asset name="tapestryBanner" path="/imagenes/tapestry-banner.gif"></asset>
</page-specification>

Y la plantilla de la página, Home.html:

<span jwcid="@Shell" title="literal:Hola mundo Tapestry !!!">

<body jwcid="@Body" style="font-family: Verdana; font-size: 10px;">
    <img jwcid="@Image" image="asset:tapestryBanner"/>
    <br/>
    <br/>

    <b><span jwcid="@HolaMundo"/></b>
    <br/>
    <br/>
    <span jwcid="reloj@Reloj"/>
</body>
</span>

Como se puede apreciar el archivo de la plantilla de la página Home.html es muy similar a código html, esta es una de las buenas características de las plantillas html de los componentes, en él algunas etiquetas contienen el atributo especial jwcid. Este atributo contiene el nombre del componente Tapestry que se quiere usar (lo que viene detrás del caracter @, lo que va delante es el identificativo del componente).

Para compilar el ejemplo he utilizado Ant con la siguiente linea de comandos que genera en el directorio build el archivo war de la aplicación que puede ser desplegado en Tomcat o JBoss (seguramente sea necesario modificar la variable de entorno de Ant en los archivos ant.sh o ant.cmd):

Para Linux: $ ./ant.sh resolve package
Para Windows: > ./ant.cmd resolve package

Compilación con Ant

 El resultado utilizando Tomcat es este:

Aplicación HelloWorldTapestry funcionando

Podemos mirar el código HTML generado por Tapestry:

Código fuente html generado

Mostrar todas las posibilidades un framework es imposible en una única entrada por ello os invito a echarle un vistazo a la documentación que hay disponible y he recuperado en esta entrada:

Documentación sobre Apache Tapestry
Código fuente ejemplo Hola Mundo con Apache Tapestry 4.1

¿Cúal es el framework que usas habitualmente para desarrollar? ¿Cúal es que más te gusta?