Tapestry


O que é?

Tapestry é um framework open-source (totalmente java) baseado em componentes para o desenvolvimento de aplicações Web (dinâmicas, robustas e altamente escaláveis).

Atualmente encontra-se na versão 4.02 (a versão 5.0 está perto de sair) e pode ser baixado no endereço http://jakarta.apache.org/tapestry.

Qual a novidade?

Princípios

O Tapestry é organizado em torno de quatro princípios:

  1. Simplicidade – as aplicações web não devem ser difíceis de programar.
  2. Consistência – o que for feito em páginas deve ser feito em componentes. O que for feito em aplicações pequenas deve ser feito em grandes aplicações. Os diferentes colaboradores devem encontrar soluções similares aos problemas similares.
  3. Eficiência – aplicações devem ser rápidas e escaláveis.
  4. Feedback – quando alguma coisa estiver errada (p. ex: erro de programação), o framework deve fornecer um diagnóstico útil.

Estes quatro princípios formam o meta-princípio: “A escolha mais simples deve ser a escolha correta”. Filosófico, não?!?

 

Vantagens

  1. É um projeto Apache;
  2. É limpo, eficiente e fácil de usar;
  3. É baseado em necessidades reais de usuários;
  4. Seu modelo de programação é globalmente limpo e elegante (não é perfeito);
  5. Sua arquitetura é eficiente e altamente escalável;
  6. A codificação e configuração são mínimas;
  7. Integração com Eclipse (plugin), Spring, Hibernate e AJAX;
  8. Usa anotações do Java 5;
  9. Os web-designers não têm “medo” das páginas:
  10. a. as páginas são “.html”;
    b. todas as tags da página são tags HTML;
    c. o designer entende o código (facilita a construção e a manutenção dos templates);
    d. pré-visualização da página sem a necessidade de um deploy da aplicação no servidor;

  11. Fornece um grande número de componentes padrões, e os componentes customizados são relativamente fáceis de serem desenvolvidos se necessário;
  12. Exigências importantes do desenvolvimento Web (ex. internacionalização) são também bem integradas.

