JavaEE + Wicket: o que eu estava esperando?

Este blog deixou de ser mantido, mas o autor continua escrevendo aqui. Não deixe de assinar o novo feed!

Wicket logoJá faz algum tempo que o framework Wicket agora se chama Apache Wicket. Esse processo todo de “graduação” do projeto Wicket para um projeto top level Apache demorou, mas o Wicket agora ocupa lugar de destaque junto a outros projetos importantes (como o Tapestry, Turbine, Struts, entre outros).

Já havia lido um pouco a respeito do Wicket por aí e confesso ter achado muito bom, principalmente comparado com algumas nojeiras que somos forçados a usar por aí. Mas, mesmo assim, eu nunca havia tentado criar um projeto qualquer para testar o Wicket.

Por esse motivo, essa semana eu montei uma aplicaçãozinha bem simples para tentar entender como o framework funciona. Adivinha o que fiz? Isso mesmo, um guestbook (meu hello world “web” favorito!).

Devo dizer que não fiquei nem um pouco surpreso com o resultado da experiência, pois, como já imaginava, encontrei um framework simples e intuitivo. A aplicação que estarei explicando neste post está disponível para download através da página de aplicações aqui do blog.

Infraestrutura

Este é um projeto Java EE 5 composto pelos seguintes componentes:

  • guestbook-ear
    • guestbook-ejb
      • Message: entidade persistente que representa as mensagens;
      • EJB MessageRepository: stateless session bean que serve para persistir e retornar mensagens do meio persistente;
    • guestbook-web
      • AddMessage: página para inclusão de mensagens;
      • MessageList: página que mostra a lista de mensagens cadastradas.

Utilizei o servidor de aplicações Glassfish v2-b58c e a implementação JPA Toplink. O banco de dados utilizado foi o MySQL 5.0.45. Tudo rodando em cima do SO Slackware 12 com Java 1.6.0u2. Utilizei também o Maven 2 para organizar a estrutura do projeto e, claro, o Wicket (versão 1.2.6).

Organizando o projeto

Embora o Maven tenha lá seus problemas, ainda é minha ferramenta preferida para criação e manutenção de um projeto Java qualquer. Em alguns minutos eu montei — usando alguns archetypes — a estrutura do projeto:

Estrutura de arquivos criados pelo Maven

Back-end

Não irei colar nenhum código relacionado ao back-end da aplicação pois isso pode ser facilmente encontrado em qualquer tutorial que ensine o básico sobre Java EE 5. Vamos focar na parte web! :P

Configurando o Wicket

Uma vez adicionado o Wicket como dependência no módulo guestbook-web, precisamos fazer algumas configurações para que o Wicket funcione.

Primeiramente, precisamos criar a classe de configuração:

  1.  
  2. package com.danielfmartins.guestbook;
  3.  
  4. // imports…
  5.  
  6. public class GuestbookApplication extends WebApplication {
  7.  
  8.     public Class getHomePage() {
  9.         return MessageList.class;
  10.     }
  11.  
  12.     @Override
  13.     protected void init() {
  14.         // algumas opções não muito "necessárias" aqui
  15.     }
  16. }
  17.  

