Está en la página 1de 73

4.

2 Tutorial de Tapestry uto a apest y

ndice

Introduccin Pginas g Ejemplo pojo-tapestrytutorial


Estructura del subsistema Capa modelo Plantillas

Componentes

PageLink, Form, TextField, Label, If g , , , ,

Sintaxis de expansiones y valores de parmetros Catlogos de mensajes Validacin de campos de entrada Propiedades Inyeccin de pginas Manejadores de eventos

Formularios

Clases

Ciclo de vida de las pginas Comunicacin de datos entre pginas

Objetivo

Aprender los fundamentos bsicos de Tapestry 5 para disear e implementar aplicaciones Web utilizando este framework

Introduccin (1)

Proyecto Apache Framework Java open source para la construccin de aplicaciones Web

La primera versin fue concebida por Howard Lewis Ship en el ao 1999 La versin actual, que ser la que nosotros estudiaremos, es la l 5 Puede utilizarse dentro de cualquier servidor de aplicaciones Java EE ligero (solamente necesita soporte para Servlets) Enfoque: Una aplicacin se compone de un conjunto de pginas Web, cada una de las cuales se construye a partir de componentes que pueden generar diversos eventos ante los que la pgina puede reaccionar

Construido sobre la API estndar de Servlets

Orientado a componentes p

Introduccin (2)

Algunas caractersticas

Sigue el enfoque POJO


Convenciones de nombrado Anotaciones

Adems de los componentes proporcionados por el framework permite que el desarrollador construya fcilmente sus propios componentes a medida Contiene componentes para interacciones AJAX Soporte para internacionalizacin Soporte para validacin de datos de entrada Soporte para Inyeccin de Dependencias Integracin con Hibernate

Soporte para implementar aplicaciones Web CRUD directamente con Hibernate (sin Spring) til cuando la lgica de negocio es ms compleja y est implementada con Spring (como es nuestro caso)

Integracin con Spring

Introduccin (y 3)

Desde un punto de vista de alto nivel, una aplicacin Tapestry puede ser vista como un conjunto de pginas interactivas que son gestionadas por el framework

Desde un punto de vista de ms bajo nivel, cuando la aplicacin nivel Web recibe una peticin, utiliza la pgina apropiada para generar la respuesta (normalmente una pgina HTML) y se la g enva al navegador

Ests pginas recuerdan los valores introducidos por el usuario en los campos de entrada Cuando el usuario realiza alguna accin, como por ejemplo un clic g , p j p sobre un enlace o un botn, pueden reaccionar a esa accin ejecutando un mtodo que acta como manejador del evento producido por ese componente

Cuando el usuario realiza alguna accin sobre la pgina HTML recibida (como por ejemplo rellenar un campo de texto y pulsar un botn), entonces esa informacin es enviada de vuelta a la aplicacin Tapestry, a travs de otra peticin Tapestry Dependiendo de la lgica de la aplicacin y de las acciones del usuario, la informacin es pasada a la misma pgina o a otra pgina para procesar la peticin y generar la respuesta adecuada

Pginas (1)

Cada pgina tiene asociada una plantilla y una clase Java


Una plantilla es un documento XML que permite generar

Ambas deben tener el mismo nombre El objetivo de la clase Java es recibir los eventos relativos a la bj ti d l l J ibi l t l ti l pgina y el objetivo de la plantilla es generar el markup de la pgina

markup

En el caso de una aplicacin Web, el markup es normalmente HTML o XHTML, pero tambin podra ser, por ejemplo, XML (y en este lti t ltimo caso, la aplicacin Web actuara como un servicio Web l li i W b t i i W b REST) Tiene extensin .tml (Tapestry Markup Language) El XML incluir referencias a componentes (proporcionados por el framework o desarrollados por el usuario) y tambin puede incluir expansiones (expresiones que permiten insertar valores de propiedades de la clase Java o textos internacionalizados en la plantilla) Cuando Tapestry genera el markup para una pgina, le pide a cada componente que est presente en la plantilla de la pgina que genere el cdigo correspondiente

Pginas (y 2)

Las clases son POJOs

No extienden de ninguna clase ni implementan ninguna interfaz del framework Tienen propiedades para almacenar el estado de la pgina Pueden contener mtodos para implementar la funcionalidad de la pgina

Son invocados cuando se producen determinados eventos en algn componente de la pgina Se utilizan convenciones de nombrado o anotaciones para asociar mtodos a eventos generados por componentes

Cuando se genera el WAR de la aplicacin Web, la clase (fichero .class) y la plantilla (fichero .tml) ( ) p ( ) deben colocarse en el mismo directorio (que vendr determinado por el paquete al que pertenece la pgina) )

pojo-tapestrytutorial

Para el tutorial de Tapestry utilizaremos el mdulo pojo tapestrytutorial pojo-tapestrytutorial de los ejemplos Implementa las capas modelo y Web de la misma mini aplicacin mini-aplicacin bancaria implementada para el tutorial de Servlets y JSPs que, recordemos, tiene los siguientes casos de uso

