Molhando os pés com Tapestry, parte 3



Documentos relacionados
Scriptlets e Formulários

Acessando um Banco de Dados

Aula 03 - Projeto Java Web

Manual das funcionalidades Webmail AASP

Persistência de Classes em Tabelas de Banco de Dados

CRIANDO BANCOS DE DADOS NO SQL SERVER 2008 R2 COM O SQL SERVER MANAGEMENT STUDIO

Tutoriais de apoio para a migração do Atualização: 30/04/2014

JDBC Java Database Connectivity

mkdir /srv/www/default/html/calculadora/imagens mkdir /srv/www/default/html/calculadora/blocos

Manual Sistema de Autorização Online GW

1 Criar uma entity a partir de uma web application que usa a Framework JavaServer Faces (JSF)

Esse manual é um conjunto de perguntas e respostas para usuários(as) do Joomla! 1.5.

QUALIDATA Soluções em Informática. Módulo CIEE com convênio empresas

Daruma NFCe Conheça todos os passos para testar a NFCe Daruma

WEBDESIGN. Professor: Paulo Marcos Trentin - paulo@paulotrentin.com.br Escola CDI de Videira

MANUAL DO ANIMAIL Terti Software

Criação de Servlets Name Directory Build WAR JSP/Servlet frameworks Launch URL Package Class name Generate header comments

- Versão 1.0 Página 1

Follow-Up Acompanhamento Eletrônico de Processos (versão 3.0) Manual do Sistema. 1. Como acessar o sistema Requisitos mínimos e compatibilidade

MANUAL COTAÇAO WEB MANUAL MANUAL AVANÇO INFORMÁTICA AVANÇO INFORMÁTICA. [Digite seu endereço] [Digite seu telefone] [Digite seu endereço de ]

FAQ Perguntas Frequentes

Portal da Prefeitura de São Paulo SECOM. MANUAL DO WARAM v. 1.5 Secretarias

Tutorial RM. academico.unipe.br ALUNO

TUTORIAL: MANTENDO O BANCO DE DADOS DE SEU SITE DENTRO DO DOMÍNIO DA USP USANDO O SSH!

Parte I. Demoiselle Mail

CONFIGURAÇÃO MINIMA EXIGIDA:

Figura 1: tela inicial do BlueControl COMO COLOCAR A SALA DE INFORMÁTICA EM FUNCIONAMENTO?

Manual de Instalação. SafeSign Standard (Para MAC OS 10.7)

3. No painel da direita, dê um clique com o botão direito do mouse em qualquer espaço livre (área em branco).

DOCUMENTAÇÃO DO FRAMEWORK - versão 2.0

MANUAL DE UTILIZAÇÃO SISTEMA DE CADASTRO INTRANET

MANUAL DE INSTALAÇÃO E CONFIGURAÇÃO. Motor Periférico Versão 8.0

Manual de configuração do sistema

Lazarus pelo SVN Linux/Windows

Validando dados de páginas WEB

Está apto a utilizar o sistema, o usuário que tenha conhecimentos básicos de informática e navegação na internet.

NOVIDADES DO JAVA PARA PROGRAMADORES C

Sumário: Fluxo Operacional... 3 Contatos Agenda Online Reservas de Salas Tarefas... 42

1. Introdução pág.3 2. Apresentação do sistema Joomla! pág.4 3. Acessando a administração do site pág.4 4. Artigos 4.1. Criando um Artigo 4.2.

INSTALAÇÃO DO SISTEMA CONTROLGÁS

CERTIFICADO DIGITAL ARMAZENADO NO COMPUTADOR (A1) Manual do Usuário

MANUAL DE UTILIZAÇÃO

Bem- Vindo ao manual de instruções do ECO Editor de COnteúdo.

4 O Workflow e a Máquina de Regras

Sistema de Chamados Protega

Sumário INTRODUÇÃO Acesso ao Ambiente do Aluno Ferramentas e Configurações Ver Perfil Modificar Perfil...

Barra de ferramentas padrão. Barra de formatação. Barra de desenho Painel de Tarefas

atube Catcher versão 3.8 Manual de instalação do software atube Catcher

Sistema de Recursos Humanos

Instalando o WordPress em localhost

Trabalhando com conexão ao banco de dados MySQL no Lazarus. Prof. Vitor H. Migoto de Gouvêa Colégio IDESA 2011

Inserindo Dados no Banco de Dados Paradox.

Manual do Visualizador NF e KEY BEST

Instalando e Configurando o DNS Server

Listando itens em ComboBox e gravando os dados no Banco de Dados MySQL.

Manual Integra S_Line

Manual do Almoxarifado SIGA-ADM

NetBeans. Conhecendo um pouco da IDE

Programando em PHP. Conceitos Básicos

