domingo, 5 de janeiro de 2014

Geradores de Código em Java - Otimize seu tempo, Economize Dinheiro e Melhore sua Qualidade - Parte 5

Comentários para Colunas Chave Estrangeira


O comentário para coluna chave estrangeira obedece a seguinte estrutura <NOME_ATRIBUTO_JAVA>:<NOME_NA_TELA>:<OPERADOR_PESQUISA>:<CAMPO_MOSTRADO_NA_COMBO>:<TIPO_COMBO_OU_LUPA>:<REPORT>:<TABELA_AUTOCOMPLETE>, em que:
  • NOME_TABELA - é o nome da tabela no banco de dados;
  • NOME_COLUNA - é o nome da coluna;
  • NOME_ATRIBUTO_JAVA - é o nome que será usado como atributo no Java;
  • NOME_NA_TELA - é o nome que será apresentado nas telas do Sistema;
  • OPERADOR_PESQUISA - é o operador de pesquisa desejado
  • CAMPO_MOSTRADO_NA_COMBO - campo mostrado na combo
  • TIPO_COMBO_OU_LUPA - deve ser informado o tipo de relacionamento com a tabela relacionada. Os valores podem ser combo ou lupa.

No exemplo mostrado abaixo é apresentado um tipo combo gerado a partir do comentários “projeto:Projeto:=:descricao:combo”.

 Ilustração 9: Campo Gerado para Coluna Chave Estrangeira

Exemplo de Código Gerado

Uma vez criado o template, todos os códigos serão gerados da mesma forma e sem erros, e qualquer alteração ou evolução pode ser feita no template e isto permitirá que os novos códigos gerados sigam o novo padrão. Abaixo é mostrado parte de um código gerado.

package gov.tjpr.gen.entity;

import gov.tjpr.entity.PersistableEntity;
import javax.persistence.*;
import java.text.Normalizer;
import java.util.Date;

@Entity
@Table(name="tbatividade", schema="public")

@SequenceGenerator(name = "SEQUENCE", sequenceName="public.tbatividade_idatividade_seq", allocationSize=1)
public class Atividade implements PersistableEntity<Integer>{

private static final long serialVersionUID = 1L;

@ManyToOne
@JoinColumn(name = "idprojeto")
private Projeto projeto;
@ManyToOne
@JoinColumn(name = "idrecurso")
private Recurso recurso;
@ManyToOne
@JoinColumn(name = "idtipoatividade")
private TipoAtividade tipoAtividade;
@Column(name="data")
private Date data;
@Column(name="qtdhora")
private Double qtdHora;
@Column(name="descricao")
private String descricao;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQUENCE")
@Column(name="idatividade")
private Integer id;
// GETTERS AND SETTERS
...
}

Quadro 3: Exemplo de Código Gerado a partir do Banco de Dados e Template

Considerações finais

Conclui-se que a geração de código permite diminuir muito o tempo de desenvolvimento, melhorar a qualidade do software, reservar tempo para atividades mais nobres e desafiadoras, padronizar o código e diminuir a curva de conhecimento de novos funcionários. Todos estes elementos contribuem para a diminuição de custos e tempo de entregas de projetos dentro das empresas.
Um gerador de código customizado vai ao encontro das tecnologias legadas e novas de uma grande empresa permitindo independência em relação a um fornecedor, diminuindo os custos de aquisição e treinamento caso fosse adquirido um gerador de mercado.
Além disso, a estrutura genérica de classes apresentadas, são de livre acesso e sem custos, com funcionalidades bem definidas que são suficientes para gerar códigos muito sofisticados como apresentados neste trabalho.

Referências bibliográficas

AMBLER, S.W. Mapping Objects to Relational Databases. An AmbySoft Whitepaper. AmbySoft Inc. 1997. Disponível em: <http://www.agiledata.org/essays/mappingObjects.html>. Acesso em: 24 abril 2012.

AMBLER, Scott. Agile Modeling: Effective Practices for eXtreme Programming and
the Unified Process. WILEY COMPUTER PUBLISHING, 2002.

HERRINGTON, Jack. Code Generation in Action. MANNING, 2003.

SCHVEPE, CLAUDIO. GERADOR DE CÓDIGO JAVA A PARTIR DE ARQUIVOS DO ORACLE FORMS 6I. 2006. Trabalho de Conclusão de Curso de Ciência da Computação, Universidade Regional de Blumenau, Blumenau. Disponível em: <http://www.bc.furb.br/docs/MO/2008/330687_1_1.PDF>. Acesso em: 29 março 2012.

Geradores de Código em Java - Otimize seu tempo, Economize Dinheiro e Melhore sua Qualidade - Parte 4

 Ilustração 5: Diagrama de Classes do Gerador