Crear una cuenta Buscar una cuenta a partir de su identificador

Pgina principal del tutorial

http://localhost:9090/pojo-tapestrytutorial
Tapestry Tutorial Main Page

Clic en Create Account Create Account Form

Clic en Find Account Find Account Form

Demo: Creacin de una Cuenta

http://localhost:9090/pojo-tapestrytutorial/createaccount
Create Account Form

Create Account Form

Created Account Data

Demo: Control de Errores


Create Account Form

El identificador de usuario y el balance son obligatorios

Create Account Form

El identificador de cuenta debe ser un nmero entero y >=0


Create Account Form

El balance debe ser un nmero real y >=0

Demo: Bsqueda de una cuenta

http://localhost:9090/pojo-tapestrytutorial/findaccount
Find Account Form

Find Account Form

Account Data

Demo: Control de Errores


Find Account Form

El identificador de cuenta es obligatorio

Find Account Form

El identificador de cuenta debe ser un nmero entero y >=0

Account Data

Debe existir alguna cuenta con el identificador i id ifi d introducido d id

Estructura del Subsistema (1)


pojo-tapestrytutorial src/main java es.udc.pojo.tapestrytutorial model account accountservice web.pages resources

*.java
es/udc/pojo/tapestrytutorial/web/pages

webapp/WEB-INF

*.tml *.properties

web.xml app.properties

Estructura del Subsistema (y 2)

Cada pgina

Tiene su clase asociada en el paquete es.udc.pojo.tapestrytutorial.web.pages dentro del directorio de cdigo fuente src/main/java Tiene su plantilla asociada en el directorio es/udc/pojo/tapestrytutorial/web/pages dentro del directorio de recursos src/main/resources

De esta forma el fichero .tml de la plantilla correspondiente a cada pgina se copiar (durante la fase de procesamiento de recursos de Maven) al mismo directorio en el que se genera el fichero .class resultado de compilar la clase de la pgina class (dentro de target/classes)

Capa Modelo (1)

La capa modelo de la aplicacin es exactamente igual que la del subsistema pojo-servjsptutorial pojo servjsptutorial Recurdese que para simplificar su implementacin

Se ha optado por la realizacin de la persistencia en memoria, en lugar de utilizar una BD Se ha definido la implementacin del servicio directamente, sin crear una interfaz i i t f

Capa Modelo (y 2)

Modelado de entidades

Account Representa una cuenta bancaria, con la misma informacin que la comentada para pojominibank
Account - accountId : Long g - userId : Long - balance : double + Constructores + mtodos get/set t d t/ t

Definicin API modelo


AccountServiceImpl Define los mtodos createAccount y findAccount No utiliza DAOs porque mantiene las cuentas en memoria en lugar de hacerlas persistentes
AccountServiceImpl A tS i I l - lastAccountId : long - accounts: Map<Long, Account> + createAccount(account : Account) : Account + findAccount(accountId : long) : Account

web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <!-<!-! <!-====================================================================== --> Tapestry 5 web application configuration b li i fi i --> ====================================================================== -->

<web-app> <display-name>POJO-Examples Tapestry Tutorial</display-name> <context-param> <param-name>tapestry.app-package</param-name> <param-value>es.udc.pojo.tapestrytutorial.web</param-value> </context-param> / p <filter> <filter-name>app</filter-name> <filter-class>org.apache.tapestry5.TapestryFilter</filter-class> </filter> <filter-mapping> <filter-name>app</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> / b

Filtros

Disponibles desde la versin 2.3 de la API de Servlets Proporcionan un mecanismo estndar para interceptar peticiones y respuestas dentro de un contenedor de Servlets, para transformar o utilizar la informacin contenida en ellas

Permiten capturar una peticin y cambiar el flujo de sta (decidir a qu Servlet dirigirla, rechazarla, procesarla, etc.) Tambin permiten realizar transformaciones sobre las respuestas generadas filter-name: Indica el nombre del filtro filter-class: Indica la clase Java que lo implementa

Se definen con la etiqueta filter


La etiqueta filter-mapping indica cuando debe invocarse un filtro


filter-name: Nombre del filtro a aplicar url-pattern: Patrn que indica para qu peticiones debe aplicarse

Integracin en un Contenedor de Servlets

Tapestry se integra dentro de un contenedor de Servlets a travs de un filtro En el fichero web.xml debe declararse el filtro org.apache.tapestry5.TapestryFilter

Puede drsele cualquier nombre, aunque suele utilizarse app Este filtro procesa todas las peticiones relativas a Tapestry y pasa el resto de peticiones al contenedor de Servlets Cuando se accede al directorio raz de una aplicacin Tapestry entonces enva la peticin a la pgina Index

Adems, para cada aplicacin debe configurarse el paquete raz de la aplicacin a travs de un parmetro con nombre tapestry.app-package

Tapestry utiliza este paquete para localizar las clases relativas a las pginas y los componentes creados por el usuario utilizados en la aplicacin li i