UNIVERSIDADE FEDERAL DO AMAPÁ NÚCLEO DE TECNOLOGIA DA INFORMAÇÃO. Manual de Avaliação de Desempenho Cadastro

Trecho retirando do Manual do esocial Versão 1.1

CRIANDO TEMPLATES E LEGENDAS

Criando um script simples

Criação de Formatos para detalhamento. Ambiente de trabalho no SOLIDWORKS

Molhando os pés com Tapestry, parte 1

GUIA RÁPIDO SISTEMA ANTIFURTO THEFT DETERRENT

GUIA RÁPIDO DE UTILIZAÇÃO DO PORTAL DO AFRAFEP SAÚDE

INTRODUÇÃO À TECNOLOGIA SERVLETS

Manual 2010 Webmaster

Manual de utilização do sistema de envio de sms marketing e corporativo da AGENCIA GLOBO. V

Criando & Consumindo um WebService com ASP.NET 2.0 Publicado em: 25 de Agosto de 2007 Por Herman Ferdinando Arais

Manual Captura S_Line

INSTALAÇÃO DO MICROSOFT WINDOWS SHAREPOINT SERVICES 2.0

Sumário. 1 Tutorial: Blogs no Clickideia

Como criar um EJB. Criando um projeto EJB com um cliente WEB no Eclipse

MANUAL DO PORTAL ACADÊMICO - ALUNO

Omega Tecnologia Manual Omega Hosting

Como incluir artigos:

02 - Usando o SiteMaster - Informações importantes

GUIA BÁSICO DA SALA VIRTUAL

Microsoft Access XP Módulo Um

Sumário 1. SOBRE O NFGoiana DESKTOP Apresentação Informações do sistema Acessando o NFGoiana Desktop

Módulo e-rede OpenCart v1.0. Manual de. Instalação do Módulo. estamos todos ligados

Tutorial para envio de comunicados e SMS

PORTAL DO ALUNO - MANUAL

Passo-a-Passo para Criação de Conta no site Griaule e Download do Programa SDK e da Licença Fingerprint SDK 2009

Vamos criar uma nova Página chamada Serviços. Clique em Adicionar Nova.

Sumário. Capítulo 2 Iniciando o TR Como efetuar o login... 8

BR DOT COM SISPON: MANUAL DO USUÁRIO

MANUAL DE UTILIZAÇÃO. HELP SUPORTE e HELP - REMOTO (Versão de usuário: 2.0)

Smart Laudos 1.9. A Forma Inteligente de Criar seus Laudos Médicos. Manual do Usuário

Criando Banco de Dados, Tabelas e Campos através do HeidiSQL. Prof. Vitor H. Migoto de Gouvêa Colégio IDESA 2011

Criar uma aplicação JPA2 com EclipseLink e H2

Operador de Computador. Informática Básica

Apresentação. Nossa sugestão é que você experimente e não tenha medo de clicar!!!

Criando uma agenda simples com NetBeans 6.5

PORTAL DE COMPRAS SÃO JOSÉ DO RIO PRETO

Passo a Passo da instalação da VPN

Transcrição:

Molhando os pés com Tapestry, parte 3 Daniel Fernandes Martins Se cansou de apenas ouvir falar sobre o framework Tapestry? Se sim, então veja por si só o que o Tapestry pode fazer por você! Sobre o tutorial Molhando os pés com Tapestry é um tutorial que apresenta, de uma forma clara e objetiva, informações sobre o como o framework Tapestry [1] pode nos ajudar a criar aplicações Java para web. Este tutorial está dividido em três partes que cobrem desde a montagem do ambiente de desenvolvimento até criação de pequenas aplicações web. Segue, em detalhes, o conteúdo deste tutorial: Configuração do NetBeans [2] para criação de aplicações Tapestry; Hello world utilizando o Tapestry; Aprendendo a submeter formulários; Aplicação de login; Aplicação completa, com internacionalização, validação (servidor e cliente) e lógica de negócio em EJB 3. O tutorial não cobre assuntos mais avançados, como criação de componentes e validadores customizados, mas se isso for de interesse, basta que o leitor busque as informações necessárias na página do projeto Tapestry. Este documento abordará o tópico destacado na lista mostrada a pouco. Sobre a aplicação Diferentemente dos dois primeiros tutoriais, vamos extrapolar um pouco os limites... a idéia aqui é criar uma aplicação de guestbook (livro de visitas) bem simples, composto de apenas duas páginas: a página principal e a página de cadastro de mensagens. A página principal servirá para mostrar a lista de todas as mensagens cadastradas, além de exibir um link que leva o usuário à página de cadastro de mensagens (Ilustração 1). A página de cadastro de mensagens abrigará o formulário de cadastro e um link para levar o usuário de volta à página principal, caso ele desista de cadastrar a mensagem. O 1