Neste momento, o velocity combina os objetos com os templates e gera um texto, que é a armazenado em forma de arquivo obedecendo a estrutura de pacotes. Se for necessário a inclusão de mais arquivos gerados, basta criar o template e defini-lo dentro da pasta correspondente a sua equipe. A atual estrutura gera os seguintes arquivos:
  • Entidade – classe de negócios;
  • DAO – interface da classe de persistência;
  • DAOImpl – implementação da classe de persistência;
  • Service – interface da classe de serviço;
  • ServiceImpl – implementação da classe de serviço;
  • Form – classe que representa os campos do formulário da interface web do struts;
  • Action – classe do struts que recebe a submissão de formulários da web, ou funcionalidades acionadas;
  • Cadastro JSP – tela de cadastro usando Java Server Pages;
  • Pesquisa JSP – tela de pesquisa em Java Server Pages;
  • Pesquisa Popup JSP – tela de pesquisa popup em Java Server Pages;
  • Tela de Detalhe Consulta – tela de consulta sem alteração em Java Server Pages;
  • Arquivo de Configuração - um arquivo com todas as alterações dos arquivos de configuração: applicationContext.xml, validation.xml, struts-config.xml, tiles-definitions.xml, ApplicationResources.properties, menu.jsp, report-views-xml.
  • Relatório – o relatório da classe padrão
 Ilustração 6: Saída do Gerador
Como observado no exemplo, foi gerado para uma única tabela, 5265 linhas de código ou 189925 caracteres sem erros de compilação e execução. Mesmo para estruturas mais complexas o tempo de implementação se torna muito menor.

Template de Geração


Após definido o padrão para todos os artefatos de codificação da equipe/empresa, é necessário trocar valores variáveis para a linguagem do velocity. No exemplo abaixo, o nome do sistema foi substituído por ${entity.getSystem()}, através da biblioteca do velocity esta variável será substituída pelo nome do sistema, neste caso, por evep. Com esta tecnologia também é possível fazer laços. Um exemplo de laço é $foreach ($attribute in ${entity.getAttributeList()}) que irá percorrer e gerar todos os atributos da classe de negócios do sistema. 

package gov.tjpr.${entity.getSystem()}.entity;

import gov.tjpr.entity.PersistableEntity;
import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name="${entity.getTableName()}", schema="${entity.getSchema()}")

#foreach ($attributePk in ${entity.getPrimaryKey().getPkAttributeList()})
#if (${attributePk.getType().equals("Integer")})
@SequenceGenerator(name = "SEQUENCE", sequenceName="${entity.getSchema()}.${entity.getTableName().toLowerCase()}_${attributePk.getColumnName().toLowerCase()}_seq", allocationSize=1)
#end
#end
public class ${entity.getClassName()} implements PersistableEntity#foreach($attributePk in ${entity.getPrimaryKey().getPkAttributeList()})<${attributePk.getType()}>#end
{
  private static final long serialVersionUID = ${pSerialEntidade};
#foreach ($attribute in ${entity.getAttributeList()})
#if (${attribute.isPrimaryKey()})
@Id
#if (${attribute.getType().equals("Integer")})
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQUENCE")
#end
@Column(name="${attribute.getColumnName()}")
  private ${attribute.getType()} ${attribute.getName()};
#elseif (${attribute.isForeignKey()})
@ManyToOne
@JoinColumn(name = "${attribute.getColumnName()}")
  private ${attribute.getForeignKey().getEntityPk().getClassName()} ${attribute.getName()};
#else
  @Column(name="${attribute.getColumnName()}")
  private ${attribute.getType()} ${attribute.getName()};
#end
#end
// GETTERS AND SETTERS
...
}

Quadro 2: Template para Geração de Classe do Padrão Modelo

METAINFORMAÇÃO DAS TABELAS


Para enriquecer a geração de códigos, são colocadas informações adicionais nas tabelas, colunas que são chave estrangeiras e colunas que não são chaves estrageiras.

Comentários em nível de tabela


O comentário em nível de tabela obedece a seguinte estrutura <NOME_CLASSE_JAVA>:<NOME_NA_TELA>:<PROPRIEDADE_MOSTRADA_COMBO>, em que:
  • NOME_TABELA - é o nome da tabela no banco de dados;
  • NOME_CLASSE_JAVA - é o nome da classe referente a esta tabela que será criada no Java;
  • NOME_NA_TELA- é o nome que irá ser mostrado nas telas do Sistema;
  • PROPRIEDADE_MOSTRADA_COMBO - é o campo que será utilizado por todas as demais tabelas (em formato de combo ou lupa) que estiverem relacionadas a esta. No exemplo abaixo a entidade Atividade possui uma combo “Nome do Recurso” onde é apresentada a lista de Recursos representados pelo seu nome.

Exemplo:
Recurso:Recurso:nome

 Ilustração 7: Uso do Comentário na Tabela

Comentários para Coluna que não é Chave Estrangeira