Las clases de los componentes deben ir en el sub-paquete components Las clases de las pginas deben ir en el sub paquete pages (en sub-paquete nuestro ejemplo es.udc.pojo.tapestrytutorial.web.pages)

Index.tml (1)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> <head> <title>${message:title}</title> </head> <body text="#000000" bgcolor="#ffffff"> <div align="center"> <p><font color="#000099" size="+2" face="Arial Helvetica, sans-serif > color= #000099 size= +2 face= Arial, Helvetica sans-serif"> <b>${message:title}</b></font><br/> </p> </div>

Index.tml (y 2)
<div align="center"> <a href="#" t:type="PageLink" href= # t:type= PageLink t:page="CreateAccount">${message:createAccount}</a> <br/> <a href="#" t:type="PageLink" t:page= FindAccount >${message:findAccount}</a> t:page="FindAccount">${message:findAccount}</a> </div>

</body> / </html>

Plantillas (1)

A travs de la declaracin DOCTYPE se hace referencia a la DTD de XHTML 1.0, y se indica adems que el 10 elemento raz es html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 0 Strict//EN" //W3C//DTD 1.0 Strict//EN "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

El elemento raz incluye la declaracin de un espacio de nombres


<html xmlns="http://www w3 org/1999/xhtml" xmlns= http://www.w3.org/1999/xhtml xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">

Cualquier elemento o atributo que tenga prefijo t pertenece al q q g p j p espacio de nombres de Tapestry En el markup generado, no se incluye la importacin del espacio de nombres de Tapestry

Plantillas (y 2)

Tapestry elimina todos los espacios y retornos de carro de la plantilla que sean innecesarios para la respuesta generada. Por ejemplo:

Dentro de un bloque de texto las secuencias de espacios se sustituyen por un nico espacio Los bloques de texto entre dos tags HTML, compuestos nicamente por espacios y retornos d lnea, son eliminados i t de l li i d

Si se examina la respuesta generada (por ejemplo con la opcin Ver cdigo fuente de un navegador) puede verse que est todo en pocas lneas l Para variar este comportamiento puede usarse el atributo XML estndar xml:space, para indicar a Tapestry que conserve los espacios y retornos de d carro (xml:space="preserve") ( l " ")

El markup generado no incluye este atributo til para depuracin mientras se est desarrollando la aplicacin
<html xmlns="http://www.w3.org/1999/xhtml" // / / xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xml:space="preserve">

Alternativa: Utilizar un plugin para el navegador que permita visualizar el cdigo fuente de forma ms amigable (e.g en forma de rbol)

E.g. Firebug para Firefox

Componentes

Definicin de componentes

Es posible incluir componentes dentro de una plantilla utilizando el elemento correspondiente (dentro del espacio de nombres de Tapestry)

<t:PageLink page="CreateAccount">${message:createAccount}</t:PageLink>

Tiene el inconveniente potencial de que se pierde la capacidad de visualizar la plantilla, como una pgina HTML, en un navegador plantilla HTML

Otra alternativa consiste en incluir la definicin del componente dentro de un elemento HTML estndar utilizando el atributo yp p p p t:type para indicar el tipo del componente

<a href="#" t:type="PageLink" t:page="CreateAccount">${message:createAccount}</a>

En los ejemplos de la asignatura se ha seguido esta aproximacin

Los nombres de los componentes no son sensibles a maysculas/minsculas

Convenciones en el uso del espacio de nombres de Tapestry con atributos

Para favorecer la legibilidad, en los ejemplos de la asignatura se han seguido las siguientes convenciones en el uso del espacio g g p de nombres de Tapestry con atributos

Cuando se usa un componente de Tapestry dentro de un elemento HTML => se ha usado el prefijo del espacio de > nombres de Tapestry en los atributos propios del componente
<a href="#" t:type="PageLink" t:page="CreateAccount>...</a>

Cuando se usa un componente de Tapestry directamente => no se ha utilizado el prefijo del espacio de nombres de Tapestry en los atributos del componente p y p
<t:if test="account">...</t:if>

En cualquier caso => siempre se ha usado el prefijo del espacio de nombres de Tapestry para el atributo id en los componentes que lo necesitan

Para el atributo especial id, el prefijo siempre es necesario

<t:select t:id="language" model="languages"/>

Componente PageLink

Su propsito es visualizar un enlace que apunte hacia otra p g pgina de la aplicacin p Se define dentro de un elemento HTML de tipo a Debe declararse el atributo t:type con valor PageLink El atributo t:page sirve para indicar el nombre de la pgina a t ib t i i di l b d l i la que se debe navegar cuando se hace clic en el enlace

Se refiere al nombre lgico de la pgina g p g

En el markup generado sustituye el valor del atributo href por un valor apropiado (en funcin del valor del atributo t:page) y al igual que cualquier otro componente, elimina el atributo componente t:type Desde la plantilla de la pgina Index se ha utilizado este componente para generar dos enlaces hacia las pginas CreateAccount y FindAccount

Sintaxis de expansiones y valores de parmetros (1)