Em seguida, devemos alterar o arquivo web.xml:

  1.  
  2. <web-app>
  3.     <!– … –>
  4.  
  5.     <servlet>
  6.         <servlet-name>HelloWorldApplication</servlet-name>
  7.         <servlet-class>
  8.             wicket.protocol.http.WicketServlet
  9.         </servlet-class>
  10.         <init-param>
  11.             <param-name>applicationClassName</param-name>
  12.             <param-value>
  13.                 com.danielfmartins.guestbook.GuestbookApplication
  14.             </param-value>
  15.         </init-param>
  16.         <load-on-startup>1</load-on-startup>
  17.     </servlet>
  18.     <servlet-mapping>
  19.         <servlet-name>HelloWorldApplication</servlet-name>
  20.         <url-pattern>/app/*</url-pattern>
  21.     </servlet-mapping>
  22.  
  23.     <!– … –>
  24. </web-app>
  25.  

Feito isso, o Wicket já está configurado para interceptar e tratar corretamente as requisições.

Página de listagem

A seguir podemos ver um exemplo de página Wicket. Qualquer semelhança com programação desktop não é mera coincidência:

  1.  
  2. package com.danielfmartins.guestbook.page;
  3.  
  4. // imports…
  5.  
  6. public class MessageList extends WebPage {
  7.  
  8.     @EJB(name="MessageRepositoryBean")
  9.     private MessageRepositoryRemote repository;
  10.  
  11.     public MessageList() {
  12.         List<Message> list = repository.getAll();
  13.  
  14.         add(new FeedbackPanel("feedback"));
  15.         add(new PageLink("addLink", AddMessage.class));
  16.  
  17.         WebMarkupContainer table = new WebMarkupContainer("table");
  18.         add(table);
  19.         table.setVisible(list.size() > 0);
  20.         table.add(new ListView("messages", list) {
  21.  
  22.             @Override
  23.             protected void populateItem(ListItem item) {
  24.                 Message msg = (Message) item.getModelObject();
  25.  
  26.                 item.add(new Label("date",
  27.                         Time.valueOf(msg.getCreatedAt().getTime()).elapsedSince().toString()));
  28.                 item.add(new Label("name", msg.getName()));
  29.                 item.add(new ExternalLink("email", "mailto:" + msg.getEmail(),
  30.                         msg.getEmail()).setVisible(msg.getEmail() != null));
  31.                 item.add(new ExternalLink("url", msg.getUrl(), msg.getUrl())
  32.                 .setVisible(msg.getUrl() != null));
  33.                 item.add(new Label("text", msg.getText()));
  34.             }
  35.         });
  36.     }
  37. }
  38.  

Não irei explicar tudo linha-a-linha. A idéia aqui é mostrar o quanto o modelo de desenvolvimento do Wicket é intuitivo, principalmente àqueles que já sabem desenvolver para desktop. Aqui, conseguimos criar páginas cuja lógica de apresentação fica totalmente isolada do template HTML, e, além disso, a página ganha uma característica mais “OO”.

Abaixo segue um trecho do template HTML dessa página:

  1.  
  2. <html>
  3. <body>
  4.     <span wicket:id="feedback">
  5.         Feedback messages
  6.     </span>
  7.  
  8.     <table border="1" wicket:id="table">
  9.         <tr>
  10.             <th>When</th>
  11.             <th>From</th>
  12.             <!– … –>
  13.         </tr>
  14.         <tr wicket:id="messages">
  15.             <td><span wicket:id="date">5 seconds</span></td>
  16.             <td><span wicket:id="name">Somebody’s name</span></td>
  17.             <!– … –>
  18.         </tr>
  19.     </table>
  20.     <p>
  21.         <a href="#" wicket:id="addLink">New message</a>
  22.     </p>
  23. </body>
  24. </html>
  25.  

Note que os atributos wicket:id referenciam os componentes instanciados na página mostrada anteriormente.

Quem já usou o Tapestry alguma vez na vida deve ter ficado desapontado ao usar frameworks como o Struts e JSF, principalmente pelo fato de que os templates Tapestry são visíveis em qualquer navegador e editor WYSIWYG; não é preciso nenhum editor especial para se conseguir ver como a página se parecerá. Bem, o Wicket nos dá essa facilidade.

Integrando o Wicket com o back-end

Para que o lookup do EJB com o uso das anotações do Java EE 5 funcione, precisamos instalar uma extensão especial. Infelizmente, não a encontrei pronta para download a partir de um repositório Maven e, por este motivo, foi preciso baixar o JAR do site e fazer a instalação manualmente no repositório local:

  1.  
  2. public class GuestbookApplication extends WebApplication {
  3.  
  4.     // …
  5.  
  6.     @Override
  7.     protected void init() {
  8.         addComponentInstantiationListener(new JavaEEComponentInjector(this));
  9.     }
  10. }
  11.  

Página de inclusão

Aqui temos um formulário que serve para registrar uma mensagem digitada pelo usuário. O formulário possui algumas regras de validação, fazendo uso inclusive de um validador customizado que montei para validar o campo URL:

  1.  
  2. package com.danielfmartins.guestbook.page;
  3.  
  4. // imports…
  5.  
  6. public class AddMessage extends WebPage {
  7.  
  8.     @EJB(name="MessageRepositoryBean")
  9.     private MessageRepositoryRemote repository;
  10.  
  11.     public AddMessage() {
  12.         add(new FeedbackPanel("feedback"));
  13.         add(new MessageForm("form"));
  14.         add(new PageLink("listLink", MessageList.class));
  15.     }
  16.  
  17.     private class MessageForm extends Form {
  18.         private Message msg = new Message();
  19.  
  20.         public MessageForm(String id) {
  21.             super(id);
  22.             setModel(new CompoundPropertyModel(msg));
  23.             add(new RequiredTextField("name"));
  24.             add(new TextField("email").add(EmailAddressPatternValidator.getInstance()));
  25.             add(new TextField("url").add(URLPatternValidator.getInstance())); // custom validator
  26.             add(new TextArea("text").setRequired(true));
  27.         }
  28.  
  29.         @Override
  30.         protected void onSubmit() {
  31.             repository.add(new Message(msg));
  32.             getSession().info("Message added"); // flash-scoped feedback message
  33.             setResponsePage(MessageList.class); // redirect-after-post
  34.         }
  35.     }
  36. }
  37.  

O validador URLPatternValidator usado no código não existe no Wicket, mas sua criação é bem trivial. Não mostrarei o código aqui, portanto, se houver interesse, baixe o projeto e veja como tudo foi feito e estruturado.

Resultado

Algumas screenshots da aplicação em execução:

Formulário de inclusão com erros de validação Listagem de mensagens

Conclusão

Num mundo ideal, eu utilizaria o Grails sempre que possível. No entanto, atualmente isso significa nunca (a não ser em projetos pessoais). Mas nem tudo está perdido, pois o Wicket é uma excelente alternativa de framework web, principalmente quando o comparamos com frameworks mainstream como o Struts e… aquele que você sabe qual.

Para quem pensa que o Wicket é ruim em termos de comunidade, em setembro de 2006 foi publicado o livro Pro Wicket. As mailing lists do projeto são movimentadas e os usuários (e desenvolvedores) do Wicket são muito prestativos. Agora que a Apache promoveu o framework como top level project, é possível que esteja rolando um esforço maior na parte de documentação do projeto, que está bem melhor do que da última vez que vi.

Não há motivos para não dar uma experimentada no Wicket… vai que você gosta? :D

Tags: , , , , , ,