O comentário para coluna não chave estrangeira obedece a seguinte estrutura <NOME_ATRIBUTO_JAVA>:<NOME_NA_TELA>:<OPERADOR_PESQUISA>:<OPCOES>:<SEM_ACENTO>:<REPORT>:<TABELA_AUTOCOMPLETE>, em que:
  • NOME_TABELA - é o nome da tabela no banco de dados;
  • NOME_COLUNA - é o nome da coluna;
  • NOME_ATRIBUTO_JAVA - é o nome que será usado como atributo no Java;
  • NOME_NA_TELA - é o nome que será apresentado nas telas do Sistema;
  • OPERADOR_PESQUISA - é o operador de pesquisa desejado
  • OPCOES - deve ser criado no formato <CHAVE1=VALOR1>;<CHAVE2=VALOR2>. É utilizado para combo quando a mesma não estiver vinculada a uma tabela e possui valores fixos. Aplicado somente a campos dos tipos VARCHAR e CHAR.
  • TABELA_AUTOCOMPLETE - é o nome da tabela onde serão buscados os dados para autocomplete.
Usando o seguinte comentário “sexo:Sexo:=:F=Feminino;M=Masculino” para o campo sexo o gerador constrói a combo mostrado no exemplo abaixo:


Geradores de Código em Java - Otimize seu tempo, Economize Dinheiro e Melhore sua Qualidade - Parte 3

ESTRUTURA DO PROCESSO DE GERAÇÃO



O seguinte fluxo é determinado neste processo de geração. O programa gerador busca as informações contidas na base de dados, carrega uma série de classes, mescla estas classes com os templates definidos na empresa e gera os arquivos de saída. Isto torna o gerador independente de tecnologia, pois os templates são definidos pela empresa ou mesmo uma equipe dentro da empresa. As classes carregadas são informações sobre todas as tabelas, relacionamentos e metainformações. A partir dos métodos destas classes é possível criar templates de acordo com a tecnologia da equipe/empresa de modo simples e rápido.

 Ilustração 2: Esquema Processo de Geração

Detalhamento do Processo do Geração


O gerador utiliza a tecnologia java DatabaseMetaData, esta tecnologia acessa a estrutura de tabelas de vários bancos de dados independentemente de tecnologia, para obter de forma independente as informações da estrutura da base de dados relacional, inclusive os comentários que possuem metainformações para enriquecer a geração.
Para criar independência entre equipes, o sistema possui uma separação em pastas para que cada equipe possa criar seus templates, permitindo customização mesmo dentro de uma única empresa.
No Tribunal de Justiça do Estado do Paraná, foi criado três pastas, como ilustrado na figura abaixo. A pasta padrao_criminal obedece o padrão da equipe que cuida dos sistemas criminais, pasta padrao_projudi pertence ao sistemas cíveis e o pasta novos_projetos são para novos projetos dentro do Tribunal.
Além disso, podem ser criadas quantas pastas forem necessárias, de acordo com as especificidades de tecnologias de sua empresa/equipe.
Para que se faça a geração, é necessário que se informe os seguintes parâmetros:
 Ilustração 3: Pasta de Templates
  • Lista de Tabelas – nomes das tabelas que serão geradas;
  • Pasta da Geração – nome do diretório onde será salvo os arquivos gerados;
  • URL – URL de conexão do banco de dados. Exemplo: jdbc:postgresql://postgres-dev:5432/evep;
  • Usuário do Banco – usuário de conexão com o banco de dados
  • Senha – senha de conexão com o banco de dados;
  • Driver – driver do banco de dados
  • Esquema – esquema onde a base de dados foi criado
  • Pasta do Template – como explicado acima, qual conjunto de templates serão utilizados
  • Novo Projeto – indica se o projeto é novo ou não. Quando o sistema é novo, além das classes geradas ele monta um ambiente completo para que o sistema rode sem problemas.
  • Alterar arquivos de configuração – indica que o gerador pode alterar diretamente todos os arquivos de configuração.
Boa parte dos parâmetros são necessários apenas para se ter uma conexão com o banco de dados, senão seria bem menor o número de parâmetros, o que torna bem fácil o uso do gerador, que é a característica “Facilidade de utilização” definidas por Ambler (AMBLER, 2002. pag. 113) .

 Ilustração 4: Parâmetros de Entrada

O gerador com base nestes parâmetros, obtém as informações da base de dados e carrega a estrutura de classes mostrada abaixo. Depois que isto ocorre, usando a tecnologia velocity é possível mesclar o template com os objetos carregados. Dentro do template pode-se acessar várias informações, entre elas:
  • Nome da tabela - através do método entity.getTableName();
  • Nome da classe Java – através do método entity.getClassName();
  • Nome do título da tela – através do método entity.getViewName();
  • Se a coluna é chave estrangeira – através do método attribute.isForeignKey();
  • O domínio de uma coluna – através do método attribute.getListOption();
  • O tamanho do campo – através do método attribute.getLength();
  • Se a coluna fará parte do relatório – através do método attribute.isReport();
  • Se a coluna não é um campo obrigatório – através do método attribute.isAllowNull();
  • O nome da classe que está relacionada com a coluna chave estrangeira – attribute.getForeignKey().getEntityPk().getClassName();
  • O atributo que representa a classe, ou seja, aquela que é apresentada em uma comboentity.getLookupAttribute()