Los valores de los parmetros de los componentes se especifican con la sintaxis prefijo:valor y las expansiones mediante ${prefijo:valor}

Entre otros, existen los siguiente prefijos

literal: indica que valor debe interpretarse como un lit l: l literal prop: indica que valor es el nombre de una propiedad de la clase de la pgina (se acceder a ella travs del mtodo get correspondiente) message: indica que valor es la clave de un mensaje del catlogo de mensajes

Sintaxis de expansiones y valores de parmetros (2)

En el caso de acceso a propiedades (prefijo prop) es posible

Referirse a subpropiedades Ejemplo: propiedad.subpropiedad invocara el mtodo getSubpropiedad sobre el objeto devuelto por el mtodo getPropiedad de la pgina Invocar a un mtodo del objeto que no sea un getter (utilizando parntesis a continuacin del nombre del mtodo) Ej Ejemplo: propiedad.hashCode() i l invocara el mtodo l t d hashCode sobre el objeto devuelto por el mtodo getPropiedad de la pgina Invocar a un mtodo del objeto pasndole parmetros (se indican separados por comas dentro de los parntesis)

Los parmetros son a su vez expresiones que pueden referirse a propiedades del objeto

Sintaxis de expansiones y valores de parmetros (y 3)

Prefijos por defecto

Un parmetro puede definir un prefijo por defecto y de defecto, hecho es lo habitual, de manera que en ese caso, el valor del parmetro se puede especificar sin incluir el prefijo

La d L documentacin de un componente especifica para cada i d ifi d parmetro su prefijo por defecto

En el caso de las expansiones, el valor por defecto del prefijo es prop

Catlogos de Mensajes (1)

app.properties
accountId-label=Account Identifier balance-label=Balance link-home=Home userId-label=User Identifier

Index.properties
createAccount=Create Account findAccount=Find Account title=Tapestry Tutorial Main Page

Catlogos de Mensajes (2)

Forman parte del soporte de internacionalizacin que p p proporciona Tapestry p y Permiten que los textos fijos de las plantillas, en lugar de escribirlos directamente en ellas, se escriban en un fi h fichero de mensajes d j

Ficheros .properties

Existe un catlogo de mensajes general para toda la aplicacin


Mensajes visibles desde todas las pginas Debe colocarse dentro del directorio WEB-INF El nombre debe ser el mismo que el que se le dio al filtro de Tapestry en el fichero web.xml p y

En el ejemplo debe llamarse, por tanto, app.properties

En este fichero deben colocarse los mensajes que sean comunes a varias pginas

Catlogos de Mensajes (3)

Es posible definir un fichero de mensajes especficos p para una pgina p g

Debe tener el mismo nombre que la pgina y debe estar en el mismo directorio que ella (en la estructura de cdigo fuente estn colocados en el mismo directorio que la plantilla de la pgina) Los mensajes definidos en este fichero solo sern visibles para la pgina en cuestin Por ejemplo los mensajes definidos en Index.properties solamente son visibles para la pgina Index

Los L mensajes se referencian a travs d una j f i t de expansin utilizando el prefijo message seguido de la clave del mensaje en el fichero de mensajes

La sintaxis es ${message:clave} Primero se busca la clave en el fichero de mensajes especfico de la pgina (si existe) y si no se encuentra, encuentra entonces se busca en el fichero de mensajes general

Catlogos de Mensajes (y 4)

En el apartado 4.3 se explicar cmo pueden utilizarse los ficheros de mensajes junto con otras funcionalidades proporcionadas por Tapestry para visualizar una aplicacin en diferentes idiomas p

Index.java
package es.udc.pojo.tapestrytutorial.web.pages; public class Index {}

La clase asociada a la pgina Index no define ninguna propiedad ni ningn mtodo

CreateAccount.tml (1)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> <head> <title>${message:title}</title> </head> <body> <form t:type="Form" t:id="createAccountForm"> <t:errors/> <table width="100%" border="0" align="center" cellspacing="12">

CreateAccount.tml (2)
<!-- User Identifier --> <tr> <th align="right" width="50%"> <t:label for="userId"/> </th> <td align="left"> <input t:type="TextField" t:id="userId" t:validate="required, min=0" size="16" maxlength="16" /> </td> </tr> <!-- Balance --> <tr> <th align="right" width="50%"> <t:label for="balance"/> </th> <td align="left"> <input t:type="TextField" t:id="balance" q , g t:validate="required,min=0" size="16" maxlength="16"/> </td> </tr>

CreateAccount.tml (y 3)
<!-- Create button --> <tr> <td width="50%"></td> <td align="left" width="50%"> <input type="submit" value="${message:create}"/> </td> / </tr> </table> </form> </body> </html>

CreateAccount.properties
create=Create title=Create Account Form

Componente Form

En la plantilla se ha incluido un componente Form ( (t:type="Form"), embebido dentro de una etiqueta yp ), q form HTML, que dentro contiene otros componentes