formulário será validado no lado do cliente, coisa bem simples de se fazer visto que já sabemos tudo (bem, quase tudo) sobre como funciona a validação de formulários no Tapestry (Ilustração 2). Ilustração 1: Esboço da página principal Aonde o extrapolar entra nessa história? É que vamos aproveitar a oportunidade para implementar a lógica de negócios com EJB 3. Portanto, é desejável (embora não seja obrigatório) que o leitor já possua algum conhecimento sobre EJBs, já que alguns procedimentos explicados aqui podem não fazer muito sentido para quem não está habituado. A aplicação utilizará o framework HiveMind [3] para implementar a integração da aplicação web com os componentes de EJBs. O HiveMind é um framework de injeção de dependências que já acompanha o Tapestry. Além disso, você aprenderá como (e porque) utilizar o Tapestry Flash [2], um plugin do Tapestry que implementa o escopo flash, bastante utilizado pelo pessoal do Ruby on Rails [REF 4]. Ilustração 2: Esboço da página de cadastro de mensagem 2

Bastante coisa para aprender, ãhn? Então seja bem vindo ao tutorial mais longo da série! : ) Criando o projeto Abra o NetBeans e acesse o menu File New Project. Selecione Enterprise Enterprise Application e pressione Next. Configure a janela conforme mostrado na Ilustração 3: Ilustração 3: Configurações do projeto Pressione Finish para concluir a criação do projeto. Criando o Entity Bean A aplicação utilizará apenas um Entity Bean, que representará as mensagens (Ilustração 4): 3

Ilustração 4: Entidade Message Então, para criar o Entity Bean, clique com o botão direito do mouse no projeto guestbook ejb e selecione a opção New File/Folder... Na janela que aparecer, escolha a opção Persistence Entity Class. No campo Class Name, digite Message. No campo Package, digite entity. O tipo da chave primária, que é representada pelo campo Primary Key Type, será Long (Ilustração 5). Ilustração 5: Entity Bean O NetBeans irá criar um Entity Bean. Altere o código para que ele fique de igual ao mostrado na Listagem 1: package entity; // imports... @Entity public class Message implements Serializable { private Long id; private Calendar date = Calendar.getInstance(); private String name; private String email; private String comment; 4