Desvantagens

  1. Não tão maduro quanto os outros frameworks;
  2. Não é padrão (“concorre” com o JSF);
  3. É menos conhecido do que Struts ou JSF, e não é utilizado por alguns gigantes da indústria;
  4. MUITO pouca gente trabalhando:

    a. pouco material;
    b. poucas pessoas para trocar idéia;
    c. se você precisar ajuda... =(

 

Mãos a obra...

A melhor forma de pegar a essência do Tapestry é trabalhar com alguns exemplos. Nesta aula, trabalharemos com alguns exemplos simples, mas que darão uma boa visão (inicial) de como funciona este framework.

Configurando...

Como uma aplicação Tapestry roda em algum container de aplicação Web, você necessita configurar o seu servlet no arquivo web.xml, como ilustrado abaixo:

<?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">
<web-app>
<display-name>DACA - Aula de Tapestry</display-name>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app</url-pattern>
</servlet-mapping>
</web-app>

 

Você pode dar qualquer nome para o servlet. Entretanto, modificar a URL padrão é muito complicado, então é melhor deixar como está (“/app”). Como fazer esta configuração pode ser visto no site oficial do Tapestry.

A URL da aplicação poderia ser: http://localhost:8080/aulaTapestry/app

 

A aplicação exemplo

• Aplicações Tapestry sempre incluem uma página chamada Home. A página Home é a primeira página mostrada pela a aplicação;

• Uma página Tapestry é sempre uma combinação de:

* uma classe Java -> provê os dados para a parte dinâmica da página;
* um Template HTML -> mistura de código HTML e componentes Tapestry dinâmicos.

• Nosso template então será o Home.html (localizado na raiz do contexto da aplicação web).

<html>
<head> <title>DACA – Aula sobre Tapestry</title>
</head>
<body>
<h1>DACA – Aula sobre Tapestry</h1>
<p>
Horário e data atuais:
<strong> <span jwcid="@Insert" value="ognl:new java.util.Date()">Julho 30 2006</span>
</strong>
</p>
</body>
</html>

O template está muito próximo do HTML normal!


Figura 1: Template HTML visualizado sem o uso do servidor.

Mas o que são esses atributos “estranhos” na tag <span> ?

<span jwcid="@Insert" value="ognl:new java.util.Date()">Julho 30 2006</span>

jwcid (Java Web Component ID): indício de que se trata de Tapestry, e não de HTML normal.

a. Identifica o componente dinâmico que você está interessado. Neste caso, o componente Insert.
b. Insere na página os dados recuperados de uma propriedade da classe Java correspondente.

value: indica onde os dados dinâmicos são encontrados.

ognl (Object Graph Navigation Language ): uma poderosa linguagem de expressão que é muito usada para identificar propriedades dentro dos objetos Java.

a. sinaliza ao Tapestry que isto é uma expressão para ser avaliada, em vez de uma string literal comum;
b. “ognl:new java.util.Date()” -> recupera uma instância da classe Date;
c. O conteúdo da tag é substituído em tempo de execução. O valor que está no template da página serve como valor default para a pré-visualização da página.


Figura 2: Página Tapestry visualizada com a aplicação rodando.

Tapestry possui em torno de 50 componentes, que geralmente cobrem a maiorias das necessidades dos programadores web (loops, condições, campos de entrada de dados, etc.). Mas você também pode desenvolver os seus próprios componentes.

Nota!

Este caminho paralelo, sobre a pré-visibilidade, é realmente uma das grandes sacadas do Tapestry: uma limpa separação entre a lógica e o conteúdo. Um programador HTML que não conhece nada de Java poder editar este template e fazer significativas mudanças e validá-las em seu editor sem envolver um programador Java. Contanto que o lado da equipe HTML preserve os componentes, as tags com um atributo jwcid, e não faça mudanças em seus elementos, o resto do template HTML pode ser editado livremente. Esta é a junção que programadores HTML e Java precisavam para trabalharem juntos.


 

Criando Links (simples)


Figura 3: Página com link.

Nós criamos este novo link adicionando o seguinte no Home.html:

<p>
<a href="#" jwcid="@PageLink" page="Home">atualizar...</a>
</p>

O componente utilizado aqui é o PageLink, de uma família de componentes que geram links em uma aplicação Tapestry.

Tapestry criará automaticamente a URL para você.

Uma pergunta: O que href= " # " faz?

Criando Links (que utilizam listeners)

O componente é o DirectLink;

* Uma das maneiras mais comuns de provocar o comportamento do lado do servidor.

Exemplo: contar o número de vezes que nós clicamos em um link.

 


Figura 4: Página utilizando o DirectLink.


Para isto, necessitaremos complementar o template HTML com uma classe Java;

O template da página DirectLink.html:

<html>
<head>
<title>Tutorial: DirectLink</title>
</head>
<body>
<h1>DACA – Aula sobre Tapestry</h1>
<p>
O valor atual é:
<span style="font-size:xx-large">
<span jwcid="@Insert" value="ognl:contador">10</span>
</span>
</p> <p>
<a href="#" jwcid="@DirectLink" listener="listener:doClick">incrementar contador + 1</a>
</p>
<p>
<a href="#" jwcid="@PageLink" page="Home">atualizar...</a>
</p>
</body>
</html>

A classe da página

package daca.tapestry.pages;
import org.apache.tapestry.annotations.Persist;
import org.apache.tapestry.html.BasePage;
public abstract class DirectLink extends BasePage {
@Persist
public abstract int getContador();
public abstract void setContador( int contador );
public void doClick() {
int contador = getContador();
contador++;
setContador(contador);
}
}
@Persist
public abstract int getContador();

Esta é uma outra característica primordial do Tapestry; as propriedades individuais da página (ou as propriedades dos componentes usados dentro da página) podem armazenar seu valor no HttpSession automaticamente.

Passando parâmetros

<p>
<a href="#" jwcid="by1@DirectLink" listener="listener:doClick" parameters="ognl:1"> incrementar contador + 1</a> </p> <p>
<a href="#" jwcid="by5@DirectLink" listener="listener:doClick" parameters="ognl:5"> incrementar contador + 5</a> </p>

public void doClick( int incremento ) {
int contador = getContador();
contador += incremento;
setContador(contador);
}


Tudo pronto... vamos então visualizar a página no browser...

 

Figura 5: Página de exception gerada pelo Tapestry.

Mas por que isto ocorreu?

<!DOCTYPE application PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" 
"http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
<application>
<meta key="org.apache.tapestry.page-class-packages" value="daca.tapestry.pages"/>
</application>

 

Trabalhando com Forms

Página NovoProjeto.html

A página NovoProjeto para nossa aplicação é muito simples, ela não requer uma classe Java:

<html jwcid="@Shell" title="DACA – Aula sobre Tapestry">
<body>
<h1>DACA – Aula sobre Tapestry: Forms</h1>

<p>Opções:</p>

<ul>
<li><a jwcid="@PageLink" page="AddProjeto">Add Novo Projeto</a></li>
</ul>
</body>
</html>

A classe do objeto Projeto:

package daca.tapestry.core;

import java.util.Date;

public class Projeto {
private String _nome;
private String _releaseId;
private String _descricaoCurta;
private String _descricaoLonga;
private String _categoria;
private String _versaoTapestry;
private Date _dataRelease;
private boolean _publico;

public String getCategoria() {
return _categoria;
}

public void setCategoria(String categoria) {
_categoria = categoria; }

public String getDescricaoLonga() {
return _descricaoLonga; }

public void setDescricaoLonga(String descricaoLonga) { _descricaoLonga = descricaoLonga; }

public String getNome(){
return _nome;
}

public void setNome(String nome) {
_nome = nome; }
public boolean isPublico() {
return _publico; } public void setPublico(boolean publico) {
_publico = publico; }

public Date getDataRelease() {
return _dataRelease; }

public void setDataRelease(Date dataRelease) {
_dataRelease = dataRelease;
}
public String getReleaseId() {
return _releaseId; }

public void setReleaseId(String releaseId) {
_releaseId = releaseId; }

public String getDescricaoCurta() {
return _descricaoCurta; }

public void setDescricaoCurta(String descricaoCurta) {
_descricaoCurta = descricaoCurta; }

public String getVersaoTapestry() {
return _versaoTapestry;
}

public void setVersaoTapestry(String versaoTapestry) { _versaoTapestry = versaoTapestry; }
}


A página AddProject

<html jwcid="@Shell" title="DACA – Aula sobre Tapestry">
<body jwcid="@Body">
<h1>Adicionar um novo projeto</h1>
<form jwcid="form@Form" success="listener:doSubmit">
<table>
<tr>
<th>Nome</th>
<td>
<input jwcid="nome@TextField" value="ognl:projeto.nome" size="40"/>
</td>
</tr>
<tr>
<th>Release ID</th>
<td>
<input jwcid="release@TextField" value="ognl:projeto.releaseId" size="20"/>
</td>
</tr>
<tr>
<th>Descrição curta</th>
<td>
<input jwcid="short@TextField" value="ognl:projeto.descricaoCurta" size="40"/>
</td>
</tr>
<tr>
<th>Descrição longa</th>
<td>
<textarea jwcid="long@TextArea" value="ognl:projeto.descricaoLonga" rows="10" cols="40"/>
</td>
</tr>
<tr>
<th>Versão Tapestry</th>
<td>
<input jwcid="tapestryVersion@TextField" value="ognl:projeto.versaoTapestry" size="20"/>
</td>
</tr>
<tr>
<th>Data da Release</th>
<td>
<input jwcid="releaseDate@DatePicker" value="ognl:projeto.dataRelease"/>
</td>
</tr>
<tr>
<th>Público</th>
<td>
<input jwcid="public@Checkbox" value="ognl:projeto.publico"/>
</td>
</tr>
</table>
<input type="submit" value="Add Projeto"/>
</form>
</body>
</html>

Alguns novos componentes:

 


Figura 7: Página visualizada fora do servidor

Classe da página AddProjeto

package daca.tapestry.pages;


import java.util.Date;
import org.apache.tapestry.event.PageBeginRenderListener;
import org.apache.tapestry.event.PageEvent;
import org.apache.tapestry.html.BasePage;
import daca.tapestry.core.Projeto;


public abstract class AddProjeto extends BasePage implements PageBeginRenderListener {


   public abstract Projeto getProjeto();
   public abstract void setProjeto(Projeto projeto);


   public void pageBeginRender(PageEvent event) {
        Projeto projeto = new Projeto();
		 projeto.setDataRelease(new Date());
		 setProjeto(projeto);
  }
  
  public void doSubmit() {}

}


Figura 8: Página visualizada no servidor

 

Submissão de Forms

@InjectPage("ShowProjeto")
public abstract ShowProjeto getShowProjeto();
public IPage doSubmit() {
   ShowProjeto showProjeto = getShowProjeto();
   showProjeto.setProjeto(getProjeto());
   return showProjeto;
}

 

 

package daca.tapestry.pages;


import org.apache.tapestry.html.BasePage;
import daca.tapestry.core.Projeto;


public abstract class ShowProjeto extends BasePage {
    public abstract void setProjeto(Projeto projeto);
    }
}
<html jwcid="@Shell" title="Show Project">
<body jwcid="@Body">
<table>
<tr>
<th>Nome</th>
<td>
<span jwcid="@Insert" value="ognl:projeto.nome"/>
</td>
</tr>
<tr>
<th>Release ID</th>
<td>
<span jwcid="@Insert" value="ognl:projeto.releaseId"/>
</td>
</tr>
<tr>
<th>Descrição curta</th>
<td>
<span jwcid="@Insert" value="ognl:projeto.descricaoCurta"/>
</td>
</tr>
<tr>
<th>Descrição longa</th>
<td>
<span jwcid="@InsertText" value="ognl:projeto.descricaoLonga"/>
</td>
</tr>
<tr>
<th>Versão Tapestry</th>
<td>
<span jwcid="@Insert" value="ognl:projeto.versaoTapestry"/>
</td>
</tr>
<tr>
<th>Data da Release</th>
<td>
<span jwcid="@Insert" value="ognl:projeto.dataRelease"/>
</td>
</tr>
<tr>
<th>P&uacute;blico</th>
<td>
<span jwcid="@Insert" value="ognl:projeto.publico ? 'Sim' : 'Não'"/>
</td>
</tr>
</table>
</body>
</html>


Figura 9: Página de resultados

Mais...

Plugins para o Eclipse:

 

Enfim...

O Tapestry é uma parte fina de arquitetura e é um bom valor a ser considerado para seu próximo projeto de desenvolvimento Web (inclusive o projeto de DACA =P ).