Este componente genera un formulario HTML En la l E l clase de la pgina puede haber definidos manejadores d l i d h b d fi id j d asociados a los eventos que genera este componente

Hay una serie de eventos que se generan cuando se visualiza el componente y otros cuando se enva el formulario (submit)

El componente contiene un elemento HTML input de tipo submit, que sirve para enviar el formulario Se l h S le ha asignado un identificador a travs del atributo t:id i d id ifi d d l ib

Como se ver ms adelante, este identificador puede ser utilizado desde el cdigo de la clase de la pgina para indicar cuales son los manejadores de eventos de este formulario l l j d d t d t f l i t:id es un atributo especial que tienen todos los componentes y su valor identifica al componente de manera nica dentro de la pgina

Componente TextField (1)

Dentro del formulario hay dos componentes de tipo TextField embebidos dentro de dos elementos input HTML (t:type="TextField")

Este componente est ligado a una propiedad de la clase de p g p p la pgina

El atributo t:value sirve para indicar el nombre de la propiedad a la que est asociado

Si no existe ese atributo entonces t:id es el que indica el nombre de la propiedad a la que est asociado

La clase debe tener mtodos get y set para acceder al valor a a d b odo pa a a d a a o de la propiedad y establecerlo Por ejemplo, el primer TextField tiene el valor userId para la propiedad t:id, por tanto estar asociado a la propiedad userId, lo que implica que la clase de la pgina debe tener los mtodos getUserId y setUserId

Componente TextField (y 2)

Dentro del formulario hay dos componentes de tipo TextField embebidos dentro de dos elementos input HTML (cont)

Este componente se visualiza como un campo de texto (un p p ( input de tipo text), conteniendo el valor de la propiedad a la que est asociado

Accede a la propiedad de la clase para recuperar su valor a travs del mtodo get correspondiente

Cuando se enva el formulario al servidor, se le asigna el valor que contenga en ese momento el campo de texto a la propiedad a la que est asociada

Establece el valor de la propiedad en la clase a travs del mtodo set correspondiente t d di t

Componente Label

El componente Label genera el tag HTML <label> asociado a un campo de entrada de un formulario

En C CreateAccount.tml se han utilizado dos componentes t A t t l Label para visualizar la etiqueta asociada a los dos campos de texto del formulario En este caso el componente se ha declarado directamente a travs p del elemento t:label

El atributo for indica el identificador del componente cuya etiqueta debe ser visualizada (en nuestro caso los identificadores de los componentes TextField) p )

Para obtener el valor de la etiqueta asociada a un componente TextField

Primero se mira si tiene un atributo t:label y si existe se usa su valor l

Si no existe ese atributo se genera en funcin del identificador del componente (atributo t:id)

Puede ser constante o leerse de un fichero de mensajes

Si existe una clave en el fichero de mensajes id-label (sustituyendo id por el identificador del componente) se usa el valor que tenga asignado (por ejemplo userId-label=User identifier) Si no se genera en funcin del valor del identificador dividindolo en no, palabras (por ejemplo userId se dividira como User Id)

Validacin de campos de formularios (1)

Tapestry proporciona un conjunto de validadores que pueden ser aplicados a los campos de entrada de un formulario a travs del atributo t:validate Para los campos de texto userId y balance se han p utilizado los validadores

required: Comprueba que el valor asignado al campo no sea nulo ni la cadena vaca min: Comprueba que el valor numrico asignado al campo no sea menor que la cantidad indicada (0 en este caso)

Por defecto, cuando se produce algn error de validacin en el envo de un formulario se vuelve a mostrar la misma pgina que lo contiene

Este comportamiento puede variarse proporcionando un manejador para el evento adecuado j d l t d d

Validacin de campos de formularios (y 2)

Los validadores bsicos proporcionados por Tapestry realizan las validaciones en el navegador (JavaScript) y tambin en el lado servidor (por seguridad y por si el cliente tiene deshabilitado JavaScript) Para visualizar los mensajes de error (lado servidor) asociados a los validadores utilizados dentro de un formulario se emplea el componente Errors (elemento t:errors)

Otros validadores proporcionados por Tapestry son

Debe colocarse dentro del componente Form que incluye a los componentes que tienen los validadores Es recomendable utilizarlo siempre por si el navegador tiene d bl l l l d deshabilitado JavaScript

Es posible aadir nuevos validadores

minlength/maxlength: Comprueban que la longitud de la i l th/ l th: cadena asignada al campo no sea menor/mayor que la cantidad indicada max: Comprueba que el valor numrico asignado al campo no sea p q g p mayor que la cantidad indicada regexp: Comprueban que la cadena asignada al campo concuerda con un patrn