@Id @GeneratedValue public Long getid() { return this.id; public void setid(long id) { this.id = id; @Temporal(value = TemporalType.TIMESTAMP) public Calendar getdate() { return date; public void setdate(calendar date) { this.date = date; public String getname() { return name; public void setname(string name) { this.name = name; public String getemail() { return email; public void setemail(string email) { this.email = email; public String getcomment() { return comment; public void setcomment(string comment) { this.comment = comment; Listagem 1: Classe Message Explicar o funcionamento das especificações EJB e JPA está fora do escopo deste tutorial. Para mais detalhes sobre essas especificações, recorra aos diversos (e excelentes) tutoriais disponíveis na Internet. Criando o banco de dados Para economizarmos tempo, utilizaremos o banco de dados que é fornecido pelo servidor de aplicações da Sun por padrão: o Derby [4]. 5

Uma vez que o servidor de aplicações Sun Java System Application Server esteja devidamente instalado e configurado dentro do NetBeans, podemos criar o banco através do menu Tools Java DB Database Create Java DB Database... Na janela que aparecer, você deve entrar com as seguintes informações: Database Name: guestbook User Name: app Password: app Pressione OK e pronto. Em alguns segundos o banco de dados estará pronto para uso. Criando o Persistence Unit As configurações de persistência da nossa aplicação ainda não foram definidas por completo. Para concluirmos a configuração de persistência, abra o código do Entity Bean Message e note que o NetBeans está pedindo a criação de uma unidade de persistência (Persistence Unit): Ilustração 6: NetBeans pedindo a criação da unidade de persistência Para criar a unidade de persistência, mova o cursor de edição para o local sublinhado pelo editor e clique na lâmpada que aparecerá ao lado da anotação @Entity, selecionando a opção Create persistence unit..., conforme mostrado na Ilustração 6. Configure a unidade de persistência de acordo com a Ilustração 7: 6

Ilustração 7: Configuração da unidade de persistência Pronto! Agora a nossa aplicação está pronta para trabalhar com o banco de dados. Criando o Stateless Session Bean Criaremos agora um Stateless Session Bean, que irá conter os métodos necessários para possamos trabalhar com o banco de dados que criamos a pouco. Clique com o botão direito do mouse no projeto guestbook ejb e selecione a opção New New File/Folder... Selecione as opções Enterprise Session Bean e pressione Next. O nome do Session Bean deverá ser MessageManager, e este será um Session Bean do tipo Stateless. Deixe marcada a opção Local para o tipo de interface a ser gerada (Ilustração 8). 7

Ilustração 8: Criando o Stateless Session Bean Altere a interface MessageManagerLocal... package business; // imports... @Local public interface MessageManagerLocal { void save(message msg); List<Message> loadall(); Listagem 2: Interface MessageManagerLocal... e também a classe MessageManagerBean: package business; // imports... @Stateless public class MessageManagerBean implements MessageManagerLocal { /* Contêiner injeta o EntityManager automaticamente */ @PersistenceContext private EntityManager entitymanager; 8

public void save(message msg) { entitymanager.persist(msg); // Grava a mensagem public List<Message> loadall() { return entitymanager.createquery( "SELECT m FROM Message m ORDER BY m.date DESC" ).getresultlist(); // Seleciona todas as mensagens Listagem 3: Classe MessageManagerBean Fácil, não?! Com este bean já podemos cadastrar mensagens e recuperar a lista de mensagens registradas no sistema. Adicionando suporte ao Tapestry Precisamos adicionar o suporte ao Tapestry no módulo web da nossa aplicação (guestbook war). Para isso, clique com o botão direito no projeto guestbook war e vá em Properties. Selecione a opção Frameworks e pressione o botão Add... Selecione o framework Tapestry na lista e confirme. Configure de acordo com a Ilustração 9: Ilustração 9: Configuração do Tapestry Utilizando o HiveMind para integrar o Tapestry com o EJB Depois de confirmar, o plugin do NetBeans irá criar os arquivos de configuração do Tapestry. Abra o arquivo WEB INF/hivemodule.xml e digite o código exibido na Listagem 4: <?xml version="1.0" encoding="utf 8"?> 9

<! app é o nome do nosso módulo... tipo uma 'namespace' > <module id="app" version="0.0.1"> <! Nome do serviço e interface implementada por ele > <service point id="ejbfactory" interface="org.apache.hivemind.serviceimplementationfactory"> <! Definimos nossa própria marcação XML > <parameters schema> <element name="construct"> <attribute name="jndi name" required="true" /> <conversion class="hivemind.ejbparam"> <map attribute="jndi name" property="jndiname" /> </conversion> </element> </parameters schema> <! Classe concreta que implementa a interface indicada acima > <! ah, e a instância é singleton por padrão > <invoke factory> <construct class="hivemind.ejbfactory" /> </invoke factory> </service point> <! Continua.. > </module> Listagem 4: Definindo um Service Point no HiveMind Antes de prosseguirmos com o tutorial, você precisa entender o que foi feito na Listagem 4. O elemento <service point> serve para declararmos um serviço no nosso módulo (de nome app), fornecendo um ID e a interface implementada pelo serviço. Dentro do elemento <service point> temos algumas informações agrupadas sob o elemento <parameters schema>. É aqui que o negócio fica legal, pois são com essas informações que somos capazes de definir, a nível de XML, como devemos formatar as informações durante a utilização do serviço. Está com dificuldades em compreender? Olhe com atenção o conteúdo do elemento <parameters schema>: <element name="construct"> <attribute name="jndi name" required="true" /> <conversion class="hivemind.ejbparam"> <map attribute="jndi name" property="jndiname" /> </conversion> </element> Listagem 5: Configuração da sintaxe XML O elemento <element> serve para definirmos um elemento na nossa sintaxe XML 10

customizada, onde, no caso, estamos definindo um elemento construct. Um exemplo de elemento no HTML é a tag <font>. Em seguida, definimos que o elemento construct possui um atributo chamado jndiname, que é obrigatório. Ainda fazendo um paralelo com o HTML, podemos dizer que o elemento (ou tag) <font> possui um atributo face, onde indicamos o nome da fonte a ser utilizada. Dentro da definição do elemento construct, temos também um elemento <conversion>, que serve para indicar a classe que armazenará os dados lidos do XML (em específico do elemento construct). A classe em questão é EJBParam, e seu código será mostrado em alguns instantes. Note que, dentro deste elemento conversion, declaramos um elemento <map> para que possamos mapear, um a um, os atributos indicados no XML com as propriedades da classe Java. No nosso caso, indicamos que o atributo jndi name, do XML, corresponderá à propriedade jndiname, da classe Java. Para que isso tudo fique mais simples de ser entendido, vamos fazer mais uma alteração no arquivo hivemodule.xml, onde criaremos um serviço que utiliza o serviço EJBFactory. Então abra o arquivo WEB INF/hivemodule.xml e coloque o seguinte trecho depois do comentário <! continua.. >: <! Novo serviço (que será uma instância do bean Stateless) > <service point id="messagemanager" interface="business.messagemanagerlocal"> <! Este serviço utiliza o serviço JndiResourceFactory > <invoke factory service id="app.ejbfactory"> <! Ei! Esta é a sintaxe XML que definimos anteriormente! > <construct jndi name="java:comp/env/ejb/messagemanager" /> </invoke factory> </service point> Listagem 6: Serviço para obter uma instância do Stateless Session Bean Talvez agora fique mais fácil de entender. Como já foi dito, serviço EJBFactory servirá para que possamos obter a referência a um EJB via JNDI. Conforme podemos ver no XML, a classe que irá fazer o trabalho sujo é a classe EJBFactory, que implementa uma interface fornecida pelo HiveMind, a ServiceImplementationFactory. O código da classe EJBFactory será mostrado em alguns instantes. Já o serviço que foi definido na Listagem 6, o MessageManager, é o que efetivamente será usado pela nossa aplicação. Basicamente, a função deste serviço é utilizar o serviço EJBFactory para obter a instância do Stateless Session Bean MessageManager. Veja que as informações são passadas para o serviço EJBFactory por meio da marcação XML que definimos anteriormente. Se esta aplicação possuísse outros EJBs, teríamos outros serviços muito parecidos com o serviço definido na Listagem 6. Por exemplo, se tivéssemos um Session Bean 11

chamado UserManager, teríamos algo parecido com o seguinte, no arquivo WEB INF/hivemodule.xml: <module...> <!... > <! Nosso OUTRO Stateless Session Bean > <service point id="usermanager" interface="business.usermanagerlocal"> <! Este serviço TAMBÉM utiliza o serviço JndiResourceFactory > <invoke factory service id="app.ejbfactory"> <construct jndi name="java:comp/env/ejb/usermanager" /> </invoke factory> </service point> </module> Listagem 7: Exemplo de serviço similar ao MessageManager Para terminarmos, precisamos criar as duas classes que referenciamos no arquivo WEB INF/hivemodule.xml: hivemind.ejbparam e hivemind.ejbfactory. A classe hivemind.ejbparam é um JavaBean bastante simples e não exige explicações: package hivemind; public class EJBParam { private String jndiname; public String getjndiname() { return jndiname; public void setjndiname(string jndiname) { this.jndiname = jndiname; Já a classe hivemind.ejbfactory é um pouco mais complexa. Veja o código: package hivemind; // imports... public class EJBFactory implements ServiceImplementationFactory { public Object createcoreserviceimplementation( ServiceImplementationFactoryParameters params) { Object result = null; try { EJBParam param = (EJBParam) 12

params.getfirstparameter(); InitialContext context = new InitialContext(); /* Obtém e prepara a referência para uso */ result = context.lookup(param.getjndiname()); result = PortableRemoteObject.narrow(result, params.getserviceinterface()); catch (Exception exc) { exc.printstacktrace(); return result; Listagem 8: Classe para obter objetos via JNDI Conforme podemos ver na Listagem 8, a interface ServiceImplementationFactory exige a implementação do método createcoreserviceimplementation. É através da implementação desta interface que podemos definir serviços HiveMind capazes de fabricar implementações. Quando o serviço MessageManager for utilizado pela primeira vez, o HiveMind invocará o método createcoreserviceimplementation, afim de fabricar o serviço. Na primeira linha após o try, obtemos os dados configurados no XML através de um objeto da classe EJBParam. No nosso exemplo, como definimos o XML dessa forma... <construct jndi name="java:comp/env/ejb/messagemanager" />...então o objeto EJBParam estará com a propriedade jndiname setada como java:comp/env/ejb/messagemanager. As linhas restantes são bastante triviais para aqueles que já trabalharam com EJBs, onde basicamente utilizamos o valor do atributo jndiname para fazer o lookup e preparar a referência ao EJB para uso. Porém, antes que possamos pular de alegria, precisamos abrir o arquivo WEB INF/web.xml e declarar a referência ao EJB. Se não fizermos isso, o EJB não será visível à aplicação web e, conseqüentemente, nossa aplicação não funcionará. Portanto, abra o arquivo WEB INF/web.xml e insira o trecho de código mostrado na Listagem 9 no fim do arquivo (antes do elemento </web app>): <ejb local ref> <ejb ref name>ejb/messagemanager</ejb ref name> <ejb ref type>session</ejb ref type> <local>business.messagemanagerlocal</local> </ejb local ref> Listagem 9: Referenciando o EJB a partir da aplicação web 13

Agora sim, estamos com todo o back end da aplicação construído e pronto para ser usado. Agora nos resta criar as páginas para que o usuário possa interagir com o sistema. Preparando o terreno Antes de continuarmos com o desenvolvimento, vamos dar uma organizada nos arquivos criados pelo plugin do NetBeans, para tornar a estrutura de arquivos mais limpa e arrumada. Vá até o projeto guestbook war e abra a pasta WEB INF. Veja que o plugin criou os arquivos da página Home dentro deste diretório. A razão de o plugin colocar tais arquivos dentro da pasta WEB INF foi para evitar que esses arquivos sejam acessados externamente, uma vez que todos os arquivos e diretórios situados sob o diretório WEB INF são acessíveis apenas à aplicação. Entretanto, esta prática não é recomendada em aplicações com diversas páginas, pois isso compromete a organização dos arquivos da aplicação. Para deixar as coisas mais organizadas, mova os arquivos Home.html e Home.page para a pasta Web Pages (local onde está situado o arquivo index.jsp). Para garantir que os arquivos relativos às nossas páginas Tapestry continuem protegidos do mundo externo, devemos definir uma regra de segurança no arquivo WEB INF/web.xml. Para fazer isso, abra o arquivo WEB INF/web.xml e coloque o trecho mostrado na Listagem 10, antes do elemento </web app>: <security constraint> <display name>page Files</display name> <web resource collection> <web resource name>page Files</web resource name> <description>protect page files</description> <url pattern>*.html</url pattern> <url pattern>*.page</url pattern> <url pattern>*.properties</url pattern> </web resource collection> <auth constraint/> </security constraint> Listagem 10: Bloqueando acesso externo aos arquivos das páginas Caso você nunca tenha trabalhado com segurança de aplicações web, o trecho acima serve basicamente para bloquear o acesso externo (seja ele via GET, POST, ou qualquer outro método HTTP) para todos os arquivos com sufixo.html,.page e.properties. Vamos agora configurar o pacote padrão onde as páginas Tapestry serão criadas. Abra o arquivo WEB INF/guestbook.application e substitua o conteúdo pelo código que segue: <?xml version="1.0" encoding="utf 8"?> <!DOCTYPE application PUBLIC 14

" //Apache Software Foundation//Tapestry Specification 4.0//EN" "http://jakarta.apache.org/tapestry/dtd/tapestry_4_0.dtd"> <application name="tapestry Application"> <meta key="org.apache.tapestry.page class packages" value="guestbook.pages" /> </application> Listagem 11: Configuração do pacote padrão das páginas Tapestry Beleza, agora estamos prontos para codificar as páginas! Criando a página principal Como nós já estamos habituados com o processo de criação de páginas no Tapestry, irei listar o código aqui, explicando apenas aquilo que não foi explicado nos tutoriais anteriores. Abra o arquivo Home.html e coloque o código mostrado na Listagem 12: <html> <head> <title> Guestbook </title> </head> <body> <h1>guestbook</h1> <h2>message list</h2> <form jwcid="form"> <table border="1" jwcid="showtable"> <tr> <th>id</th> <th>date</th> <th>name</th> <th>email</th> <th>comment</th> </tr> <tr jwcid="messagefor"> <td> <span jwcid="msgid">1</span> </td> <td> <span jwcid="msgdate">01/01/2006 23:56</span> </td> <td> <span jwcid="msgname">some people name</span> </td> <td> <a href="#" jwcid="msgemaillink"> <span jwcid="msgemail">somemail@email.com</span> 15

</a> </td> <td> <span jwcid="msgcomment">the comment goes here</span> </td> </tr> </table> </form> <h4 jwcid="nomessages">no messages found</h4> <a href="newmessage.html" jwcid="newmsglink">new message</a> </body> </html> Listagem 12: Template da página principal Agora abra o arquivo Home.page e substitua seu conteúdo pelo conteúdo da listagem a seguir: <?xml version="1.0" encoding="utf 8"?> <!DOCTYPE page specification PUBLIC " //Apache Software Foundation//Tapestry Specification 4.0//EN" "http://jakarta.apache.org/tapestry/dtd/tapestry_4_0.dtd"> <page specification> <property name="message" /> <property name="dateformat" initial value="@java.text.dateformat@getdatetimeinstance( @java.text.dateformat@short, @java.text.dateformat@short, locale)" /> <component id="form" type="form" /> <component id="showtable" type="if"> <binding name="condition" value="messagelist.size() > 0" /> <component id="nomessages" type="else" /> <component id="msgid" type="insert"> <binding name="value" value="message.id" /> <component id="msgdate" type="insert"> <binding name="value" value="message.date.time" /> <binding name="format" value="dateformat" /> <component id="msgname" type="insert"> <binding name="value" value="message.name" /> <component id="msgemaillink" type="genericlink"> <binding name="href" value="'mailto:' + message.email" /> 16

<component id="msgemail" type="insert"> <binding name="value" value="message.email" /> <component id="msgcomment" type="insert"> <binding name="value" value="message.comment" /> <component id="delete" type="submit"> <binding name="parameters" value="message" /> <binding name="action" value="listener:deletemsg" /> <component id="messagefor" type="for"> <binding name="element" value="literal:tr" /> <binding name="source" value="messagelist" /> <binding name="value" value="message" /> <component id="newmsglink" type="pagelink"> <binding name="page" value="literal:newmessage" /> </page specification> Listagem 13: Configuração dos componentes da página principal Embora o código mostrado na Listagem 13 seja meio grande, é bem fácil de entender por quem já acompanhou os outros dois tutoriais. Apenas os trechos em destaque merecem uma atenção especial, visto que tais elementos não foram vistos nos tutoriais anteriores... O primeiro trecho é um elemento <property> com um atributo initial value, cuja função é definir um valor inicial para a propriedade. Neste caso, estamos criando uma propriedade que irá armazenar um Format usado para formatar os campos de data da página. No atributo initial value definimos um DateFormat criado de acordo com o locale do usuário. Esta é uma expressão OGNL e, caso tenha qualquer dúvida em relação às expressões OGNL, leia a documentação do projeto [6]. O segundo trecho em destaque é um componente GenericLink, que serve para renderizar um link na página HTML cujo valor do atributo href é definido arbitrariamente. O terceiro trecho é um componente For, usado para iterar em coleções de objetos. No nosso caso, utilizamos este componente para iterar entre as mensagens cadastradas no sistema. O componente For possui alguns atributos que devem ser fornecidos: element, source e value: O atributo element serve para indicar a tag HTML a ser renderizada para cada elemento da coleção a ser percorrido. Como estamos utilizando um <table> para listar as mensagens, então o atributo element é preenchido com o literal tr, o que significa que cada mensagem é renderizada em uma linha (tag <tr>) da tabela correspondente; O atributo source indica a propriedade através da qual a coleção de objetos é 17

acessível; Por fim, o atributo value indica a propriedade que irá guardar o objeto iterado no momento. Para ficar mais fácil de entender o funcionamento do componente For, veja o código Java mostrado na Listagem 14: public void iterar(list lista) { // 1 System.out.println( <ul> ); Iterator it = lista.iterator(); while (it.hasnext() { Object atual = it.next(); // 2 System.out.println( <li>objeto atual: + atual + </li> ); // 3 System.out.println( </ul> ); Listagem 14: Exemplo de iteração em uma coleção, em Java Fazendo um paralelo entre os trechos em negrito do código da Listagem 14 e os atributos do componente For da Listagem 13, o parâmetro do método iterar() é equivalente ao atributo source. A variável atual é equivalente ao atributo value. Finalmente, o <li> é equivalente ao atributo element. Continuando, crie a classe Home, dentro do pacote guestbook.pages. Esta classe irá conter o código necessário para implementar a lógica desejada para a página Home. O código da classe pode ser visto na listagem a seguir: package guestbook.pages; // imports public abstract class Home extends BasePage implements PageBeginRenderListener { @InjectObject("service:app.MessageManager") public abstract MessageManagerLocal getmessagemanager(); public abstract List<Message> getmessagelist(); public abstract void setmessagelist(list<message> list); public void pagebeginrender(pageevent pageevent) { setmessagelist(getmessagemanager().loadall()); A única coisa no código que não estamos habituados é o trecho em destaque. O método é anotado com @InjectObject, onde indicamos que o objeto a ser injetado é um serviço do HiveMind chamado MessageManager, declarado dentro do módulo app (isso é feito através do uso do prefixo service:). Caso não lembre, volte ao arquivo WEB INF/hivemodule.xml e veja que este serviço serve para obtermos uma instância do Stateless Session Bean MessageManager via JNDI. 18

Vamos agora rodar a aplicação, para ver se a página está funcionando conforme de acordo com as nossas necessidades: Ilustração 10: Lista de mensagens... vazia! Como não temos nenhum registro cadastrado, a lista de mensagens não foi exibida. Vamos inserir um registro manualmente, através das ferramentas fornecidas pelo NetBeans, para que possamos ver se tudo está funcionando. Selecione a guia Runtime, e localize o nosso banco de dados na lista (Ilustração 11). Ilustração 11: Trabalhando com bancos de dados no NetBeans Clique com o botão direito do mouse no banco de dados guestbook e selecione a opção Execute Command... Digite o código SQL mostrado na Listagem 15 e pressione o botão Run SQL, cuja localização pode ser vista na Ilustração 12. Ilustração 12: Botão para acionar a execução dos comandos SQL 19

update "APP"."SEQUENCE" set seq_count = 1; insert into "APP"."MESSAGE" values( 1, 'contato@danielfmartins.com', CURRENT_TIMESTAMP, 'Daniel F. Martins', 'Testing 1 2 3333') Listagem 15: Adicionando um registro de testes Vá até o browser e atualize a página. Veja o nosso novo registro sendo mostrado: Ilustração 13: Nosso registro sendo exibido na tela! Internacionalizando a página principal Para habilitar o mecanismo de internacionalização em uma página, basta criar um arquivo.properties com o mesmo nome da página em questão (e no mesmo local). Por exemplo, para a página Home, teríamos um arquivo Home.properties com as mensagens padrão. Para definir mensagens em português brasileiro, crie um arquivo chamado Home_pt_BR.properties. Para definir mensagens em inglês, crie um arquivo Home_en.properties. A mesma regra vale para outros idiomas. Vamos criar então um arquivo Home.properties, que irá conter as mensagens padrão. Este arquivo deve ser criado no mesmo local dos outros arquivos referentes à página Home. Depois de criado o arquivo, preencha o de acordo com o mostrado na Listagem 16: 20

# Home page messages application.title=guestbook application page.title=message list messages.empty=no messages found column.id=id column.date=date column.name=name column.email=email column.comment=comment page.newmessage=new message Listagem 16: Arquivo.properties com as mensagens Vamos alterar agora o arquivo Home.html, para que este faça uso das mensagens indicadas no arquivo Home.properties: <html> <head> <title> <span key="application.title">application title</span> </title> </head> <body> <h1><span key="application.title">application title</span></h1> <h2><span key="page.title">page title</span></h2> <form jwcid="form"> <table border="1" jwcid="showtable"> <tr> <th> <span key="column.id">id</span> </th> <th> <span key="column.date">date</span> </th> <th> <span key="column.name">name</span> </th> <th> <span key="column.email">email</span> </th> <th> <span key="column.comment">comment</span> </th> </tr> <tr jwcid="messagefor"> <td> <span jwcid="msgid">1</span> </td> <td> <span jwcid="msgdate">01/01/2006 23:56</span> </td> <td> <span jwcid="msgname">some people name</span> </td> <td> <a href="#" jwcid="msgemaillink"> 21

<span jwcid="msgemail">somemail@email.com</span> </a> </td> <td> <span jwcid="msgcomment">the comment goes here</span> </td> </tr> </table> </form> <h4 jwcid="nomessages"> <span key="messages.empty">no messages found</span> </h4> <a href="newmessage.html" jwcid="newmsglink"> <span key="page.newmessage">new message</span> </a> </body> </html> Listagem 17: Adicionando as mensagens no template Como podemos ver nos trechos em negrito, na Listagem 17, para exibir uma mensagem no template, utilizamos um elemento <span key= chave >xxxx</span>. Abaixo, uma outra forma de se obter o mesmo resultado, mesmo que de uma forma mais tediosa: <span jwcid= @Insert value= message:chave >Mensagem aqui</span> Certo. Rode a aplicação novamente e veja se tudo continua como estava. A grande diferença é que, agora, caso a aplicação precise ser localizada em um outro idioma, a coisa é facilmente implementada, bastando criar o arquivo.properties correspondente. Então, caso o usuário tenha configurado seu browser para um idioma diferente (e que sua aplicação suporte, claro), a página exibirá as mensagens naquele idioma automaticamente. Ciando a página de cadastro Beleza. Vou mostrar como criar a página de cadastro sem muitos rodeios, afinal já estamos acostumados com quase tudo que será utilizado. Crie um arquivo chamado NewMessage.html, no mesmo diretório onde a página Home está situada. Insira neste arquivo o código mostrado na Listagem 18: <html> <head> <title>application Title</title> </head> <body> <h1><span key="application.title">application title</span></h1> <h2><span key="page.title">page title</span></h2> 22

<span jwcid="haserrors"> <span key="message.error">errors found:</span> <ul> <span jwcid="fieldtracking"> <span jwcid="isinerror"> <li><span jwcid="error">some input error.</span> </span> </span> </ul> </span> <form jwcid="form"> <table> <tr> <td> <span jwcid="namelabel">name</span>: </td> <td> <input type="text" jwcid="name" /> </td> </tr> <tr> <td> <span jwcid="emaillabel">email</span>: </td> <td> <input type="text" jwcid="email" /> </td> </tr> <tr> <td> <span jwcid="commentlabel">comment</span>: </td> <td> <textarea jwcid="comment" cols="40"></textarea> </td> </tr> <tr> <td colspan="2" align="right"> <input type="button" jwcid="submit" value="message:submit" /> </td> </tr> </table> </form> <a href="home.html" jwcid="homelink"> <span key="page.home">home</span> </a> </body> </html> Listagem 18: Template da página de cadastro Agora, crie o arquivo de especificações da página, o NewMessage.page, no mesmo local do arquivo NewMessage.html. Coloque neste arquivo o código mostrado na Listagem 19: 23