Continuando minha busca por alternativas legais para geração automática de código usando templates encontrei na InfoQ o interessantíssimo projeto open source SPIDER On Rails, um plug-in Eclipse bastante customizável que possibilita a criação de aplicações completas em várias linguagens usando o Velocity (este vídeo mostra o SPIDER em ação). Resolvi, então, tentar aproveitar os mesmos templates Groovy que eu havia criado quando testei o code2code (veja o post anterior) para gerar um CRUD completo e poder ter uma visão comparativa das vantagens e desvantagens de cada ferramenta. Durante o processo tive o apoio do líder do projeto, para nosso orgulho um brasileiro. Bruno Braga, a quem sinceramente agradeço, tem sido extremamente acessível e vem ajudando muito, tendo inclusive incorporado algumas sugestões de melhoria apontadas (por exemplo, na próxima versão – ou em uma nightly build – também será possível usar templates Groovy ou FreeMarker).
Neste post vou mostrar como gerar código padrão Demoiselle usando o template que criei. Ao final, farei alguns comentários sobre as facilidades/dificuldades encontradas, apontando algumas dicas de quando usar o SPIDER ou code2code.
Passo 1 – Preparando o Ambiente / Criando/configurando um projeto Demoiselle
Siga os procedimentos indicados nos Passos 1 e 2 do post anterior, só que utilizando a versão 1.0.3 no archetype-webapp-sample. Ao final você terá criado o projeto mystore (package com.mycompany.mystore) com o banco de dados HSQLDB mystore executando no modo Server.
Dica: Se desejar utilizar uma versão mais atual do HSQLDB (a última estável é a 1.8.1.1) basta alterar o respectivo número na dependencia do POM.xml. O Maven aumaticamente se encarregará de baixá-la.
Passo 2 – Instalando o SPIDER on Rails
No Eclipse (que dever ter o WTP instalado) vá ao menu Help -> Software Updates, aba Available Software, clique no botão Add Site e informe http://www.j2eespider.org/update (J2EE Spider é o antigo nome do projeto). Marque a versão desejada (usei a 1.0.0.M4, a última informada) e escolha Install. Reinicie o Eclipse, caso solicitado. A partir daí, ao clicar com o botão direito no nome de qualquer projeto no seu Eclipse, aparecerá o menu SPIDER on Rails (Ctrl+Alt+E), que abrirá a tela do plugin.
Nota: A principal referencia que utilizei durante este trabalho (além do apoio de Bruno!) foi a seção Começando a Utilizar, no site do SPIDER. Existe também um vídeo que explica em detalhe o processo de instalação.
Passo 3 – Criando as Tabela no Banco de Dados
Vamos fazer o caminho inverso utilizado na geração com code2code. Partiremos das tabelas já criadas no banco de dados para que o SPIDER (na verdade, o HibernateTools integrado com ele) crie as classes de entidade já mapeadas. Para isso vamos usar o HSQL Database Manager, que vem no .jar do HSQLDB.
Execute o menu Run -> Run Configurations, clique com o botão direito em Java Application e escolha New. Em Name, coloque MyStoreDBConsole; em Main class, informe org.hsqldb.util.DatabaseManagerSwing. Na aba Arguments, campo Program arguments, informe: -driver org.hsqldb.jdbcDriver -url jdbc:hsqldb:hsql://localhost/mystore -user sa. Clique em Run e a janela do Database Manager será aberta.
Copie o comando SQL a seguir e clique em Executar (Ctrl+E). Observe no navegador do lado esquerdo que serão criadas as tabelas PRODUCT e CUSTOMER, cujas chaves primárias (ID) são geradas automaticamente.
CREATE TABLE PRODUCT
(ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
NAME VARCHAR(100),
PRICE DOUBLE,
QTY INTEGER);
CREATE TABLE CUSTOMER
(ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
NAME VARCHAR(100),
EMAIL VARCHAR(100));
Sua tela deverá estar como na figura abaixo:
Passo 4 – Usando o Template SPIDER para Demoiselle
Curiosidades: O exemplo de uso do SPIDER mostrado no vídeo (não deixe de ver, insisto!) gera uma aplicação Java para Web usando o framework brasileiro Mentawai. Precisei criar um template gerador de código no padrão Demoiselle. Em mãos eu tinha apenas os templates Groovy, criados para o code2code, que precisaria converter para Velocity (foi mais fácil do que imaginei!). Também usei como referência um Template Gerador de Código JSF criado pela Secretaria de Saúde do Ceará, me poupando de algumas dúvidas e problemas que eles passaram (essa é uma das maravilhas dos projetos de código aberto!). Em 2009, o projeto ganhou o 3o lugar no Prêmo Ceará de Cidadani@ Eletrônica, categoria Software Livre. Hoje o template foi doado ao projeto SPIDER On Rails e está no repositório com os devidos créditos aos autores.
Efetue o download do arquivo demoiselle-spider-template.zip e o descompacte em um diretório qualquer da sua máquina. Clique com o botão direito no projeto mystore e escolha a opção SPIDER On Rails. Sua tela aparecerá como na figura a seguir. Observe que você poderá utilizar os templates oficiais do SPIDER, atualizados automaticamente via web pelo plugin, ou escolher uma pasta específica. Ficaremos com a segunda opção, pelo menos até que o template Demoiselle também seja incorporado ao SPIDER! 😛
Passo 5 – Configurações Iniciais
Na Aba Config é possível selecionar a linguagem e o template desejados. Hoje temos apenas um template para a versão 1.0.6, mas futuramente poderíamos ter um para cada versão do Demoiselle, ou então templates para aplicações com características específicas. O uso da linguagem tem uma serventia bem interessante. Desde que os templates estejam preparados, é possível indicar por exemplo, se nomes de classes, métodos ou atributos seriam gerados em inglês ou português. Muito interessante para criar templates geradores de código no padrão de frameworks utilizados internacionalmente. Por simplicidade, preferi gerar todo o código em inglês, mas seria muito bom adaptar o template para fazer uso da internacionalização. Pode-se ainda configurar uma ferramenta de Merge (para administração de eventuais conflitos, quando o template for aplicado em código pré-existente) e as informações do banco de dados. Preencha as informações como na figura.
Na aba Package, configure o nome do pacote padrão como com.mycompany.mystore.
A aba Tech é utilizada para que o usuário possa escolher as tecnologias a serem utilizadas no projeto, de forma que o SPIDER consiga gerar (seguindo regras especificas no template) a estrutura de diretórios e todas as dependencias necessárias. A rigor, poderíamos até omitir esta aba, pois no Demoiselle este trabalho é feito na criação do projeto Maven usando o arquétipo demoiselle-archetype-webapp-sample. Contudo, a aba Mapping (que veremos mais adiante) exige que selecionemos o tipo de banco de dados. Como estamos usando o HSQLDB, selecione HypersonicSQL no campo Database Type.
Nota: Este é um ponto bem interessante do SPIDER. Aqui poderíamos colocar opções de utilização de outros componentes Demoiselle (como Segurança, Relatórios, Agendador de Tarefas), de forma a facilitar a vida do usuário adicionando automaticamente as dependencias no POM.xml do projeto.
A Aba Layout também não será usada, pois faremos a geração seguindo um padrão fixo. Esta é outra funcionalidade bem legal, que permite ao usuário uma ótima flexibilidade na hora de gerar suas aplicações. Uma boa oportunidade aqui seria criar e disponibilizar layouts de acordo com Skins específicos, conceito implementado pelo componente demoiselle-jsf-ui (ver Módulo 05 do Tutorial Demoiselle).
Passo 6 – Gerando a aplicação
A primeira coisa aqui é gerar as classes de entidade a partir das tabelas do banco, criadas no passo 3. Neste ponto o SPIDER não reiventa a roda e utiliza uma integração com o Hibernate Tools.
Abra a aba Mapping e selecione o pacote com.mycompany.mystore.bean, onde as classes serão geradas. Clique no botão build e observe a criação da pasta mapping em seu projeto. Da primeira vez não vão funcionar, pois precisamos fazer 2 ajustes:
- Abra o arquivo hibernate.cfg.xml da pasta mapping e apague o valor “sa” da propriedade hibernate.connection.password (mesmo usando uma senha em branco, fomos obrigados a colocar um valor na aba Config. Na próxima versão do SPIDER esse valor será opcional). Faça o mesmo com /main/resources/hibernate.cfg.xml, pois você já terá um arquivo de configuração Hibernate pronto para a correta execução da aplicação.
- Será preciso incluir o .jar do HSQLDB na pasta mapping/lib. Você poderá encontrá-lo no seu repositório local Maven (pois ele automaticamente já baixou o .jar quando você colocou o HSQLDB nas dependencias do projeto, no passo 1), em USER_HOME/.m2/repository/hsqldb/hsqldb. Ne exemplo, usei o hsqldb-1.8.0.1.jar.
Clique novamente no botão build. O SPIDER observará que o hibernate.cfg.xml foi alterado (nas pastas mapping e main/resources) e perguntará se desejamos gerar novamente. Escolha “Don’t Generate” para ambos, pois a nossa modificação deve prevalecer. Note que foram criados dois arquivos de log (1 para cada build) na pasta mapping e também as classes Product.java e Customer. java no package com.mycompany.mystore.bean.
Precisaremos ainda efetuar 3 alterações em cada uma das classes geradas. A primeira delas tirar o src.main.java do nome do package package src.main.java.com.mycompany.mystore.bean (não consegui resolver esse bug). Depois, é fazê-las implementar a interface IPojo, uma exigência da arquitetura do Demoiselle. Por fim, adicione a anotação @GeneratedValue em cada campo id, pois isto foi algo que o HibernateTools não conseguiu reconhecer automaticamente. Não se esqueça de resolver os Imports (Ctrls+Shift+O).
Nota: Pude notar que o HibernateTools bastante poderoso e customizável, portanto poderíamos tentar implementar um maior controle desta geraçaõ automática, por exemplo fazendo-o colocar as anotações antes de cada atributo e não antes de cada método Get, como você deve ter percebido que ele fez. Consulte a referencia da ferramenta para saber mais.
Passo 7 – Gerando CRUDs
Agora estamos pronto para gerar os CRUDs de Produto e Cliente. Acesse a aba CRUD by Mapping e selecione a classe Customer, que já deverá estar listada. Na direita selecione todos os atributos. Nos atributos, marque o id é uma chave (Key) e que é seu HTML Type é do tipo hidden. Os demais ficarão com tipo text. Abaixo, o campo CRUD Type só apresenta a opção default e o campo Module não está sendo utilizado. Fica tudo como está.
Observação: Não vamos escolher o tipo de CRUD, adicionar validadores nem mudar os tipos HTML dos campos, porque no momento o template que elaborei não dá suporte a essas ótimas funcionalidades. Esta é uma excelente oportunidade de contribuição!
Clique no botão build this crud e acompanhe a aplicação de todos os templates Velocity configurados. Serão gerados vários novos arquivos Java (DAO, Business Controler, Managed Beans, constantes de Navegação) e Web (páginas JSF para listagem, visualização e edição). Recomendo que você dê uma navegada pelas pastas e arquivos do projeto para melhor entendimento.
Vale destacar aqui uma funcionalidade muito interessante do SPIDER. O uso de incrementos com base em Expressões Regulares, permite incluir um pequeno trecho de código (incremento) em arquivos já existentes sem perder configurações e/ou customizações do desenvolvedor realizadas anteriormente. Isso permite, por exemplo, alterar conteúdo de classes, páginas e arquivos de propriedades, a cada geração de um novo CRUD (foi o que ocorreu com o main/resources/hibernate.cfg.xml, /main/webapp/WEB-INF/faces-config.xml e /main/webapp/public/templates/default.xhtml, dentre outros).
Exercício: Repita este passo se quiser gerar também o CRUD de Produtos. Seu projeto ficará como na figura:
Passso 8 – Executando a Aplicação
Antes de rodar, precisaremos alterar os arquivos /main/webapp/WEB-INF/faces-config.xml e /main/webapp/public/templates/default.xhtml gerados originalmente pelo arquétipo do Demoiselle, pois os incrementos a cada CRUD foram feitos corretamente, mas dentro de tags comentadas. Seu faces-config.xml deverá ficar assim:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<!-- Facelets Configuration-->
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
<managed-bean>
<managed-bean-name>customerMB</managed-bean-name>
<managed-bean-class>com.mycompany.mystore.view.managedbean.CustomerMB</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>productMB</managed-bean-name>
<managed-bean-class>com.mycompany.mystore.view.managedbean.ProductMB</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>customerMB</managed-bean-name>
<managed-bean-class>com.mycompany.mystore.view.managedbean.CustomerMB</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<navigation-case>
<from-outcome>customer_list</from-outcome>
<to-view-id>/private/pages/customer_list.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>customer_edit</from-outcome>
<to-view-id>/private/pages/customer_edit.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>customer_view</from-outcome>
<to-view-id>/private/pages/customer_view.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>customer_insert</from-outcome>
<to-view-id>/private/pages/customer_edit.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>product_list</from-outcome>
<to-view-id>/private/pages/product_list.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>product_edit</from-outcome>
<to-view-id>/private/pages/product_edit.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>product_view</from-outcome>
<to-view-id>/private/pages/product_view.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>product_insert</from-outcome>
<to-view-id>/private/pages/product_edit.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
O /main/webapp/public/templates/default.xhtml não precisaria ser alterado, mas a aplicação mostraria dois itens de menu (Menu_01 e Menu_02) sem a menor necessidade. Abra-o e exclua o trecho abaixo, deixando apenas os links para os menus Product e Customer.
<rich:toolBarGroup>
<h:commandLink value="Menu_01" title="Menu_01" onclick="javascript:alert('Menu_01')" />
</rich:toolBarGroup>
<rich:toolBarGroup>
<h:commandLink value="Menu_02" title="Menu_02" onclick="javascript:alert('Menu_02')" />
</rich:toolBarGroup>
Pronto, agora é só rodar a aplicação. Você pode fazer isso dentro do próprio eclipse, clicando com o botão direito no nome do projeto e escolhendo Run As -> Run On Server, ou então fazendo o deploy pelo Maven com Run As -> Maven Install, abrindo o browser e digitando http://localhost:8080/mystore. Navegue pela a aplicação, inclua, exclua e altere alguns registros para ver o funcionamento.
Considerações Finais
O SPIDER On Rails é um projeto relativamente maduro e em constante evolução. Seu líder, Bruno Braga, é bastante acessível e aceita muito bem as sugestões de melhoria. A criação de templates não é tão difícil, principalmente se partimos de algo já pronto. O mais complicado para mim foi aprender a usar corretamente as expressões regulares para promover os incrementos em arquivos existentes, mas aos poucos a gente vai pegando o jeito e fica mais fácil. Creio que o processo de escrever templates para o SPIDER mereça um post exclusivo uma hora dessas.
A geração automática de código costuma ser bastante criticada pela impossibilidade em se controlar a qualidade do que é produzido. O SPIDER permite uma grande flexibilidade para que deixemos o código do “nosso jeito” ou do “jeito da nossa organização”. Em comparação com o code2code, o SPIDER On Rails é mais completo e profissional, por isso também leva um pouco mais de tempo para aprender a criar/utilizar os templates. Ambos tem sua serventia; O desenvolvedor pode inclusive utilzá-los em conjunto, deixando para o SPIDER as tarefas mais rebuscadas, ficando o code2code com os templates mais simples. Acredito fielmente que vale o investimento em produzir templates que possam ser reutilizados e que aumentem signficativamente a produtividade do desenvolvedor.
Se você está usando (ou pretende usar) o Demoiselle, temos aqui um ponto de partida. Procurei indicar pontos de melhoria no decorrer do texto (e existem outros, como tipos de CRUD Mestre Detalhe, criação automática de Classes de Testes, uso de recursos Web 2.0/Ajax, e por aí vai). Sinta-se livre para criticar, propor, sugerir, usar e alterar o template aqui disponibilizado conforme a sua conveniência. Gostaria muito de obter feedback, portanto os comentários são muito bem-vindos. Até a próxima!