CreateAccount.java
public class CreateAccount { @Property private Long userId; @Property private Double balance; @InjectPage p private AccountCreated accountCreated; Object onSuccess() { Account account = new Account(userId, balance); Account(userId new AccountServiceImpl().createAccount(account); accountCreated.setAccountId(account.getAccountId()); return accountCreated; } }

Propiedades

La clase CreateAccount contiene dos propiedades asociadas a los dos campos de texto presentes en la plantilla de la pgina: userId y balance

Como se haba dicho con anterioridad el acceso a esas propiedades se hace a travs de mtodos get/set La anotacin @Property permite anotar campos para los que deben crearse mtodos get/set

De esta forma no es necesario escribir esos mtodos Si se usa la anotacin, los mtodos get/set no pueden existir

Inyeccin de pginas

Utilizando el patrn de inyeccin de dependencias, la anotacin @InjectPage permite inyectar una pgina en una propiedad de otra pgina

Tiene un atributo opcional (value) que debe ser utilizado cuando el tipo de la pgina a inyectar no puede ser determinado (e.g. el tipo de la propiedad en la que se inyecta es una interfaz que cumple la pgina a ser inyectada)

Formularios

El componente Form genera una serie de eventos (tanto a la hora de visualizarse como a la hora de hacer un submit de l) para los cuales se puede proporcionar un manejador en la clase de la pgina que contiene el formulario

En CreateAccount se proporciona un manejador para el evento success, que es emitido una vez que el formulario se ha enviado al ,q q servidor y sus campos de entrada se han validado correctamente Para procesar un evento, existen dos posibilidades

Definir un mtodo con el formato onXxx, siendo Xxx el nombre del evento (e.g. onSuccess) Usar la anotacin @OnEvent sobre el nombre de un mtodo (que puede tener un nombre arbitrario) NOTA: en el cdigo de los ejemplos, se ha preferido la primera opcin (convencin de nombrado)

El mtodo onSuccess acta como manejador del evento success para todos los formularios de la pgina Si hubiese ms de un formulario podra especificarse un manejador diferente para cada uno en f dif t d funcin d su id tifi d (atributo t:id) i de identificador ( t ib t )

A travs del nombre del mtodo: onSuccessFromCreateAccountForm Anotando el mtodo: @OnEvent(value = "success", component = "createAccountForm")

Manejadores de eventos (1)

Un manejador de un evento puede devolver

Nada (tipo de retorno void o cuando devuelve null): En este caso la misma pgina vuelve a ser visualizada Una nueva pgina de la aplicacin a ser visualizada

String: Debe ser el nombre lgico de la pgina Class: La clase de la pgina Una instancia de la clase de la pgina (til cuando la pgina debe ser configurada de alguna manera)

Link: Una implementacin de la interfaz Link que ser convertida a una URL a la cual ser redirigido el cliente URL: El cliente ser redirigido a esa URL StreamResponse: Un objeto de tipo Stream que permite p j p q p enviar datos binarios al cliente (e.g. fichero PDF)

Cualquier otro objeto devuelto producir un error

Manejadores de eventos (y 2)

El manejador del evento success de la pgina CreateAccount (mtodo onSuccess)

Crea un objeto Account a partir de las propiedades userId y balance de la pgina

Sern los valores (ya validados) que se hayan introducido en los campos de texto del formulario

Llama al servicio del modelo para crear la cuenta Utiliza la instancia de la pgina de tipo AccountCreated que ha sido inyectada y establece el identificador de la cuenta que se acaba de crear a travs del mtodo setAccountId

Esa pgina lo necesita puesto que muestra el identificador de la cuenta creada

Devuelve la instancia de la pgina de tipo AccountCreated

Por tanto, esa ser la siguiente pgina a ser visualizada

AccountCreated.java
package es.udc.pojo.tapestrytutorial.web.pages; public class AccountCreated { private Long accountId; public Long getAccountId() { return accountId; } public void setAccountId(Long accountId) { this.accountId = accountId; } Long onPassivate() { return accountId; } void onActivate(Long accountId) { this.accountId = accountId; } } NOTA: No se ha utilizado la anotacin @Property sobre el campo accountId porque desde la clase CreateAccount se llama al mtodo setAccountId (y por p tanto el mtodo debe existir en tiempo de compilacin)

Ciclo de vida de las pginas

Para mejorar el rendimiento Tapestry mantiene un pool de instancias para cada pgina

Cuando se solicita una pgina, obtiene una instancia del pool para pgina atender esa peticin Una vez atendida la peticin, la pgina es devuelta al pool

Hay que tener en cuenta que cada vez que se trabaja con una pgina puede ser una instancia distinta Cuando el manejador del evento success de la pgina C d l j d d l d l i CreateAccount devuelve una instancia de la pgina AccountCreated (en la que ha establecido el identificador de la cuenta que se ha creado)

Antes de de o e a a poo las variables de la instancia so inicializadas tes devolverla al pool as a ab es a sta c a son c a adas para borrar los datos especficos de esa peticin

Realmente lo que se hace es indicarle al navegador que haga una nueva peticin sobre la pgina AccountCreated Cuando esa peticin llega a la aplicacin, se coge una instancia de p g p , g la pgina AccountCreated del pool, y la utiliza para generar la respuesta PROBLEMA: La instancia que se ha cogido del pool no tiene establecido el identificador de la cuenta que se ha creado !!!

Comunicacin de datos entre pginas

Existen dos mecanismos que permiten pasar datos entre pginas p g

Se puede hacer que un campo de la pgina sea persistente


Los campos persistentes se anotan con @Persist El valor de estos campos se guarda en la sesin (HttpSession) Cada vez que se obtiene del pool una pgina que tenga un campo persistente se busca en la sesin el valor del campo y se establece en la pgina Desventajas:

Menor escalabilidad al hacer uso de la sesin para almacenar p datos No es posible hacer bookmarks a esas pginas

Se puede utilizar el contexto de activacin de pginas p p g

Requiere ms cdigo pero no utiliza la sesin y permite hacer bookmarks a las pginas Es la opcin elegida en el ejemplo

Contexto de Activacin de Pginas (1)

Para hacer una pgina "activable" basta con aadirle los mtodos onActivate y onPassivate Cuando una pgina implementa onPassivate

Antes de ser devuelta al pool se invoca a este mtodo Debe devolver los datos que necesitar la pgina para q p g p visualizar los datos deseados, cuando se haga una redireccin a ella desde un manejador de un evento Estos datos se incluyen en la URL a la que se redirige el cliente, junto con el nombre de la pgina

No se hace uso de la sesin Es posible hacer un bookmark a esa URL

Contexto de Activacin de Pginas (2)

Cuando una pgina implementa onActivate

Cuando se recibe una peticin de renderizacin del cliente, cliente es decir, cuando es una peticin para que se muestre una pgina, se obtiene una nueva instancia del pool y se llama a este mtodo pasndole los datos del contexto que vienen incluidos en la URL En caso de haberse redirigido a la pgina como resultado del procesamiento de un evento, el contexto de activacin contenido en la URL se habr generado a partir de los datos devueltos por onPassivate (por tanto onActivate recibe los datos que devuelve onPassivate)

Contexto de Activacin de Pginas (3)

Cuando una pgina implementa onActivate (cont)

En caso de haber accedido a la pgina a travs de un componente PageLink, el contexto de activacin contenido en la URL se habr generado a partir del atributo t:context t conte t del componente PageLink (por tanto el mtodo onActivate recibe los datos indicados en ese parmetro) El atributo t:context tambin existe en otros componentes (e.g. Form), pero se comporta de una manera diferente

Su valor se pasa a los manejadores de los eventos que se puedan producir sobre dicho componente (e.g. cuando se enva un formulario todos los manejadores que se ejecutan: onValidateForm, onSuccess, ... reciben los parmetros indicados por el atributo t t:context del componente F t t Form correspondiente) Estas peticiones de procesamiento de eventos sobre componentes no son peticiones de renderizacin de una pgina por tanto NO pgina, se invoca el mtodo onActivate de la pgina en la que est contenido el componente

Contexto de Activacin de Pginas (y 4)

El mtodo onPassivate de AccountCreated devuelve el identificador de la cuenta creada

Cuando el mtodo onSuccess de la clase CreateAccount devuelve la instancia de AccountCreated (suponiendo que el identificador de la cuenta creada es 1) la URL a la que se redirige al cliente es
http://host:port/pojo-tapestrytutorial/accountcreated/1

El mtodo onActivate recibe el identificador de la cuenta creada y lo almacena en la variable accountId (invocando al mtodo setAccountId) Los datos que devuelve onPassivate y recibe onActivate tienen que ser tipos simples (o sus contrapartidas objetuales) o String Es posible pasar ms de un dato entre pginas

onPassivate puede devolver un Obj i d d l Object[] [] onActivate puede recibir ms de un parmetro

Cada parmetro, de izquierda a derecha, corresponde a un elemento del array Object[] y Tapestry hace automticamente un cast al tipo Object[], de parmetro

AccountCreated.tml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns http://www.w3.org/1999/xhtml xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> <head> <title>${message:title}</title> </head> </h d> <body text="#000000" bgcolor="#ffffff"> <div align="center"> <p> <font color="#000099" face="Arial, Helvetica, sans-serif"> <b>${message:bodyMessage-1} ${accountId} ${message:bodyMessage-2}</b> </font> </p> </div> <br/> b / <a href="#" t:type="PageLink" t:page="Index">${message:link-home}</a> <br/> </body> </html>

AccountCreated.properties
bodyMessage-1=Account number bodyMessage 2=created bodyMessage-2=created sucessfully title=Created Account Data

Creacin de una cuenta (AccountCreated)

En AccountCreated.tml se usa la expansin ${accountId} y por tanto se llama al mtodo getAccountId de la clase AccountCreated, que en este caso contendr el identificador de la cuenta que se ha creado

Recurdese que ese valor se le pas a travs del mecanismo de activacin de pginas

FindAccount.tml (1)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> <head> <title>${message:title}</title> </head> <body text="#000000" bgcolor="#ffffff"> <form t:type="Form" t:id="findAccountForm"> <t:errors/> <table width="100%" border="0" align="center" cellspacing="12">

FindAccount.tml (2)
<!-- Account Identifier --> <tr> <th align="right" width="50%"> <t:label for="accountId"/> </th> <td align="left"> <input t:type="TextField" t:id="accountId" t:type TextField t:id accountId t:validate="required, min=0" size="16" maxlength="16"/> </td> </tr> <!-- Search button --> <tr> <td width="50%"></td> <td align="left" width="50%"> <input type="submit" value="${message:find}"/> </td> </tr> </table> </form> </f > </body> </html>

FindAccount.java
public class FindAccount { @Property private Long accountId; @InjectPage private AccountDetails accountDetails; Object onSuccess() { accountDetails.setAccountId(accountId); return accountDetails; } }

Bsqueda de una cuenta (FindAccount)

FindAccount.tml

Contiene un formulario con un campo de texto para introducir el identificador de la cuenta buscada

Se valida que tenga algn valor y que sea mayor que 0

FindAccount.java

Tiene una propiedad para almacenar el identificador de la cuenta buscada Se le inyecta una pgina de tipo AccountDetails (utilizada para mostrar los detalles de una cuenta) Tiene un manejador para el evento success que utiliza la pgina inyectada para establecerle el identificador de la cuenta buscada y la devuelve como resultado

AccountDetails.java
public class AccountDetails { private Long accountId; private Account account; public void setAccountId(Long accountId) { this.accountId = accountId; } public Account getAccount() { return account; } void onActivate(Long accountId) { this.accountId = accountId; try { account = new AccountServiceImpl().findAccount(accountId); } catch (InstanceNotFoundException e) { } } Long onPassivate() { return accountId; } }

Bsqueda de una cuenta (AccountDetails.java)

Utiliza el contexto de activacin de pginas

En el mtodo onPassivate se devuelve el identificador de la cuenta buscada

Cuando se enva el formulario de bsqueda de cuenta, suponiendo que se est buscando la cuenta con identificador 1 1, la URL a la que se redirige el cliente ser

http://host:port/pojo-tapestrytutorial/accountdetails/1 Es E posible hacer un bookmark sobre esa URL ibl h b k k b

En el mtodo onActivate

Se llama al modelo para recuperar una cuenta con el p p identificador especificado por el usuario Si la cuenta se encuentra, se guarda en la variable account Si la cuenta no se encuentra, se captura la excepcin y no se encuentra hace nada (simplemente se deja a null la variable account)

Define el mtodo getAccount para permitir el acceso a la propiedad account

AccountDetails.tml (1)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"> <head> <title>${message:title}</title> </head> <body text="#000000" bgcolor="#ffffff"> <div align="center"> <p> <font color="#000099" face="Arial, Helvetica, sans-serif"> <b>${message:header}</b> </font> </p> </div> g <div align="center">

AccountDetails.tml (2)
<t:if test="account"> <table border="1" align="center" width="35%"> <tr> <t > <th width="60%">${message:accountId-label}</th> <td width="30%" align="center">${account.accountId}</td> </tr> <tr> <th width="60%">${message:userId-label}</th> <td width="30%" align="center">${account.userId}</td> </tr> <tr> <th width="60%">${message:balance-label}</th> <td width="30%" align="center">${account.balance}</td> </tr> </t > </table> <p:else> <font color="#000099" face="Arial, Helvetica, sans-serif"> <b>${message:accountNotFound}</b> </font> </p:else> </t:if>

AccountDetails.tml (3)
</div> <br/> <a href="#" t:type="PageLink" t:page="Index">${message:link-home}</a> <br/> </body> </html>

Componente If

El componente If muestra su contenido si se cumple una condicin El parmetro test recibe un valor de tipo booleano

Si es true se muestra el contenido del componente El prefijo por defecto para este parmetro es prop Permite otros tipos de valores no booleanos

Object: tr e si no es n ll true null Number: true si no es 0 Collection: true si no est vaca String: true si no es la cadena vaca y no es el literal false

Tiene un parmetro opcional else que permite proporcionar un contenido alternativo a ser mostrado si la condicin no se cumple

El espacio de nombres tapestry:parameter sirve para pasar parmetros pa met os de bloq e a componentes bloque

En Tapestry, un bloque (block) es un trozo de plantilla

Normalmente se le asigna el prefijo p Con este espacio de nombres definido, los parmetros de bloque se pasan a travs de un elemento que se construye usando el prefijo p: seguido del nombre del parmetro <p:else></p:else>

Bsqueda de una cuenta (AccountDetails.tml)

Utiliza un componente If para determinar si la propiedad account de la pgina (accedida a travs del mtodo getAccount) es distinta de null

Recurdese que el prefijo por defecto del parmetro test del componente If es prop

Si es distinta de null se usan expansiones para mostrar l valores de los campos de la cuenta t los l d l d l t

Por ejemplo ${account.accountId} inserta el resultado de invocar a getAccount().getAccountId() g () g ()

Si es null significa que no se ha encontrado ninguna cuenta con el identificador introducido por el g p usuario y se muestra un mensaje indicando que no se ha podido encontrar dicha cuenta

También podría gustarte