Pós-Graduação em Ciência da Computação
“XO2 – UM GERADOR DE CÓDIGO MDA BASEADO
EM MAPEAMENTOS DE MODELOS”
Por
João Paulo Augusto de Oliveira Ferreira
Dissertação de Mestrado
Universidade Federal de Pernambuco
[email protected]
www.cin.ufpe.br/~posgraduacao
RECIFE, OUTUBRO/2005
UNIVERSIDADE FEDERAL DE PERNAMBUCO
CENTRO DE INFORMÁTICA
PÓS-GRADUAÇÃO EM CIÊNCIA DA COMPUTAÇÃO
JOÃO PAULO AUGUSTO DE OLIVEIRA FERREIRA
“XO2 – UM GERADOR DE CÓDIGO MDA BASEADO EM
MAPEAMENTOS DE MODELOS"
ESTE TRABALHO FOI APRESENTADO À PÓS-GRADUAÇÃO EM
CIÊNCIA DA COMPUTAÇÃO DO CENTRO DE INFORMÁTICA DA
UNIVERSIDADE FEDERAL DE PERNAMBUCO COMO REQUISITO
PARCIAL PARA OBTENÇÃO DO GRAU DE MESTRE EM CIÊNCIA DA
COMPUTAÇÃO.
ORIENTADOR(A): Roberto Souto Maior Barros
RECIFE, OUTUBRO/2005
Ferreira, João Paulo Augusto de Oliveira
X02 – Um gerador de código MDA baseado em
mapeamentos de modelos / João Paulo Augusto de
Oliveira Ferreira. – Recife : O Autor, 2005.
xx, 108 folhas : il., fig., tab.
Dissertação (mestrado) – Universidade Federal de
Pernambuco. CIn. Mestrado em Ciência da
Computação, 2005.
Inclui bibliografia e apêndice.
1. Sistema – Geração de código – Ambiente XO2.
2. Arquitetura de sistemas (MDA). 3. Padrão XMI. 4.
Mapeamento de modelos. I. Título.
004.4’24
005.13
CDU (2.ed.)
CDD (22.ed.)
UFPE
BC2006-045
Aos meus pais e avós pela educação, incentivo e compreensão.
AGRADECIMENTOS
A todos que me ajudaram ao longo deste trabalho. Aos meus amigos e familiares. Aos professores Roberto e Décio. Ao professor Zeque e amigos do SIG@.
vii
Never send a human to do a machine’s job.
— AGENT SMITH, THE MATRIX
RESUMO
Atualmente, devido às exigências do mercado e à grande competitividade, as empresas precisam
desenvolver sistemas de informação com qualidade e dentro de prazos cada vez mais curtos.
Neste cenário, este trabalho apresenta o ambiente XO2 , que possibilita gerar grande parte do
código-fonte de um sistema de informação orientado a objetos.
O ambiente utiliza transformação de modelos com base na arquitetura MDA - Model Driven
Architecture. Também propõe um documento para mapeamento de modelos e uma interface
gráfica para auxiliar no processo de criação dos documentos e geração de código.
O XO2 foi validado em um estudo de caso para substituição da camada de persistência do
SIG@UFPE e mostrou-se capaz de aumentar a qualidade e consistência do código gerado, elevar
o nı́vel de abstração através da separação bem definida de papéis e responsabilidades proposta
pela arquitetura MDA. Finalmente, o ambiente foi capaz de aumentar a produtividade do
projeto pela redução de esforço na realização de tarefas repetitivas.
Palavras-chave: geração de código, MDA, XMI, mapeamento de modelos.
xi
ABSTRACT
Nowadays, companies need to provide high quality products and services within short periods of time. In this scenario, this work presents XO2 , a code generation environment, based
on the MDA - Model Driven Architecture, which is aimed to automatically generating large
parts of the implementation code of object-oriented software using model mappings and model
transformations.
The tool uses the MDA - Model Driven Architecture and proposes a markup language
to represent model mappings and an user interface to help the documents creation and code
generation activities.
The XO2 tool was tested against a real case and prove its capacity to increase the generated
code quality and consistency, increase the abstraction through the separation of concerns defined
by the MDA. Finally, the tool increased the project overall productivity by reducing the amount
of work spent on repetitive tasks.
Keywords: code generation, MDA, XMI, model mapping.
xiii
SUMÁRIO
Capı́tulo 1—Introdução
1.1
1.2
1.3
1
Por que gerar código? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Estrutura da Dissertação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Capı́tulo 2—Geração de Código: Conceitos, Padrões e Tecnologias
2.1
2.2
Conceitos . . . . . . . . . . . . . . . . . . .
Geração de Código . . . . . . . . . . . . . .
2.2.1 Modelos de Geradores de Código . .
2.2.2 Tipos de Geradores de Código . . .
2.2.2.1 Code Munger . . . . . . . .
2.2.2.2 Inline Code Expander . . .
2.2.2.3 Mixed Code . . . . . . . .
2.2.2.4 Partial Class Generator . .
2.2.2.5 Tier Generator . . . . . . .
2.2.3 Fluxo de desenvolvimento . . . . . .
2.3 Mapeamento OO-Relacional . . . . . . . . .
2.4 Padrões OMG - Object Management Group
2.4.1 MOF . . . . . . . . . . . . . . . . .
2.4.2 XMI . . . . . . . . . . . . . . . . . .
2.5 JMI . . . . . . . . . . . . . . . . . . . . . .
2.6 MDR . . . . . . . . . . . . . . . . . . . . . .
2.7 MDA . . . . . . . . . . . . . . . . . . . . . .
2.7.1 PIM - Plataform Indepent Model . .
2.7.2 PSM - Platform Specific Model . . .
2.7.3 Código-Fonte . . . . . . . . . . . . .
2.7.4 Transformações . . . . . . . . . . . .
2.8 Velocity . . . . . . . . . . . . . . . . . . . .
2.9 Hibernate . . . . . . . . . . . . . . . . . . .
2.10 Conclusões . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Capı́tulo 3—Trabalhos Relacionados
3.1
3.2
3.3
XDoclet . . .
3.1.1 Pontos
AndroMDA .
3.2.1 Pontos
iQgen . . . .
3.3.1 Pontos
. . . . . . .
Relevantes
. . . . . . .
Relevantes
. . . . . . .
Relevantes
.
.
.
.
.
.
1
3
3
5
6
6
7
7
8
9
9
10
11
12
13
13
16
19
20
20
22
22
23
23
24
25
26
29
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
xv
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
29
32
33
35
35
39
xvi
SUMÁRIO
3.4
3.5
3.6
e-Gen . . . .
3.4.1 Pontos
Qualiti Coder
3.5.1 Pontos
Conclusões .
. . . . . . .
Relevantes
. . . . . . .
Relevantes
. . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
40
41
42
42
42
Capı́tulo 4—XO2 - Um gerador de código MDA baseado em mapeamentos de modelos 45
4.1
4.2
4.3
4.4
4.5
4.6
Visão Geral . . . . . . . . . . . . . . . . . . . .
Arquivos de Entrada . . . . . . . . . . . . . . .
4.2.1 O Diagrama de Classes . . . . . . . . .
4.2.2 O Template Velocity/XO2 . . . . . . . .
4.2.3 O Mapeamento de Modelos . . . . . . .
Arquitetura das Classes XO2 . . . . . . . . . .
4.3.1 O pacote xo2 . . . . . . . . . . . . . . .
4.3.2 O pacote gui . . . . . . . . . . . . . . .
4.3.3 O pacote uml . . . . . . . . . . . . . . .
4.3.4 O pacote mapping . . . . . . . . . . . .
4.3.5 O pacote util . . . . . . . . . . . . . .
Bibliotecas Utilizadas . . . . . . . . . . . . . .
O processo de desenvolvimento com o XO2 . .
4.5.1 Criação do Modelo Orientado a Objetos
4.5.2 Criação do Documento de Mapeamentos
4.5.3 Criação dos Templates . . . . . . . . . .
4.5.4 Geração do Código-fonte . . . . . . . . .
Conclusões . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Capı́tulo 5—Testes e Resultados
5.1
5.2
5.3
5.4
Gerando código para sites da web . . .
Gerando arquitetura em camadas para
Resultados . . . . . . . . . . . . . . . .
Conclusões . . . . . . . . . . . . . . .
75
.
o
.
.
. . . . . . . . . . . .
projeto SIG@UFPE
. . . . . . . . . . . .
. . . . . . . . . . . .
Capı́tulo 6—Conclusões
6.1
6.2
45
46
46
47
53
58
58
59
60
66
69
71
72
72
72
73
73
74
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
75
84
95
97
99
Contribuições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Trabalhos Futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Apêndice A—VTL - Velocity Template Language
103
LISTA DE FIGURAS
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
2.13
2.14
2.15
2.16
2.17
2.18
2.19
2.20
2.21
2.22
2.23
Funcionamento de um gerador de código ativo . . . . . . . . . . . . . . .
Funcionamento de um gerador de código passivo . . . . . . . . . . . . .
Funcionamento de um gerador de código do tipo Code Munger . . . . .
Funcionamento do Javadoc . . . . . . . . . . . . . . . . . . . . . . . . .
Funcionamento de um gerador de código do tipo Inline Code Expander .
Funcionamento de um gerador de código Mixed Code . . . . . . . . . . .
Funcionamento de um gerador de código Partial Class . . . . . . . . . .
Funcionamento de um gerador de código do tipo Tier . . . . . . . . . . .
Gerador de código Tier para aplicação J2EE . . . . . . . . . . . . . . . .
Fluxo de desenvolvimento convencional . . . . . . . . . . . . . . . . . . .
Fluxo de desenvolvimento com gerador de código . . . . . . . . . . . . .
Representação da linguagem XML em MOF . . . . . . . . . . . . . . . .
Principais elementos do padrão MOF . . . . . . . . . . . . . . . . . . . .
Representando uma classe em XMI . . . . . . . . . . . . . . . . . . . . .
Representação das classes Carro e Pessoa . . . . . . . . . . . . . . . . .
Representação da classe Carro . . . . . . . . . . . . . . . . . . . . . . . .
Visão geral dos principais elementos da linguagem UML . . . . . . . . .
Ciclo de Desenvolvimento Tradicional do RUP . . . . . . . . . . . . . .
Ciclo de Desenvolvimento MDA . . . . . . . . . . . . . . . . . . . . . . .
Transformações MDA . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Transformações MDA . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Padrão MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
7
8
8
8
9
10
10
11
12
12
15
16
17
17
18
20
21
22
23
23
24
26
3.1
3.2
3.3
3.4
Diagrama de classes UML . . . . . . . .
Interface gráfica do iQgen . . . . . . . .
Interface gráfica do e-Gen Modeler . . .
Interface gráfica do e-Gen Design Portal
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
30
36
40
41
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
4.10
4.11
Visão Geral do XO2 . . . . . . . . . . . . . . .
Diagrama UML . . . . . . . . . . . . . . . . . .
Mapeamentos . . . . . . . . . . . . . . . . . . .
Principais elementos do mapeamento M3 L . . .
Diagrama UML com herança . . . . . . . . . .
Principais pacotes do ambiente XO2 . . . . . .
O pacote XO2 . . . . . . . . . . . . . . . . . . .
A interface gráfica de mapeamento de modelos
A interface gráfica de geração de código . . . .
A interface XO2lement . . . . . . . . . . . . . .
A classe XO2Package . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
46
48
53
54
56
58
59
60
61
61
62
xvii
.
.
.
.
.
.
.
.
.
.
.
.
xviii
LISTA DE FIGURAS
4.12
4.13
4.14
4.15
4.16
4.17
4.18
4.19
4.20
A interface XO2Classifier . . . . . . . . . . . . . . . . . . .
A classe XO2Method . . . . . . . . . . . . . . . . . . . . . .
Classes que representam os relacionamentos . . . . . . . . .
Estrutura de um documento XMI . . . . . . . . . . . . . . .
O pacote mapping . . . . . . . . . . . . . . . . . . . . . . .
Mapeamento Classe/Tabela. . . . . . . . . . . . . . . . . . .
Principais componentes externos e apis utilizados pelo XO2
Etapas do processo de geração de código do XO2 . . . . . .
Inserção do XO2 no processo de desenvolvimento tradicional
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
63
65
65
66
67
71
72
73
5.1
5.2
5.3
5.4
5.5
5.6
5.7
Documentos responsáveis pelo cadastro
Modelo de projeto . . . . . . . . . . . .
Tela de atualização produzida pelo XO2
Os subsistemas do sistema SIG@UFPE .
A distribuição do sistema SIG@UFPE .
Arquitetura em camadas do SIG@UFPE
Representação UML da classe Prédio . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
76
76
84
85
85
87
88
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
LISTA DE TABELAS
2.1
Arquitetura MOF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.1
3.2
3.3
3.4
3.5
3.6
Pontos relevantes ao uso do XDoclet . . . . . . . .
Pontos relevantes ao uso do AndroMDA . . . . . .
Pontos relevantes ao uso do iQgen . . . . . . . . .
Pontos relevantes ao uso do e-Gen . . . . . . . . .
Pontos relevantes ao uso do Qualiti Coder . . . . .
Principais caracterı́sticas dos ambientes analisados
4.1
Pontos relevantes ao uso do XO2 . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
5.1
Tempo de desenvolvimento (em horas) com e sem ambiente XO2 . . . . . . . . . 96
6.1
Comparativo entre o XO2 e outros ambientes . . . . . . . . . . . . . . . . . . . . 100
xix
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
32
35
39
42
43
43
CAPÍTULO 1
INTRODUÇÃO
Na era da informação, em um cenário de grande competitividade, a sobrevivência de uma
empresa depende principalmente da qualidade de seus produtos e serviços, da agilidade na
resolução de problemas, e da satisfação de seus clientes. As empresas são obrigadas a implantar
modelos de qualidade, automatizar seus processos, e obviamente investir na aquisição e/ou no
desenvolvimento de sistemas de informação que atendam às suas demandas.
Neste contexto, onde um sistema de informação pode ser um diferencial e também uma
arma competitiva, o processo de construção do sistema passa a ser estratégico e, como tal,
necessita seguir critérios rı́gidos de qualidade e diversos outros fatores que pertencem ao escopo
da engenharia de software.
A engenharia de software, por sua vez, procura adaptar práticas bem-sucedidas de outras
engenharias no contexto de criação de sistemas, o que motiva pesquisas em torno de assuntos
como reuso de componentes e automatização do processo de desenvolvimento.
Esta dissertação apresenta um ambiente para automatizar e acelerar a etapa de implementação de um processo de desenvolvimento de software.
O ambiente proposto por este trabalho, denominado XO2 , propõe-se a gerar uma grande
parte do código-fonte de um sistema de informação orientado a objetos através da transformação de modelos, independentemente da plataforma, arquitetura e linguagem de programação, seguindo os princı́pios da arquitetura MDA - Model Driven Architecture [KWB03].
A utilização do ambiente XO2 resulta em benefı́cios como: (1) aumento da qualidade e
padronização do código-fonte, (2) aumento da consistência do código, (3) aumento da produtividade através da automatização e aceleração do processo de desenvolvimento e (4) abstração
pela separação bem definida de papéis e responsabilidades.
O ambiente XO2 difere de soluções já existentes, pois além de modelos OO - Orientados a
Objetos descritos em UML [BRJ98], podem ser utilizados como entrada do sistema outros modelos, como o ER - Entidade-Relacionamento [BCNN91], cujos elementos quando relacionados
servem como insumo para criação de grande parte do código-fonte de sistemas de informação.
1.1
Por que gerar código?
Desde o inı́cio da sua história, o homem vem procurando formas de agilizar o seu trabalho.
Ferramentas e processos foram desenvolvidos para otimizar e aumentar a qualidade da realização
de tarefas repetitivas.
Na engenharia de software não poderia ser diferente. Atualmente, as empresas precisam
de sistemas mais completos, com número reduzido de bugs e com um tempo de desenvolvimento cada vez mais curto. Além disso, os projetos de sistemas precisam ser mais robustos e
seus requisitos são alterados constantemente [Joh05]. Diante deste cenário, surgiram técnicas,
padrões, frameworks 1 e metodologias de desenvolvimento voltados para a agilização dos proces1
Arcabouço, um conjunto de classes para atender as necessidades de um determinado problema.
1
2
INTRODUÇÃO
sos. Entre eles destacam-se Agile Modeling [SWA02], XP [KB04] e AOP [JDG03], que reduzem
drasticamente o esforço despendido na produção de artefatos durante as fases de levantamento
de requisitos, análise e projeto e ainda facilitam a implementação dos sistemas.
Ainda assim, na fase de implementação, o desenvolvedor precisa escrever um grande número
de linhas de código, devido ao uso de frameworks “pesados”. Desta forma, surge nas empresas o questionamento sobre o desperdı́cio do raciocı́nio e do tempo dos seus desenvolvedores em
atividades repetitivas (criação de infra-estrutura de código, documentação, testes unitários), enquanto estes poderiam estar ocupados com o desenvolvimento de um código-fonte que realmente
exigisse a interferência humana (implementação de regras de negócio) [Mei05] [Nic05].
A utilização de frameworks que fazem uso intensivo de código escrito destaca o valor da
substituição da mão-de-obra humana por um ambiente gerador de código. Arquiteturas em
camadas, EJB [MH01], persistência de dados utilizando middlewares como o Hibernate [Hib05]
são exemplos de frameworks que fazem uso intensivo de escrita de código, que na sua grande
maioria não necessita de raciocı́nio para ser criado, pois segue um padrão repetitivo. Este é
o ambiente ideal para a utilização de ferramentas capazes de gerar código, pois estas seriam
capazes de eliminar o esforço do desenvolvedor na criação do código repetitivo.
Geração de código é o processo de produzir código de alto nı́vel através de descrições de
requisitos ou modelos de negócio. Atualmente existem dezenas de ferramentas que auxiliam os
desenvolvedores na fase de implementação do desenvolvimento de software. As ferramentas vão
desde simples wizards que auxiliam na criação de trechos de código até ambientes que produzem
a arquitetura completa de um sistema.
O primeiro benefı́cio que se obtém pela utilização de um gerador de código é o aumento
da produtividade. Não menos significativos são os aumentos de: qualidade, consistência e
abstração.
Qualidade. Devido à grande quantidade de código-fonte escrito durante o desenvolvimento
de um sistema, é bem provável que novas melhorias de código não sejam propagadas por toda
base de código escrito. A utilização de um ambiente gerador de código cria, através dos templates, uma base de código que poderá ser recriada a cada nova execução. Desta forma, a
correção de erros e as melhorias no código serão aplicadas instantaneamente em todo o código
do sistema.
À medida que aumenta-se a qualidade dos templates, a qualidade da base de código gerada também aumenta, pois a qualidade do código produzido por um gerador está diretamente
relacionada à qualidade dos templates utilizados.
Consistência. O código produzido por um ambiente gerador de código está de acordo com
os padrões de projeto e com os padrões de codificação (nomes de classes, variáveis, métodos,
alinhamento) e é consistente em toda a sua base de código. O código-fonte produzido é mais
fácil de ser entendido, de sofrer manutenção e de ser utilizado.
O gerador de código encoraja o desenvolvedor a trabalhar de acordo com a arquitetura e
com os padrões do projeto.
Produtividade. Como os desenvolvedores não precisam desenvolver código repetitivo, o
cronograma do projeto torna-se bastante otimizado (iterações mais curtas), pois tem-se uma
quantidade maior de horas para elaborar e implementar as regras de negócio. Com mais tempo
para implementação das regras de negócio os desenvolvedores podem buscar a melhor solução
para cada problema e, ainda, dar mais atenção às fases de prototipação e testes.
É notório que os requisitos de um projeto estão sempre sendo alterados [Joh05], desta forma
1.2 OBJETIVOS
3
o ganho na produtividade também será percebido durante a manutenção do projeto. Com a
simples alteração dos modelos um novo código-fonte compatı́vel com os requisitos poderá ser
gerado rapidamente.
Abstração. A grande maioria dos geradores de código produzem código a partir do processamento de modelos abstratos e regras de transformação (templates). O grande valor desta
abordagem é a possibilidade de se produzir código para outras plataformas. Esta abstração é
traduzida na portabilidade do sistema para outras plataformas.
A abstração propicia ao arquiteto experimentar diferentes abordagens para resolução de um
determinado problema utilizando diferentes arquiteturas e plataformas.
1.2
Objetivos
Este trabalho teve por objetivo o desenvolvimento de um ambiente gerador de código, denominado XO2 , com a capacidade de produzir código-fonte a partir de vários modelos abstratos do
sistema. Enquanto a maioria dos geradores de código utilizam apenas um modelo para produzir
código, o XO2 permite a utilização de vários modelos como entrada para o ambiente.
Depois de uma vasta pesquisa, foi comprovada a inexistência de um padrão de mapeamento
de modelos abstratos. Sendo assim, este trabalho também propõe um documento escrito em
linguagem XML, denominado M3 L - Model Mapping Markup Language, capaz de representar,
de forma simplificada, ligações entre modelos orientados a objetos, entidade-relacionamento,
etc.
O documento M3 L contém apenas um subconjunto de todos os elementos necessários para
representar de forma fiel o mapeamento de modelos. Porém, com esse pequeno número de
elementos já se conseguiu provar a eficiência e a utilidade do mapeamento de modelos em um
ambiente gerador de código.
O ambiente XO2 foi modelado utilizando a linguagem UML e sua implementação foi realizada
na linguagem Java, com o intuito de manter a modularidade, extensibilidade e reusabilidade do
código.
Assim como o documento M3 L, o protótipo XO2 implementa apenas uma parte da solução
do problema, pois permite ao usuário utilizar apenas o modelo orientado a objetos e o entidaderelacionamento. No entanto, o padrão de modelagem e o protótipo foram projetados de forma
que sejam capazes de serem estendidos.
Foi implementada uma interface gráfica para auxiliar a construção do documento M3 L e
execução do ambiente XO2 .
Para a validação do ambiente foi utilizado como estudo de caso o SIG@UFPE - Sistema
de Informação e Gestão Acadêmica Universidade Federal de Pernambuco [UFP05]. O XO2
foi configurado para produzir boa parte do código arquitetural do sistema e os resultados dos
testes foram bastante animadores no que concerne à qualidade e consistência do código-fonte
produzido, além dos ganhos de produtividade e aumento na capacidade de abstração durante
as fases de análise e projeto do sistema.
1.3
Estrutura da Dissertação
Além desta seção introdutória, esta dissertação é composta por mais cinco capı́tulos.
Capı́tulo 2 - Apresenta um resumo sobre os principais conceitos, padrões e ferramentas
4
INTRODUÇÃO
relevantes ao entendimento deste trabalho. Nele será explicado o conceito de geração de código
juntamente com os principais tipos de geradores de código e alguns padrões OMG2 . Ainda são
detalhadas algumas ferramentas utilizadas no desenvolvimento do protótipo.
Capı́tulo 3 - Apresenta alguns trabalhos relacionados. É feita uma análise dos principais
ambientes geradores de código existentes.
Capı́tulo 4 - Apresenta detalhadamente o ambiente XO2 , sua arquitetura, decisões de projeto, seu funcionamento, como extrair o máximo do ambiente e ainda como estendê-lo.
Capı́tulo 5 - Apresenta os testes e resultados obtidos através da utilização do ambiente XO2
em dois problemas distintos: produzir websites dinâmicos em linguagem Perl [WCO00] e alterar
a camada de persistência do sistema SIG@UFPE.
Capı́tulo 6 - Apresenta as contribuições deste trabalho, as conclusões tiradas e os trabalhos
futuros.
2
Object Management Group. Consórcio regulamentador de alguns padrões para sistemas distribuı́dos e orientados a objetos
CAPÍTULO 2
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E
TECNOLOGIAS
Este capı́tulo apresenta os principais conceitos, padrões e tecnologias relevantes ao entendimento
do ambiente de geração de código proposto neste trabalho. Primeiramente, serão definidos
alguns termos utilizados ao longo do texto. Em seguida, o leitor será apresentado ao conceito
de geração de código e mapeamento OO-Relacional. Posteriormente, os padrões da OMG serão
introduzidos. Finalmente, serão detalhadas as tecnologias Velocity [CG03] e Hibernate [Hib05].
2.1
Conceitos
No contexto deste trabalho, sistema de informação ou sistema é todo software ou parte de
software desenvolvido com o propósito de resolver um problema especı́fico, variando de um
simples website até um complexo sistema financeiro.
Um modelo ou diagrama de sistema é a descrição ou especificação com um determinado
propósito do sistema ou de uma de suas partes. Um modelo geralmente é apresentado como uma
combinação de gráficos e textos. O texto pode ser escrito em alguma linguagem de modelagem
ou mesmo em linguagem natural.
Ao longo deste trabalho serão utilizados amplamente termos como analista de sistemas,
arquiteto de sistemas, engenheiro de software e designer.
Analista de sistemas ou simplesmente analista é responsável por definir e especificar os
requisitos funcionais e não-funcionais de um sistema. Ainda é responsável por, juntamente com
o usuário, criar um protótipo da interface gráfica.
O analista deve possuir um amplo conhecimento do negócio que está sendo modelado. Ele irá
trabalhar juntamente com os futuros usuários do sistema e com os profissionais de TI, atuando
como um mediador entre o mundo tecnológico e o mundo do negócio. O analista precisa ser
capaz de identificar problemas e oportunidades e, ainda, propor soluções. Se de um lado o
analista precisa conhecer os meandros do negócio modelado e os jargões da equipe de TI, ele
não deve estar “intoxicado” pela tecnologia.
O arquiteto de sistemas ou apenas arquiteto é responsável por definir a arquitetura de
software, a plataforma e a linguagem de implementação. Ele também deve sugerir reutilização
de componentes e projetar classes reusáveis e soluções arquiteturais.
A arquitetura define a quantidade e responsabilidades das camadas de um sistema e a comunicação entre essas camadas. O arquiteto deve estar em contato com o analista para ter uma
visão completa das necessidades do negócio ao mesmo tempo que deve guiar os desenvolvedores,
tendo sempre como objetivos qualidade e robustez.
O desenvolvedor ou engenheiro de software é responsável pela escrita do código-fonte, além
de realizar testes de unidade e de performance e corrigir defeitos apontados.
Designer é o profissional responsável pela elaboração e criação das interfaces gráficas do
sistema. Geralmente é um profissional especializado em artes gráficas e que não necessita ter
5
6
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
muitos conhecimentos da área de engenharia de software.
2.2
Geração de Código
Geração de código é o processo de escrever um software que tem a capacidade de escrever outros
softwares. Desta forma, um gerador de código recebe alguns parâmetros de entrada, realiza um
processamento e, finalmente, produz código-fonte como saı́da [Her03].
Os geradores de código podem ser classificados de acordo com o tipo de geração de código
utilizado e de acordo com o tipo de arquivos de entrada e saı́da.
Frameworks como J2EE [MH01] e .NET [and03] forçam a escrita de um número muito maior
de linhas de código, pois geralmente as classes de negócio dão origem a vários documentos fonte.
Analogamente, quanto mais complexo for o framework mais recomendada será a utilização de
um ambiente gerador de código.
2.2.1
Modelos de Geradores de Código
Herrington [Her03] classifica os geradores de acordo com o tipo de geração em: ativos e passivos.
Os geradores ativos podem ser executados diversas vezes sobre o mesmo código de acordo
com as alterações realizadas no input (arquivo de entrada). O código editado é mantido através
de seções protegidas que garante a sua existência em futuras gerações de código.
A Figura 2.1 ilustra o ciclo de um gerador de código ativo.
Figura 2.1 Funcionamento de um gerador de código ativo
Um gerador ativo é capaz de ler e entender um modelo abstrato do sistema e produzir o
código-fonte base de implementação do sistema para uma determinada plataforma e, ainda, é
capaz de proteger o código editado.
Os geradores passivos permitem que o código seja gerado uma única vez e toda a manutenção
necessária deverá ser realizada por parte dos desenvolvedores.
A Figura 2.2 ilustra o ciclo de um gerador de código passivo.
Os geradores passivos fornecem uma aceleração inicial na produtividade do projeto, no
entanto, caso os requisitos sejam alterados todas as modificações realizadas na base de código
2.2 GERAÇÃO DE CÓDIGO
7
Figura 2.2 Funcionamento de um gerador de código passivo
serão perdidas a cada execução do ambiente.
Muitos dos geradores de código passivos são soluções criadas pelos próprios desenvolvedores
para resolver tarefas simples e repetitivas.
Um gerador de código passivo é muito útil na produção de comentários e anotações no
código. Este tipo de gerador de código é bastante difundido como wizard em IDEs - Integrated
Development Environment1 . Geralmente uma IDE utiliza um gerador passivo para produzir
o código base (declaração de pacote e classe e blocos de comentário) de uma classe que será
editado pelo desenvolvedor.
2.2.2
Tipos de Geradores de Código
Nesta seção, serão abordados os principais tipos de geradores de código que são classificados
por Herrington [Her03] de acordo com os arquivos de entrada (utilizados como insumo para o
ambiente) e saı́da (produzidos pelo ambiente).
2.2.2.1 Code Munger O gerador conhecido como Code Munger2 é o tipo mais comum. A
partir de um código-fonte de entrada, o “munger” seleciona as partes importantes e as utiliza
para criar um ou mais arquivos de saı́da. A Figura 2.3 apresenta o fluxo de processo de um
gerador de código do tipo Code Munger. O gerador recebe os arquivos de entrada e, geralmente
através de expressões regulares ou análise de código somados a templates internos ou externos,
constrói os arquivos de saı́da.
Um gerador deste tipo geralmente é utilizado para criar documentação através da leitura de
variáveis e métodos. O Javadoc [Sun05b], exemplo de Code Munger, realiza a leitura e análise de
código-fonte Java em busca de comentários e marcações para em seguida produzir documentação
em forma de documentos HTML. A Figura 2.4 ilustra o funcionamento do Javadoc.
Em relação à qualidade, o Javadoc produz documentação bastante precisa pois os comentários são mantidos ao longo do código-fonte e como esse será completamente percorrido
pelo Javadoc, o desenvolvedor não precisa criar as entradas para os nomes e tipos de variáveis.
1
2
Ambiente de desenvolvimento integrado que provê interface gráfica, editor, compilador e depurador de código
Gı́ria em inglês que significa comportamento simplista
8
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.3 Funcionamento de um gerador de código do tipo Code Munger
A utilização do Javadoc também fornece um ganho na produtividade, pois o desenvolvedor
é liberado da tarefa cansativa de criar e manter uma documentação externa. Isto ocorre porque
o código-fonte desenvolvido já contém internamente a documentação necessária.
Um gerador do tipo Code Munger possui um baixo nı́vel de abstração, já que a entrada é
geralmente o próprio código-fonte.
Figura 2.4 Funcionamento do Javadoc
2.2.2.2 Inline Code Expander Um gerador de código do tipo Inline Code Expander recebe um código-fonte com marcadores que serão “expandidos” ou transformados durante a
produção do código. A Figura 2.5 ilustra o fluxo de controle de um inline code expander.
Figura 2.5 Funcionamento de um gerador de código do tipo Inline Code Expander
Como percebe-se pela Figura 2.5, existem dois códigos-fonte. O primeiro, escrito pelo de-
2.2 GERAÇÃO DE CÓDIGO
9
senvolvedor, contém uma série de marcações. O segundo, produzido pelo gerador de código, é
o código que deverá ser compilado.
Um Inline Code Expander é freqüentemente utilizado para estender código SQL em um
código-fonte já existente. Os desenvolvedores adicionam notas ou marcações que servem como
indicações para o gerador. Este por sua vez analisa o código e sempre que encontra uma
indicação, insere o novo código.
A utilização de um Inline Code Expander fornece uma qualidade maior no código do projeto,
pois fornece de forma independente a infra-estrutura de acesso aos dados exigida para a execução
dos comandos SQL. Ele também deixa o código de infra-estrutura consistente ao longo de toda
a base de código.
2.2.2.3 Mixed Code Assim como o Inline Code Expander e o Code Munger, o Mixed Code
recebe um código-fonte como entrada, o transforma e produz um código-fonte de saı́da. Porém
o código de saı́da é armazenado no próprio arquivo de entrada, sobrescrevendo o conteúdo
existente. A Figura 2.6 representa o funcionamento de um gerador Mixed Code.
Figura 2.6 Funcionamento de um gerador de código Mixed Code
2.2.2.4 Partial Class Generator Como o próprio nome indica, um gerador Partial Class é
responsável por criar parte de uma camada da aplicação. Um gerador de código deste tipo produz um conjunto básico de classes para implementar atividades simples. Caso seja necessário,
extensões da classe devem ser criadas para implementar novas funcionalidades. Este funcionamento é ilustrado na Figura 2.7.
Um exemplo tı́pico de um gerador de código Partial Class é aquele utilizado para construir
uma camada de acesso aos dados. O gerador cria o código de persistência para cada classe e
seus campos. Sendo assim, qualquer funcionalidade extra deverá ser implementada em uma
classe derivada.
Numa avaliação geral, percebe-se que um gerador deste tipo controla toda a estrutura de
acesso à base de dados, assim a qualidade do código estará diretamente associada aos templates
utilizados para geração de código. Alterações nos templates serão contempladas em todo o
código gerado.
Como a API de acesso aos dados é criada automaticamente, haverá uma padronização nas
assinaturas dos métodos e nomes de variáveis, facilitando o entendimento e manutenção do
código gerado, além de reduzir o número de erros.
Portabilidade é mais um benefı́cio da utilização de um gerador de código deste tipo, pois
a lógica de acesso aos dados é extraı́da das classes de negócio e armazenada em arquivos de
10
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.7 Funcionamento de um gerador de código Partial Class
definição tornando a camada de persistência portável para outra plataforma.
2.2.2.5 Tier Generator Um gerador Tier3 é capaz de gerar uma camada inteira de um
sistema multi-camada. Num sistema web, pode ser uma camada de acesso aos dados, camada
de negócio ou de interface gráfica com o usuário.
Figura 2.8 Funcionamento de um gerador de código do tipo Tier
A Figura 2.8 mostra como funciona um gerador Tier. O gerador recebe um documento com
a definição abstrata do sistema e um conjunto de templates que serão utilizados para produzir
3
Do inglês camada
2.2 GERAÇÃO DE CÓDIGO
11
os documentos de saı́da. Nestes documentos estará contida uma camada completa da aplicação.
A principal diferença entre os geradores Tier e Partial Class é que o primeiro produz e
mantém todo o código da camada e o segundo deixa a criação das classes especializadas para o
desenvolvedor.
A Figura 2.9 ilustra um gerador Tier que produz a camada de acesso aos dados de uma
aplicação J2EE [MH01]. Percebe-se que o gerador produz toda a camada de persistência dos
dados.
Como o gerador de código é responsável pela construção da camada, obtém-se consistência
por toda a base de código gerada.
A velocidade com que o gerador de código produz uma camada da aplicação permite que o
arquiteto experimente diversos estilos e estruturas de classes, simplesmente alterando os templates e gerando novamente o código. Seria impossı́vel para um desenvolvedor fazer as mesmas
alterações em uma base inteira de código consumindo o mesmo tempo.
Figura 2.9 Gerador de código Tier para aplicação J2EE
2.2.3
Fluxo de desenvolvimento
A utilização de um ambiente gerador de código provoca uma alteração no fluxo de desenvolvimento de um sistema. No fluxo convencional, representado na Figura 2.10, os desenvolvedores
escrevem o código, fazem a compilação e em seguida testam o código. Caso necessário, o código
será editado reiniciando o fluxo.
A utilização de um gerador de código adiciona duas etapas responsáveis pela criação dos
templates e geração da base de código. A Figura 2.11 ilustra o fluxo de desenvolvimento com
gerador de código.
Na fase de criação dos templates, o arquiteto e o engenheiro verificam quais necessidades
serão codificadas de forma que o template forneça um código fiel à modelagem.
Na fase de geração de código, os templates e os arquivos de definição serão inseridos no
ambiente gerador de código. Dependendo do gerador de código utilizado, o código produzido
12
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.10 Fluxo de desenvolvimento convencional
Figura 2.11 Fluxo de desenvolvimento com gerador de código
poderá ser editado e então, juntamente com o código escrito pelos desenvolvedores, compilado.
Caso necessário o fluxo será reiniciado.
2.3
Mapeamento OO-Relacional
Os desenvolvedores de sistemas orientados a objetos que utilizam SGBD4 relacional como forma
de persistência de dados geralmente gastam uma boa parte do tempo de programação para
tornar os objetos de negócio persistentes. Isto acontece pela diferença fundamental entre o
paradigma orientado a objetos e o paradigma relacional. A base do paradigma OO é um objeto
que possui atributos, comportamento e herança, enquanto que a base do paradigma relacional
é uma tabela que tem a capacidade de armazenar dados e relacionar-se com outras tabelas.
Segundo Yoder [YJW98] a diferença entre os paradigmas é similar à impedância entre circuitos eletrônicos, sendo assim, quando se conecta um sistema orientado a objetos a bancos de
dados relacionais obtém-se circuitos que funcionam independentemente e com sinais (formato
de dados) não-compatı́veis.
Existem algumas formas para contornar o problema da “impedância” entre modelos, entre
elas: utilização de um SGBD orientado a objetos, criar um “circuito” (middleware) que inserido
4
Sistema de Gerenciamento de Bancos de Dados ou Banco de Dados.
2.4 PADRÕES OMG - OBJECT MANAGEMENT GROUP
13
entre os paradigmas realize de forma transparente a troca de dados. Ou seja, cria-se uma camada
de persistência de dados capaz de converter os objetos de negócio do sistema em tabelas do banco
e dados relacional.
Apesar da existência de vários SGBDs orientados a objetos [LC97], estes ainda não se
tornaram um padrão da indústria. Ainda, os SGBDs relacionais possuem algumas vantagens
como performance e capacidade de processamento de consultas SQL.
Já existem várias ferramentas que realizam a “ponte” entre os modelos OO e relacional,
entre elas: TopLink [Ora05b], Hibernate [Hib05], JDO [JR03]. Essas ferramentas utilizam o
conceito de camada de persistência transparente5 (persistent layer transparency) que realiza
a transformação dos objetos em tabelas e relacionamentos de um banco de dados relacional.
Geralmente, o usuário necessita configurar o middleware indicando o mapeamento entre suas
classes e as tabelas do banco de dados. Uma vez configuradas as regras de mapeamento,
os usuários não precisam mais se preocupar com as tabelas e os relacionamentos, já que a
persistência e recuperação dos dados será realizada de forma transparente pela camada de
persistência. E mais, o desenvolvedor não precisará escrever consultas SQL para atualização e
recuperação de dados.
Um sistema que utiliza uma camada de persistência convencional torna-se “engessado”,
pois alterações no SGBD necessitam de reescrita de código. Já um sistema com camada de
persistência transparente possibilita a substituição do SGBD sem que haja reescrita de códigofonte.
Existem várias propostas de padrões de mapeamento entre os modelos OO e ER, no entanto,
não existe um padrão de facto. Este trabalho segue o padrão de mapeamento proposto por
Ambler [Amb00].
Segundo o padrão proposto por Scott Ambler, um atributo da classe corresponde a zero ou
mais colunas de uma tabela em um banco de dados relacional. Zero, pois nem todos os atributos
da classe são persistentes, alguns atributos são calculados. Mais colunas, pois um atributo como
endereço deve dar origem a várias colunas como rua, número, bairro, etc.
O padrão propõe também que uma classe de negócio seja mapeada para uma ou mais tabelas,
e prevê a implementação de heranças e relacionamentos. Alguns desses tópicos serão abordados
com mais detalhes ao longo deste trabalho à medida em que se fizer necessário.
2.4
2.4.1
Padrões OMG - Object Management Group
MOF
Atualmente, com as grandes empresas inseridas na era da computação, cada uma possui seu
próprio padrão de dados. O grande problema é que cada empresa armazena seus dados em
diferentes formatos, complicando cada vez mais a comunicação eletrônica entre as empresas
envolvidas. É possı́vel tomar como exemplo um banco que realiza milhares de transferências
eletrônicas diariamente, e grande parte dessas transações envolvem instituições que utilizam
vários padrões de arquivos. As instituições envolvidas precisam encontrar um padrão para
intercambiar tais arquivos. Desse problema surgiu a necessidade de um padrão para definir o
formato de armazenamento e compartilhamento de dados.
5
A aplicação utiliza a mesma API de acesso aos dados, independentemente da forma de armazenamento e
do SGBD utilizado. O conceito de camada de persistência transparente simplifica a aplicação e aumenta a
manutenibilidade, escondendo os detalhes da implementação de persistência dos dados.
14
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
O padrão MOF - Meta-Object Facility é o padrão OMG [BRJ98] que especifica uma linguagem abstrata para descrição de outras linguagens. MOF também é um meta-metamodelo e
sua sintaxe abstrata é utilizada para descrever metamodelos. A arquitetura MOF possui quatro
camadas como ilustra a tabela 2.1.
Nı́vel
M0
Camada
dados
M1
metadados / modelos
M2
meta-metadados / metamodelos
M3
meta-metamodelo
Exemplos
Registros de uma tabela de um BD,
instâncias de classes Java
Tabelas, colunas de um BD, classes,
métodos e atributos Java
Definição dos elementos de uma base dados como Tabela, Coluna, descrição dos
construtores da linguagem Java
MOF
Tabela 2.1 Arquitetura MOF
A figura mostra que cada nı́vel M(x), onde x<3, é descrito utilizando construtores definidos
no nı́vel M(x+1). O nı́vel M3 é o nı́vel mais alto, enquanto que o nı́vel 0 é o mais baixo e
representa os dados. São elementos do nı́vel 0 as instâncias de classes da linguagem, os registros
de uma tabela de banco de dados, etc. O nı́vel 1 representa os metadados ou modelos, são eles
que definem a estrutura dos dados, podendo ser as tabelas e colunas de um banco de dados ou
as classes da linguagem Java. O nı́vel 2 é o nı́vel dos meta-metadados ou metamodelos, são os
elementos que definem os modelos e conceitos como tabela, coluna, classe, etc. Finalmente, o
nı́vel 3 ou meta-metamodelo é o responsável pela definição dos metamodelos.
A criação de um metamodelo para definir o padrão XML[Har01] e seus elementos será
utilizada para ilustrar a utilização do padrão MOF na criação de metamodelos. Um documento
XML pode ser descrito como um conjunto de nós. Estes nós podem ser: elementos, atributos e
texto, assim como no Exemplo 2.1.
Exemplo 2.1 Um tı́pico documento XML
1 <a l u n o s >
2
<p e s s o a nome=”Maria”/>
3
<p e s s o a nome=”J o s e ”/>
4
<c u r s o >C i e n c i a da Computacao</c u r s o >
5
</p e s s o a >
6 </a l u n o s >
O exemplo contém os seguintes nós do tipo elemento (ElementNode), segundo a ordem em
que aparecem: alunos, pessoa, pessoa, curso. Os nós do tipo atributo (AttributeNode) são:
nome e nome. O único nó do tipo texto (TextNode) é “Ciencia da Computacao”.
A partir do exemplo, pode-se afirmar sobre a estrutura de um documento XML que:
ˆ Cada nó possui um nome (em nós de tipo texto o nome é formado pelo próprio texto);
ˆ Nós elemento podem conter outros nós elemento, nós atributo ou nós texto;
ˆ Nós atributo possuem um valor (e.g. nome tem valor Maria); e
2.4 PADRÕES OMG - OBJECT MANAGEMENT GROUP
15
ˆ Em cada documento XML existe apenas um elemento raiz.
A Figura 2.12 exibe uma possı́vel representação, em MOF, do modelo da linguagem XML.
Figura 2.12 Representação da linguagem XML em MOF
As caixas na figura representam classes MOF. Existe uma classe abstrata chamada Node com
um atributo name: é esta classe que captura o fato de que todos os nós possuem um nome. A
classe Node é uma generalização de classes não-abstratas que representam os três diferentes tipos
de nós: ElementNode, TextNode e AttributeNode. Entre as classes ElementNode e Node existe
uma associação MOF chamada contains que captura o fato de que cada classe ElementNode
pode conter zero ou mais nós internos. Para limitar a apenas um a quantidade de elementos
raiz, foi criada uma subclasse de ElementNode chamada RootNode para representar o elemento
raiz. O nome do documento XML é armazenado no atributo documentName.
O metamodelo captura toda a informação que diz respeito à estrutura dos documentos XML,
desta forma será identificado como metamodelo da linguagem XML. Como percebe-se, o padrão
MOF não foi utilizado para representar a gramática, mas sim a estrutura da linguagem XML.
É importante saber que a especificação MOF não define nenhuma representação textual ou
gráfica da linguagem. O metamodelo apresentado foi ilustrado utilizando-se a notação UML.
A Figura 2.13 ilustra os principais elementos do padrão MOF e como eles estão relacionados
entre si.
É interessante notar a organização dos elementos. Todas as classes são subclasses do elemento modelo (ModelElement). O classifier é uma interface que define classes (Class), tipos
de dados (DataType) e associações (Association). Um namespace pode ser visto como um agrupador de elementos. Os elementos contidos em um namespace recebem o nome de feature e podem ser comportamentais (BehavioralFeature) e estruturais (StructuralFeature). Operações
ou métodos (Operation) e exceções (Exception) são features comportamentais. Os atributos (Attribute) e referências (Reference) são features estruturais. Tanto (Package) como
Classifier são subclasses de GeneralizableElement e portanto podem ser generalizados.
16
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.13 Principais elementos do padrão MOF
2.4.2
XMI
XML Metadata Interchange [GDB02] é o padrão da OMG para armazenamento e compartilhamento de metamodelos MOF através de documentos XML. O padrão define um conjunto de
regras para gerar DTDs ou XML Schemas a partir de metamodelos MOF e as regras para serialização de instâncias desses metamodelos. Analogamente, o padrão possibilita o armazenamento
e intercâmbio de modelos UML na forma de documentos XML.
As principais caracterı́sticas do padrão XMI são:
ˆ Provê um padrão para representação de objetos em XML, permitindo o intercâmbio efetivo
de objetos;
ˆ Especifica como criar XML Schemas a partir de modelos;
ˆ Permite a criação de documentos XML básicos que, mais tarde, possam evoluir através
da adição de elementos à estrutura; e
ˆ Os usuários não precisam conhecer a fundo a linguagem XML para utilizar o padrão.
A versão 2.0 do padrão XMI permite, adicionalmente, o mapeamento de modelos UML em
XML Schemas. Como o padrão define o mapeamento dos objetos em XML, não será necessário
definir a forma pela qual esses objetos serão intercambiados ou transformados, já que todo o
processo será realizado por um software capaz de interpretar o padrão XMI.
2.4 PADRÕES OMG - OBJECT MANAGEMENT GROUP
17
Figura 2.14 Representando uma classe em XMI
A Figura 2.14 apresenta um modelo UML contendo uma classe Carro e os atributos ano e
marca. Logo abaixo, tem-se um documento XMI que armazena os dados de um objeto da classe
Carro. Este documento pode ser validado por um XML Schema produzido a partir do modelo.
Um documento XMI é capaz de armazenar qualquer modelo MOF e suas instâncias, e
de definir vários aspectos envolvidos na descrição de objetos, entre eles: representar objetos
na forma de elementos e atributos XML; fazer a ligação entre objetos de um mesmo arquivo
ou distribuı́dos em vários arquivos; identificar objetos e referenciá-los; controlar a versão dos
objetos em um modelo XMI; e validar documentos XMI através de DTDs e XML Schemas.
Os dois principais tipos de documentos definidos pelo padrão XMI são os próprios documentos XMI e XMI Schema. Um documento XMI permite armazenar, por exemplo, os objetos
de um diagrama de objetos UML. Um documento XMI Schemas possibilita o armazenamento
de modelos orientados a objetos. Essa versatilidade do padrão XMI para representar dados e
meta-dados é uma de suas principais caracterı́sticas.
A Figura 2.15 mostra um diagrama de classes com uma classe Carro e uma classe Pessoa.
A associação da classe Carro com a classe Pessoa dá origem ao atributo motorista. O relacionamento também indica que um carro pode ter zero ou mais objetos da classe Pessoa.
Figura 2.15 Representação das classes Carro e Pessoa
É possı́vel representar instâncias das classes apresentadas na figura através de atributos ou
elementos XML.
O Exemplo 2.2 mostra um trecho de documento XMI para representar instâncias das classes
do modelo. Neste caso, tem-se um objeto carro que possui dois motoristas.
18
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Exemplo 2.2 Trecho de documento XMI
1 <Carro m o t o r i s t a=”P1 P2”/>
2 <M o t o r i s t a xmi : i d=”P1”/>
3 <M o t o r i s t a xmi : i d=”P2”/>
O atributo XML motorista no elemento carro representa as referências para os elementos
Motorista. O valor do atributo motorista contém os identificadores de cada um dos elementos
Pessoa que representa o motorista do carro.
A representação dos objetos do modelo poderia igualmente ser realizada utilizando elementos
XML. Neste caso seriam utilizados links para identificar e referenciar os objetos. Desta forma
cada referência apontaria para o identificador do objeto associado. Todavia, o elemento conteria
apenas referências para elementos com os dados do motorista. O Exemplo 2.3 ilustra um possı́vel
documento XMI que utiliza objetos para representar os objetos.
Exemplo 2.3 Trecho de documento XMI
1
2
3
4
5
6
<Carro>
<m o t o r i s t a h r e f=”#P1”/>
<m o t o r i s t a h r e f=”#P2”/>
</Carro>
<Pessoa xmi : i d=”P1”/>
<Pessoa xmi : i d=”P2”/>
Como percebe-se, foram criados dois elementos motorista dentro de Carro, no atributo
href destes elementos está uma URI que aponta para os elementos do documento que contêm
as definições dos objetos Pessoa.
A relevância do padrão XMI para o entendimento do resto desse trabalho está na capacidade de armazenamento modelos UML, mais especificamente, os elementos de um diagrama de
classes.
A versão 1.2 do padrão XMI foi utilizada para representar os modelos que serão utilizados
durante a implementação do ambiente XO2 .
Figura 2.16 Representação da classe Carro
A Figura 2.16 ilustra uma classe Carro que contém apenas um atributo ano do tipo int. O
Exemplo 2.4 ilustra trechos de um documento XMI para armazenar o modelo.
Exemplo 2.4 Trecho de documento XMI
1 ...
2 <UML: C l a s s xmi . i d = ’ sm $ 23d278 : 1 0 1 8 6 dedd48 :−7 f f 6 ’
3
name = ’ Carro ’ v i s i b i l i t y = ’ p u b l i c ’>
4 <UML: C l a s s i f i e r . f e a t u r e >
5
<UML: A t t r i b u t e xmi . i d = ’ sm $ 23d278 : 1 0 1 8 6 dedd48 :−7 f e 9 ’
6
name = ’ ano ’ v i s i b i l i t y = ’ p r i v a t e ’>
2.5 JMI
7
8
9
10
11
12
13
14
15
19
<UML: S t r u c t u r a l F e a t u r e . type>
<UML: DataType xmi . i d r e f = ’ sm $ 23d278 : 1 0 1 8 6 dedd48 :−7 fde ’/>
</UML: S t r u c t u r a l F e a t u r e . type>
</UML: A t t r i b u t e >
</UML: C l a s s i f i e r . f e a t u r e >
</UML: C l a s s >
...
<UML: DataType xmi . i d =
’ sm $ 23d278 : 1 0 1 8 6 dedd48 :−7 fde ’ name = ’ i n t ’/> . . .
A declaração da classe Carro é expressa pelo código encontrado entre as linhas 2 e 12. Foram
exibidos apenas os atributos mais importantes, no caso id, name e visibility. Primeiramente,
tem-se o xmi.id, que é um identificador único dentro do modelo e poderá ser utilizado para
referenciar a classe. O formato do id varia de acordo com a ferramenta utilizada. Prosseguindo,
o atributo name identifica o nome da classe. Em visibility será armazenado o identificador
de visibilidade da classe (public, protected, private).
A linha 4 cria um compartimento para os features (atributos, métodos) de um classifier.
Para o exemplo apresentado, o único elemento será o atributo ano, declarado na linha 5. Assim
como o elemento class, o elemento attribute possui id, name e visibility. Além disso,
deve possuir um tipo. O atributo ano é do tipo inteiro, assim na linha 8, há um elemento
datatype que referencia o tipo int declarado pelo código da linha 14. O exemplo ilustra como
a flexibilidade fornecida pelo padrão XMI torna os documentos mais extensos.
A Figura 2.17 mostra uma visão geral dos principais elementos da linguagem UML e como
eles relacionam entre si.
2.5
JMI
O padrão Java Metadata Interface [Sun05d] permite a interoperabilidade entre o padrão MOF
e linguagem Java. Se XMI provê o armazenamento de modelos MOF em documentos XML,
JMI torna capaz a utilização de modelos MOF em aplicações Java.
JMI é um serviço extensı́vel que facilita o acesso de aplicativos escritos na plataforma Java
a um repositório de metadados descritos em MOF. As ferramentas que utilizam JMI deixam
expostos todos os metadados utilizados, facilitando assim a criação de plug-ins ou extensões.
JMI provê:
ˆ Um framework de metadados que fornece um modelo de programação Java para acesso
aos metadados contidos em um repositório;
ˆ Um framework para integrar e estender ferramentas e aplicações Java; e
ˆ Integração com modelos OMG e sua arquitetura de metadados.
Finalmente, como uma implementação em Java para acesso a metadados descritos em MOF,
JMI especifica um conjunto de regras para gerar um conjunto de interfaces Java que possibilitem
a manipulação da informação contida em instâncias do metamodelo.
20
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.17 Visão geral dos principais elementos da linguagem UML
2.6
MDR
O MDR - Metadata Repository [MDR05] é um repositório de metadados MOF. O repositório é
capaz de interpretar e armazenar qualquer metamodelo MOF. Metamodelos e metadados podem
ser importados e exportados do MDR utilizando o padrão XMI. Sendo assim, os metadados
armazenados no repositório podem ser manipulados através de JMI.
O MDR é desenvolvido como parte do projeto NetBeans [Net05] e na prática fornece aos
sistemas implementados em Java um acesso direto a repositórios de documentos MOF. Este
acesso é promovido através da integração de três padrões existentes: MOF (definição de metamodelos), XMI (armazenamento de metamodelos em documentos XML) e JMI (API Java para
acesso a metadados). O MDR permite que uma aplicação leia e manipule documentos XMI
facilmente sem que haja uma necessidade do conhecimento do padrão.
2.7
MDA
O MDA - Model Driven Architecture [KWB03] é um framework para desenvolvimento de software definido pela OMG totalmente baseado em modelos e transformações de modelos.
O MDA define como separar especificação e implementação de um sistema em uma plataforma.
21
2.7 MDA
Figura 2.18 Ciclo de Desenvolvimento Tradicional do RUP
O MDA permite:
ˆ Especificar um sistema independentemente de plataforma;
ˆ Escolher uma plataforma especı́fica para implementação do sistema; e
ˆ Transformar a especificação do sistema em uma especificação para uma determinada
plataforma
Os três principais objetivos da arquitetura MDA são: portabilidade, interoperabilidade e
reusabilidade através de uma separação arquitetural de preocupações 6 .
A utilização do MDA não requer grandes alterações no ciclo de desenvolvimento de software
iterativo e incremental do RUP [Kru00]. O ciclo de desenvolvimento tradicional como mostra a
Figura 2.18 tem como fases geradoras de modelos (de análise e projeto) as fases 1 a 3 (requisitos,
análise e projeto). Contudo, tais artefatos começam a perder seu valor quando é iniciada a fase
de implementação. À medida que o sistema é alterado, a distância entre o que foi modelado
nas primeiras fases e o código implementado aumenta. É preciso disciplina e integração entre
o analista e o desenvolvedor para que toda alteração ou correção do código-fonte seja refletida
nos modelos de Análise e Projeto e vice-versa.
O ciclo de desenvolvimento MDA, como mostra a Figura 2.19, é bem parecido com um
ciclo tradicional de desenvolvimento. A principal diferença entre o processo MDA e o processo
tradicional é que as transformações entre os modelos no processo tradicional são feitas manualmente e no MDA são realizadas com o auxı́lio de ferramentas, eliminando a necessidade de
6
Segundo este conceito, é essencial separar as partes mutáveis das partes triviais de um sistema para conseguir
reutilização das partes triviais.
22
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.19 Ciclo de Desenvolvimento MDA
que alterações realizadas no código ou em um diagrama sejam refletidas nos outros diagramas
através de um processo manual. A Figura 2.20 ilustra as transformações executadas por uma
ferramenta MDA.
Na arquitetura MDA, transformação é o processo de produzir um modelo a partir de outro
já existente. Essa transformação é realizada através de diretivas conhecidas como regras de
transformação. O MDA possui três diferentes de modelos (PIM, PSM e código-fonte) que são
sucintamente descritos a seguir.
2.7.1
PIM - Plataform Indepent Model
O PIM, como o próprio nome indica, modelo independente de plataforma e tecnologia, é o
primeiro modelo definido e apresenta um alto nı́vel de abstração.
Um modelo PIM descreve um modelo de negócio e os detalhes de como as funcionalidades
do sistema serão implementadas sem especificar detalhes sobre as tecnologias utilizadas.
2.7.2
PSM - Platform Specific Model
O PSM é um modelo de sistema para uma determinada plataforma e tecnologia, ele contém
detalhes da implementação e da tecnologia empregada. O PSM é oriundo do PIM e é produzido
de acordo com uma série de regras de transformação previamente definidas.
Um PIM pode ser transformado em vários PSMs. Para cada plataforma tecnológica deverá
ser gerado um PSM diferente.
23
2.7 MDA
2.7.3
Código-Fonte
A transformação do modelo PSM em código é a última etapa do processo MDA de desenvolvimento. Com o PSM especificado para uma tecnologia ou plataforma, esta transformação ocorre
de forma bastante simples, utilizando apenas as regras de transformação já definidas. Assim, o
código poderá ser gerado automaticamente sem a interferência humana.
Figura 2.20 Transformações MDA
2.7.4
Transformações
Como abordado anteriormente, o MDA é totalmente baseado em modelos e transformações
entre modelos. As transformações podem ser manuais ou automáticas. A Figura 2.21 ilustra
detalhadamente as transformações entre os modelos PIM e PSM.
Figura 2.21 Transformações MDA
Através da Figura 2.21 percebe-se que no PIM são detalhados tipos e padrões independentes
da plataforma utilizada. O PSM contém os mesmos tipos e padrões, desta vez reescritos com
os detalhes da plataforma na qual o sistema será implementado.
O MDA ainda está em fase de evolução e estabelecimento na indústria. Alguns desafios ainda
persistem, entre eles a transformação automática entre os modelos PIM e PSM que atualmente
24
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
é realizada pelas ferramentas através da escrita dos templates. Acredita-se que, no futuro, o
MDA torne-se um padrão tanto na área acadêmica quanto na indústria de desenvolvimento de
software por trazer benefı́cios como:
ˆ Produtividade: o desenvolvedor não precisa escrever o código-fonte básico;
ˆ Portabilidade: com a separação do PIM e do PSM, um projeto desenvolvido em MDA pode
ser facilmente portável, bastando a criação de um modelo especı́fico para a plataforma;
ˆ Interoperabilidade: visto que ele permite o relacionamento entre diferentes modelos PSM;
e
ˆ Manutenibilidade: alterações no modelo PIM são refletidas diretamente no modelo PSM.
2.8
Velocity
Em seu inı́cio, a World Wide Web era constituı́da puramente por páginas estáticas criadas com
a linguagem HTML. Com o passar do tempo, os desenvolvedores sentiram a necessidade de
produzir conteúdo dinâmico e personalizado. Linguagens como Perl [WCO00], ASP [Wei00],
PHP [WT04] e JSP [Ber03] fornecem uma infra-estrutura completa para a criação de conteúdo
dinâmico para websites.
O padrão MVC - Model View Controller [GHJV95] surgiu para separar a interface gráfica
do sistema, assim o designer preocupa-se apenas com a parte visual, enquanto que os desenvolvedores se preocupam com a parte funcional e dinâmica do site.
Segundo o padrão, o modelo ou regras de negócio devem ser separados da apresentação e do
controlador. A Figura 2.22 ilustra o padrão MVC.
Figura 2.22 Padrão MVC
25
2.9 HIBERNATE
O modelo (Model) é constituı́do pelas classes responsáveis por implementar as regras de
negócio e manipulação de dados do sistema e arquiteturais. A apresentação (View) é responsável
por exibir os dados para os usuários. O controlador (Controller) é formado por classes que fazem
a ligação entre a interface gráfica ou apresentação e as classes de negócio. Esta abordagem é
bastante interessante pois separa bem os conceitos e impede que o código para representar as
regras de negócio seja “contaminado” pelo código responsável pela apresentação dos dados e
vice-versa. A abordagem MVC também permite que o sistema possa ter seu código utilizado por
diversos tipos de clientes e plataformas, bastando apenas que sua camada de apresentação seja
reescrita. O MVC permite também a reutilização de componentes e o aumento da complexidade
do projeto.
O Velocity [CG03] ajuda a por em prática a utilização do padrão MVC permitindo que os
designers criem um template de páginas web que acesse código Java e produza código HTML
para ser visualizado pelo usuário em seu navegador. Todavia, o código produzido pelo Velocity
não limita-se a código HTML, ele pode gerar qualquer tipo de arquivo texto. Com Velocity, o
designer gráfico não precisa conhecer detalhes da linguagem Java, apenas os meios para acessar
objetos, atributos e métodos. Sendo assim, a apresentação e a lógica de negócio ficam totalmente
separadas.
A criação do template dá inı́cio ao funcionamento padrão do Velocity. O designer modela
a interface gráfica do sistema utilizando os elementos básicos da linguagem HTML e alguns
elementos do Velocity para referenciar objetos do sistema. O desenvolvedor será responsável
pelo sistema que fornecerá acesso ao conteúdo e por informar ao designer os meios de acesso
ao conteúdo desejado. Após a criação dos templates e da implementação do sistema, o Velocity
irá “renderizar” o template de acordo com os objetos do sistema para produzir código HTML a
ser exibido no navegador do usuário.
Encontra-se como apêndice uma listagem com os principais elementos da VTL - Velocity
Template Language usados para construção dos templates.
2.9
Hibernate
O Hibernate [Hib05] é um serviço de persistência objeto/relacional para sistemas escritos em
Java. Isto significa armazenar objetos em um banco de dados relacional ou fornecer uma visão
orientada a objetos de dados relacionais.
Diferentemente de outras ferramentas, o Hibernate permite que um objeto Java possa ser
persistindo em um banco de dados relacional, sem alteração de código. Como a Figura 2.23
exibe, o Hibernate cria uma camada transparente de persistência. Esta camada é responsável
por armazenar e recuperar os objetos do banco de dados sem que a camada de negócios do
sistema tenha conhecimento de como a persistência é realizada.
O Hibernate utiliza dois tipos de arquivos de configuração: um de mapeamento e outro de
configuração.
Para cada classe persistente do sistema deverá ser criado um documento XML com a extensão
“.hbm.xml”. Esse arquivo é responsável por descrever o mapeamento da classe em uma tabela
do banco de dados. O trecho de código 2.5 exibe um documento de mapeamento do Hibernate.
Exemplo 2.5 Arquivo de mapeamento do Hibernate
1 <?xml v e r s i o n =”1.0” e n c o d i n g =’ u t f −8’?>
2 <!DOCTYPE h i b e r n a t e −mapping PUBLIC
26
GERAÇÃO DE CÓDIGO: CONCEITOS, PADRÕES E TECNOLOGIAS
Figura 2.23 Hibernate
3
”−// H i b e r n a t e / H i b e r n a t e Mapping DTD 2 . 0 / /EN”
4
” h t t p : / / h i b e r n a t e . s o u r c e f o r g e . n e t / h i b e r n a t e −mapping − 2 . 0 . dtd”>
5
6 <h i b e r n a t e −mapping package=” s i g a . e s t r u t u r a F i s i c a . t i p o S a l a ”>
7
8
< c l a s s name=”T i p o S a l a ” t a b l e =”SIGA TIPO SALA”>
9
<i d name=”c o d i g o T i p o S a l a ” column=”CD TP SALA” />
10
<p r o p e r t y name=” d e s c r i c a o T i p o S a l a ” column=”DS TP SALA” />
11
</ c l a s s >
12
13 </h i b e r n a t e −mapping>
O código entre as linhas 1 e 4 representa o cabeçalho do documento. Na linha 6, declara-se
o pacote da classe. Na linha 8, tem-se a declaração da classe e da tabela mapeada. O atributo
name representa o nome da classe e table o nome da tabela. O identificador da classe e a
chave primária da tabela são declarados na linha 9, através do elemento id. No elemento estão
armazenados o nome do atributo da classe (name) e a coluna da tabela (column). Os atributos
da classe são declarados através de property.
O arquivo de configuração do Hibernate é responsável por armazenar dados sobre a conexão
com a base de dados, bem como listar todos os arquivos de mapeamento que deverão ser
utilizados.
2.10
Conclusões
Este capı́tulo teve como objetivo apresentar o estado da arte da geração de código através da
introdução de conceitos, padrões e tecnologias importantes para o estudo e compreensão deste
trabalho.
Apresentou-se o conceito de geração de código, os geradores ativos e os passivos e os geradores
MDA.
O conceito de mapeamento OO-Relacional e o impacto da impedância entre modelos foram
apresentados em seguida, ilustrando uma das motivações da realização deste trabalho.
Um dos pilares da solução proposta por este trabalho é a arquitetura MDA que determina a
2.10 CONCLUSÕES
27
abstração do sistema em três nı́veis de modelos distintos. A primeiro modelo, PIM, representa
a modelagem de negócio do sistema independente de plataforma e implementação. O segundo
modelo, PSM, é derivado do PIM e ilustra particularidades ligadas à tecnologia e plataforma de
implementação do sistema. O terceiro e último modelo é o próprio código de implementação.
Além de especificar os modelos a arquitetura MDA também especifica a transformações entre
eles, visto que esta deve ser realizada de forma automática.
Neste capı́tulo ainda foram apresentadas uma série de tecnologias utilizadas ao longo deste
trabalho entre elas: JMI, MDR, Velocity e Hibernate.
CAPÍTULO 3
TRABALHOS RELACIONADOS
Este capı́tulo apresenta o panorama atual dos ambientes geradores de código. Uma breve
análise será feita sobre os principais ambientes, ressaltando suas principais caracterı́sticas, funcionamento, vantagens e desvantagens do seu uso.
Durante o processo de análise foram selecionados os cinco ambientes geradores de código
mais relevantes atualmente e capazes de produzir código Java. Os critérios utilizados foram os
seguintes: tipo de licença, extensibilidade, usabilidade, GUI1 , tipo de entrada e saı́da, modelos
utilizados, o nı́vel de abstração e compatibilidade com o padrão MDA. Entre os ambientes
selecionados encontram-se dois ambientes open-source (XDoclet [WR03] e AndroMDA [And05]),
além de três ambientes com licenças comerciais (iQGen [iQg05], e-Gen [eG05] e Qualiti Coder
[Cod05]).
Este capı́tulo está dividido em seis seções. Cada uma das cinco primeiras seções apresenta
um ambiente gerador de código. Ao final de cada uma dessas seções são apresentados os pontos
relevantes ao uso do gerador. A última seção apresenta as conclusões sobre o panorama atual
dos ambientes geradores de código.
3.1
XDoclet
XDoclet [WR03] é um ambiente gerador de código open-source e permite que o código Java seja
gerado através da adição de metadados ao próprio código Java.
Segundo a classificação de Herrington [Her03], o XDoclet é um gerador de código que utiliza o
próprio código Java como input para geração de código. O parser XDoclet percorre o documento
em busca de tags Javadoc que são inseridas no próprio código-fonte e, de acordo com o template
definido, produz código-fonte.
Além das tags padrão, o XDoclet permite a definição de custom tags, marcações personalizadas criadas pelo usuário para atender a novas necessidades.
A utilização de um ambiente como o XDoclet pode trazer benefı́cios além daqueles diretamente ligados à geração de código como, por exemplo, a modularização do código, já que as
tags e diretivas de geração de código estão organizadas nos arquivos-fonte Java.
A ferramenta pode ser estendida através de uma vasta gama de módulos. Entre os principais
módulos existentes, destacam-se os que fornecem recursos para geração de código EJB [MH01],
JSP [Ber03], Hibernate [Hib05] e JDO [JR03]. O desenvolvedor pode ainda, através da criação
de templates personalizados, definir o tipo e o formato da saı́da.
O XDoclet funciona da seguinte forma: primeiro é definido um template XML, caso não
deseje-se utilizar um dos templates do ambiente e, em seguida, as tags necessárias são adicionadas aos arquivos-fonte. Por fim, o gerador é executado e o código-fonte produzido.
A Figura 3.1 ilustra um diagrama de classes UML do sistema modelado para facilitar a
compreensão da utilização do ambiente XDoclet.
1
Do inglês Graphical User Interface. Interface gráfica do usuário.
29
30
TRABALHOS RELACIONADOS
Figura 3.1 Diagrama de classes UML
Na Figura 3.1 tem-se: uma classe Empresa que possui uma coleção de objetos da classe
Funcionario.
No Exemplo 3.1 encontra-se o código-fonte Java da classe Empresa.
Exemplo 3.1 Código-fonte Java da classe Empresa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package exemplo ;
import j a v a . u t i l . * ;
public c l a s s Empresa {
// A t r i b u t o s da c l a s s e
public S t r i n g nome ;
public C o l l e c t i o n f u n c i o n a r i o s ;
// Metodos da c l a s s e
public void a d m i t i r F u n c i o n a r i o ( F u n c i o n a r i o f u n c i o n a r i o ) {
/* c o d i g o . . . */
}
public boolean v e r i f i c a r F u n c i o n a r i o ( F u n c i o n a r i o f u n c i o n a r i o ) {
/* c o d i g o . . . */
}
}
A linha 1 indica que a classe Empresa pertence ao pacote exemplo. A linha 3 importa
o pacote util que contém a classe Collection utilizada para representar uma coleção de
objetos. A linha 5 declara a classe pública Empresa. Nas linhas 7 e 8 estão definidos os dois
atributos privados de Empresa (nome do tipo String e funcionarios, uma coleção de objetos
Funcionario).
O código dos métodos admitirFuncionario e verificarFuncionario encontra-se entre as
linhas 11 e 17. O método admitirFuncionario possui como parâmetro um objeto da classe
Funcionario e não possui retorno. O método verificarFuncionario possui um retorno do
tipo boolean que indica se o funcionário está no quadro da empresa.
No Exemplo 3.2 encontra-se o código-fonte Java da classe Funcionario.
Exemplo 3.2 Código-fonte Java da classe Funcionario
1 package exemplo ;
2
3 public c l a s s F u n c i o n a r i o {
4
// A t r i b u t o s da c l a s s e
31
3.1 XDOCLET
5
private S t r i n g nome ;
6
private int i d a d e ;
7 }
O código acima é similar à definição da classe Empresa. A linha 1 indica que a classe também
pertence ao pacote exemplo. A declaração da classe pública Funcionario está na linha 3. Nas
linhas 5 e 6 estão declarados os atributos privados nome (tipo String) e idade (tipo int).
É importante ressaltar que os métodos de acesso aos atributos foram omitidos, pois poderiam
ser gerados facilmente pelo ambiente.
O Exemplo 3.3 ilustra o código que deseja-se produzir a partir dos exemplos 3.1 e 3.2.
Exemplo 3.3 Código de saı́da a ser gerado
1 Pacote: t e s t e
2 −− C l a s s e : Empresa
3
−− A t r i b u t o s
4
name:java . l a n g . S t r i n g
5
−− Metodos
6
admitirFuncionario
7
verificarFuncionario
8 −− C l a s s e : F u n c i o n a r i o
9
−− A t r i b u t o s
10
name:java . l a n g . S t r i n g
11
idade:int
O exemplo exibe uma listagem dos pacotes existentes bem como as classes, atributos e
métodos das classes. Para os atributos será exibido também o seu tipo.
O Exemplo 3.4 ilustra o template XDoclet utilizado para obter saı́da desejada.
Exemplo 3.4 Template XDoclet
1 <X D t P a c k a g e : f o r A l l P a c k a g e s>
2
P a c o t e : <XDtPackage:packageName />
3
<X D t C l a s s : f o r A l l C l a s s e s>
4
−− C l a s s e : <XDtClass:className />
5
−− A t r i b u t o s
6
<X D t F i e l d : f o r A l l F i e l d s>
7
<X D t F i e l d : f i e l d N a m e /> :<X D t F i e l d : f i e l d T y p e />
8
</ X D t F i e l d : f o r A l l F i e l d s>
9
−− Metodos
10
<XDtMethod:forAllClassMethods>
11
<XDtMethod:methodName/>
12
</ XDtMethod:forAllClassMethods>
13
</ X D t C l a s s : f o r A l l C l a s s e s>
14 </ X D t P a c k a g e : f o r A l l P a c k a g e s>
O template pode parecer um pouco confuso à primeira vista. Primeiramente, na linha 1
está a diretiva forAllPackages para processar e iterar por todos os pacotes encontrados. Em
seguida, na linha 2, define-se um texto para ser exibido e seguido do nome do pacote. Na linha
3, encontra-se a diretiva forAllClasses para processar e iterar por todas as classes encontradas
no pacote. Logo abaixo, na linha 4, está a impressão do nome da classe. As linhas 6 a 8 são
32
TRABALHOS RELACIONADOS
responsáveis pela impressão dos atributos da classe e de seus tipos. Por fim, nas linhas 10 a 12
estão as diretivas para imprimir os nomes dos métodos da classe.
Como percebe-se, a linguagem de definição dos templates é simples e ao mesmo tempo fornece
várias funcionalidades. O ambiente XDoclet possui ainda uma série de módulos que permitem a
geração de código sem a necessidade de criação de templates. No entanto, sua entrada de dados
está limitada a código Java. Assim, alguns elementos da análise orientada a objetos (como
associações, dependências e tagged values) são “perdidos”. A ferramenta também não possui
formas claras de integração entre as fases de análise e de implementação, pois a entrada é o
próprio código-fonte parcialmente implementado.
Existe ainda uma variante do XDoclet, chamada VDoclet [VDo05]. A principal diferença é
que o VDoclet utiliza a engine de templates Velocity [CG03], enquanto que o XDoclet utiliza
uma engine proprietária.
3.1.1
Pontos Relevantes
O XDoclet é uma ferramenta open-source e cada vez mais vem recebendo extensões seja na
forma de novos módulos ou novas versões do ambiente.
O ambiente XDoclet fornece uma boa usabilidade, visto que o uso de tags é simples, existe
bastante documentação disponı́vel, e, para muitos casos, quando se deseja obter resultados
rápidos sem incorporar um ambiente gerador de código ao processo de desenvolvimento do
sistema de informação, ele torna-se uma solução bastante atrativa.
Como o XDoclet aceita apenas como entrada arquivos Java, torna-se impraticável utilizálo para geração de código para outras linguagens. Por outro lado, o ambiente permite que
texto ASCII seja produzido como saı́da. Este recurso é bastante interessante pois facilita a
documentação, modularização, adequação a padrões de codificação e qualidade.
A utilização do XDoclet para geração de código fornece um nı́vel muito baixo de abstração,
visto que o próprio código-fonte é a entrada para o sistema. Sendo assim, não há implementação
da arquitetura MDA e muito menos integração entre as fases de Análise e Projeto e Implementação do sistema. Aqueles que necessitam de um nı́vel mais alto de abstração ou integração
entre diversas fases de desenvolvimento devem procurar um ambiente que implemente o padrão
MDA ou, pelo menos, aceite modelos como entrada.
A Tabela 3.1 apresenta um resumo dos pontos relevantes ao uso do XDoclet.
Caracterı́stica
Licença
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
Nı́vel
Open-source
Alta
Alta
Não
Limitado
Ilimitado
Não
Baixa
Não
Observações
Através de módulos
Vocabulário simples
Linha de comando
Apenas código Java
Produz texto, de acordo com o módulo
Apenas o nı́vel de implementação
-
Tabela 3.1 Pontos relevantes ao uso do XDoclet
33
3.2 ANDROMDA
3.2
AndroMDA
O AndroMDA [And05] é uma ferramenta open-source para geração de código. Foi criada por
Matthias Bohlen e atualmente é mantida por um pequeno conjunto de desenvolvedores. Seu
objetivo inicial era produzir apenas código EJB [MH01] utilizando como backend XDoclet e
Velocity e, por isso, era conhecida como “UML2EJB”.
O ambiente segue a arquitetura MDA, aceita como entrada modelos UML na forma de
documentos XMI [?], e é capaz de produzir qualquer tipo de arquivo ASCII como saı́da.
O AndroMDA possui um componente chamado Schema2XMI, que possibilita a leitura de
um modelo ER de banco de dados e a sua conversão para XMI. Porém, isto não se caracteriza
como uma forma de mapeamento entre o modelo Orientado a Objetos e o modelo EntidadeRelacionamento. Durante a análise do AndroMDA, verificou-se que a utilização do Schema2XMI
torna-se interessante apenas quando o sistema é produzido a partir do seu modelo de dados.
Existe uma série de módulos (conhecidos como “cartuchos”) para propósitos especı́ficos como
geração de código EJB, código Hibernate, etc. Muitos dos módulos existentes são capazes de
produzir a arquitetura completa de um sistema. Esses módulos são formados, geralmente, por
um ou mais templates e por um arquivo de configuração.
Os templates do AndroMDA são escritos em VTL - Velocity Template Language e, assim,
apresentam uma sintaxe simples e poderosa. O ambiente fornece uma série de classes e métodos
auxiliares que, como será visto adiante, facilitam a definição dos templates.
Caso seja necessário, pode-se desenvolver novos módulos para o ambiente. Porém, durante
o processo de análise da ferramenta, verificou-se que, apesar de fornecer módulos bastante
completos e um meio de criar novos módulos, este processo de criação não é simples visto que
é necessário um conhecimento mais aprofundado do ambiente.
Por tratar-se de um gerador ativo de código e que segue o padrão MDA, pode ser introduzido
no processo de desenvolvimento de software da empresa e participar de outras fases do processo
de desenvolvimento, além da fase de implementação.
O Exemplo 3.5 apresenta um trecho de código do template AndroMDA para geração de
classes básicas Java.
Exemplo 3.5 Template AndroMDA para geração de classes Java
1
2
3
4
5
6
7
p u b l i c c l a s s $ { c l a s s . name}
{
#f o r e a c h ( $ a t t i n $ c l a s s . a t t r i b u t e s )
#s e t ( $ atttypename=$ t r a n s f o r m . f i n d F u l l y Q u a l i f i e d N a m e ( $ a t t . type ) )
p r i v a t e $ atttypename $ { a t t . name } ;
#end
Na linha 1, tem-se a criação da classe, declarada pública. Na linha 4, verifica-se a utilização do comando Velocity foreach que será utilizado para percorrer todos os atributos
da classe e armazená-los na variável att. Na linha 5, o método auxiliar do AndroMDA
findFullyQualifiedName é utilizado para recuperar o tipo (nome qualificado) do atributo
e atribuı́-lo à variável atttypename. Em seguida, a linha 6 declara privado o atributo da classe.
O Exemplo 3.6 apresenta a criação de dois construtores da classe. O primeiro é um construtor
vazio (não recebe parâmetros). O segundo é um construtor que recebe como parâmetro todos
os atributos da classe e fará o armazenamento dos valores através dos métodos set.
34
TRABALHOS RELACIONADOS
Exemplo 3.6 Template AndroMDA para geração de classes Java
1
p u b l i c $ { c l a s s . name } ( )
2
{
3
}
4
5
p u b l i c $ { c l a s s . name}
6
$ transform . g e t A t t r i b u t e s A s L i s t ($ c l a s s , true , f a l s e )
7
{
8 #f o r e a c h ( $ a t t i n $ c l a s s . a t t r i b u t e s )
9
s e t $ { s t r . u p p e r C a s e F i r s t L e t t e r ( $ { a t t . name } ) } ( $ { a t t . name } ) ;
10 #end
11
}
Na linha 1, tem-se a declaração do construtor default da classe, ou seja, sem parâmetros.
O construtor declarado na linha 5 receberá todos os parâmetros. Os parâmetros são listados
através do método auxiliar getAttributesAsList que retornará todos os atributos da classe
na forma de uma lista (separados por vı́rgula). Em seguida, na linha 8, todos os atributos da
classe serão percorridos e armazenados, um a um, na variável att. Sendo assim, na linha 9, os
parâmetros serão armazenados através dos respectivos métodos set de cada atributo.
Finalmente, no Exemplo 3.7, são criados os métodos get e set para cada atributo da classe.
Exemplo 3.7 Template AndroMDA para geração de classes Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#f o r e a c h ( $ a t t i n $ c l a s s . a t t r i b u t e s )
#s e t ( $ atttypename = $ t r a n s f o r m . f i n d F u l l y Q u a l i f i e d N a m e ( $ a t t . type ) )
p u b l i c $ atttypename g e t $ { s t r . u p p e r C a s e F i r s t L e t t e r ( $ { a t t . name } ) } ( )
{
r e t u r n t h i s . $ { a t t . name } ;
}
public void
s e t $ { s t r . u p p e r C a s e F i r s t L e t t e r ( $ { a t t . name } ) } ( $ { atttypename } v a l u e )
{
t h i s . $ { a t t . name} = v a l u e ;
}
#end
}
O conjunto de atributos da classe é percorrido e armazenado na variável att, código da
linha 1. Em seguida, o tipo do atributo será armazenado na variável atttypename, linha 2,
que será utilizado como retorno do método get e parâmetro do método set. O código da
linha 3 apresenta a declaração do método get correspondente ao atributo. O nome do método é
formado pela palavra “get” e pelo nome do atributo com o primeiro caractere em letra maiúscula,
facilitado pelo método upperCaseFirstLetter. Na linha 5, tem-se o retorno do método, ou
seja, o valor do atributo.
O método set é criado pelo código que encontra-se entre as linhas 8 e 12. Percebe-se que
o método não possui retorno (void) e que seu nome é formato pela palavra “set” e pelo nome
do atributo com o primeiro caractere em letra maiúscula. O método recebe um parâmetro
chamado value, que tem o mesmo tipo do atributo na classe. Finalmente, na linha 11, o valor
é armazenado no atributo.
35
3.3 IQGEN
3.2.1
Pontos Relevantes
O AndroMDA é uma ferramenta open-source e cada vez mais vem ganhando atenção devido à
dedicação de sua equipe de desenvolvimento, que procura lançar sempre versões estáveis, com
novos recursos e bem testadas.
O ambiente AndroMDA fornece uma boa usabilidade, pois utiliza a linguagem VTL para
construção dos templates e ainda fornece um grande número de métodos auxiliares úteis na
construção dos templates. Esses métodos vão desde os que fornecem tratamento de strings até
métodos para retornar coleções de elementos do modelo UML em diversos formatos.
A documentação existente não está bem estruturada, tornando difı́cil a busca por métodos
existentes. Como implementa o padrão MDA, é possı́vel e recomendado inserir o ambiente no
processo de desenvolvimento do sistema de informação.
A utilização de modelos UML, na forma de documentos XMI, por parte do AndroMDA abre
um leque de opções em termos de geração de código. Pode-se gerar código para praticamente
qualquer tipo de linguagem de programação. A facilidade de “traduzir” modelos EntidadeRelacionamento para XMI pode ser um atrativo para as empresas nas quais o administrador de
banco de dados possui um papel chave na definição do projeto do sistema.
Há um grande número de módulos disponı́veis e o usuário pode estendê-los ou ainda criar os
seus próprios módulos. Contudo, criar um novo módulo requer um entendimento maior sobre o
ambiente.
A utilização do AndroMDA para geração de código fornece um nı́vel alto de abstração,
pois utiliza como entrada diagramas de classe UML produzidos nas fases de Análise e Projeto.
Empresas familiarizadas ou que desejam utilizar a arquitetura MDA facilmente se interessarão
por este gerador e poderão tirar proveito desta caracterı́stica rapidamente.
A Tabela 3.2 apresenta um resumo dos pontos relevantes ao uso do AndroMDA.
Caracterı́stica
Licença
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
Nı́vel
Open-source
Alta
Alta
Não
XMI
Ilimitado
UML e ER
Alta
Sim
Observações
Criação e alteração de Módulos
Requer conhecimento de métodos auxiliares
Linha de comando
Diagramas UML
De acordo com o módulo
Não permite mapeamento entre modelos
Modelos produzidos nas fases de Análise e Projeto
-
Tabela 3.2 Pontos relevantes ao uso do AndroMDA
3.3
iQgen
O ambiente iQgen [iQg05] é um gerador de código que possui licença comercial de utilização e,
diferentemente do XDoclet e do AndroMDA, fornece uma interface gráfica rica, composta por
um navegador de classes para facilitar a visualização e a seleção dos elementos do modelo; um
componente para verificação e validação de erros no modelo (UML Profile); e um painel que
36
TRABALHOS RELACIONADOS
apresenta um log das operações realizadas (Figura 3.2). Pela interface gráfica também é possı́vel
selecionar os arquivos de entrada, os templates de transformação e os arquivos produzidos pelo
ambiente.
Figura 3.2 Interface gráfica do iQgen
O ambiente possibilita a entrada de dados a partir de modelos UML em formato XMI e
produz uma saı́da textual. De acordo com os templates utilizados, pode-se gerar código para
praticamente qualquer linguagem de programação, assim como código documental (Javadoc,
HTML, etc).
O iQgen utiliza a arquitetura MDA para geração de código. Sendo assim, a conversão dos
modelos PIM e PSM é realizada através da escrita dos templates.
Diferentemente de ambientes como o AndroMDA, que já disponibilizam módulos ou templates para produção de código para algumas plataformas (ex: EJB, JavaDdoc, etc.), o iQgen
não possui nenhum módulo. Sendo assim, cabe aos usuários desenvolverem seus próprios
módulos. Os módulos são escritos utilizando a linguagem JSP, aceitando até taglibs 2 [Tag05].
Esta abordagem possibilita a utilização de APIs existentes para a linguagem Java no auxı́lio do
desenvolvimento dos templates.
O ambiente possui uma documentação bastante completa, fornecendo informação sobre os
elementos necessários para a criação de templates e para a utilização da ferramenta. Na documentação encontram-se exemplos que detalham a criação dos templates.
2
Trechos de código Java que servem para reduzir a complexidade de páginas JSP
37
3.3 IQGEN
O iQgen utiliza geração de código ativa de forma que blocos “protegidos” de código são
criados para que a lógica de negócio neles seja inserida e mantida em futuras iterações.
O ambiente possibilita a utilização de todos os elementos do modelo UML, mas não permite
a utilização de outros modelos.
O Exemplo 3.8, a seguir, ilustra um template para criação de classes básicas contidas em
um documento XMI.
Exemplo 3.8 Template iQgen para geração de classes Java
1
2
3
4
5
6
7
8
9
10
11
12
package <%=getPath ()%> ;
p u b l i c c l a s s <%=c l a s s n a m e%>
< i q g e n : i f expr=”<%=s u p e r c l a z z != n u l l%>”>
e x t e n d s <%=supername%> </ i q g e n : i f>
<i q g e n : u s e r c o d e i d=” g l o b a l ”>
// e s c o p o p r o t e d i g o
</ i q g e n : u s e r c o d e>
<%−− d e c l a r a c a o de a t r i b u t o s −−%>
<%@ i n c l u d e f i l e =” a t t r i b u t e s . j s p ” %>
O iQgen utiliza bastante a modularização de templates JSP de forma que o exemplo utilizado
aqui possui vários arquivos JSP. Todavia, apenas será apresentado o mais relevante, neste caso,
para criação da classe básica e de seus atributos.
Na linha 1, tem-se a definição do pacote ao qual pertence a classe. Em seguida, na linha 3,
define-se a classe com o modificador public.
Na linha 4, através da expressão iqgen:if verfica-se se a classe é generalização de outra
classe. Se for, tal relação será declarada através da cláusula extends seguida do nome da classe
superior, supername. Este código encontra-se na linha 5.
Na linha 7, tem-se a criação do escopo protegido para declaração de atributos globais da
classe. O código envolvido pelos tag iqgen:usercode deverá ser implementado pelo desenvolvedor e o ambiente será responsável por assegurar que o código seja preservado em futuras
iterações de geração de código.
Na linha 12, o comando include (comando da linguagem JSP) inclui um outro arquivo JSP,
neste caso, “attributes.jsp”, que será responsável pela criação dos atributos da classe. O código
do arquivo encontra-se no Exemplo 3.9.
Exemplo 3.9 Template iQgen para geração dos atributos de uma classes Java
1
2
3
4
5
6
7
8
9
10
<% C o l l e c t i o n a t t r = getMetaModel ( ) . g e t A t t r i b u t e s ( getElement ( ) ) ; %>
<%−− d e c l a r e a t t r i b u t e s −−%>
<i q g e n : f o r e a c h group=”<%=a t t r . i t e r a t o r ()%>” item=” a t t r i b u t e ”>
<%
S t r i n g attrName = getMetaModel ( ) . getName ( a t t r i b u t e ) ;
S t r i n g attrType = getMetaModel ( ) . getTypeName ( a t t r i b u t e ) ;
%>
p r i v a t e <%=attrType%> <%=S t r i n g H e l p e r . f d ( attrName)%> ;
</ i q g e n : f o r e a c h>
38
TRABALHOS RELACIONADOS
O código do Exemplo 3.9 apresenta, na linha 1, o acesso dos atributos da classe através do
método getMetaModel().getAttributes(getElement()) e o seu armazenamento na variável
attr. Como percebe-se, Collection é o tipo de attr, ilustrando uma das facilidades que o
iQgen fornece para os desenvolvedores/arquitetos familiarizados com as linguagens Java e JSP.
Em seguida, o comando iqgen:foreach realiza a iteração por todos os atributos da coleção
que serão armazenados, um a um, em attribute. As linhas 6 e 7 apresentam o código que
armazena o nome e o tipo do atributo nas variáveis attrName e attrType respectivamente.
Finalmente, na linha 9, é realizada a declaração do atributo da classe (private). O método
(API iQgen) StringHelper.fd garante que o primeiro caracter do nome do atributo será em
“caixa baixa”.
O Exemplo 3.10 ilustra o trecho do template responsável pela criação dos métodos de acesso
(get e set) aos atributos da classe.
Exemplo 3.10 Template iQgen para geração dos métodos get e set de uma classes Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<i q g e n : f o r e a c h group=”<%=a t t r . i t e r a t o r ()%>” item=” a t t r i b u t e ”>
<%
S t r i n g attrName = getMetaModel ( ) . getName ( a t t r i b u t e ) ;
S t r i n g attrNameFU = S t r i n g H e l p e r . f u ( attrName ) ;
S t r i n g attrType = getMetaModel ( ) . getTypeName ( a t t r i b u t e ) ;
S t r i n g instName = S t r i n g H e l p e r . f d ( attrName ) ;
%>
p u b l i c <%=attrType%> g e t<%=attrNameFU%>( ) {
<i q g e n : u s e r c o d e i d=”<%=\” g e t \ ”+attrNameFU%>”>
r e t u r n <%=instName%> ;
</ i q g e n : u s e r c o d e>
}
p u b l i c v o i d s e t<%=attrNameFU%>(<%=attrType%> p<%=attrNameFU%>)
<i q g e n : u s e r c o d e i d=”<%=\” s e t \ ”+attrNameFU%>”>
t h i s .<%=instName%> = p<%=attrNameFU%> ;
</ i q g e n : u s e r c o d e>
}
</ i q g e n : f o r e a c h>
{
Na linha 1, percorre-se todos os atributos da classe que são armazenados em attribute.
Em seguida, o código entre as linhas 2 e 7 armazena o nome do atributo em attrName, o nome
do atributo com o primeiro caractere em “caixa alta” em attrNameFU, o tipo do atributo em
attrType, e o nome da instância do atributo em instName. É importante notar que essas
atribuições são realizadas para simplificar a criação dos métodos como será visto a seguir.
O método get é declarado entre as linhas 9 e 13. Percebe-se que nas linhas 10 a 12 foi criado
um escopo protegido de código, tornando possı́vel ao desenvolvedor criar seu próprio corpo de
método.
O método set é declarado entre as linhas 15 e 19 e recebe como parâmetro uma variável de
nome p<%=attrNameFU%>, ou seja, o nome do atributo na classe com a primeira letra maiúscula
seguido do prefixo “p”. O tipo do parâmetro deverá ser o tipo do atributo da classe, neste caso,
attrType. Assim como o método get, o método set possui um escopo protegido de código,
linhas 16 a 18.
39
3.3 IQGEN
Assim como os geradores baseados na linguagem VTL, o iQgen é baseado na linguagem JSP
e fornece uma sintaxe completa para a escrita de templates. A API disponibilizada pelo ambiente
também supre as necessidades do desenvolvedor em termos de métodos auxiliares que facilitem
a transformação e a formatação de texto, além de acesso por meio de atalhos a elementos
do modelo. Tem-se como exemplo o método da API getMetaModel().getAttributes(), que
fornece, de forma direta, acesso a todos os atributos de um determinado elemento do modelo.
3.3.1
Pontos Relevantes
O iQgen é uma ferramenta comercial que atualmente encontra-se na versão 2.1 e que já atingiu
um grau de maturidade avançado. Este fato é demonstrado pelo número reduzido de bugs
observados durante a avaliação do ambiente.
A interface gráfica apresenta uma série de facilidades que ajudam na ótima usabilidade
do gerador, tais como: navegação e validação do modelo UML, painel com erros, arquivos de
entrada e saı́da. A construção dos templates escritos em JSP tornam a ferramenta atraente
para projetos que possuam em sua equipe conhecedores da linguagem JSP. Diferente de outros
ambientes o iQgen não traz em sua distribuição um grande número de templates, fica a cargo
dos desenvolvedores criarem os seus.
A API iQgen ainda fornece métodos auxiliares que facilitam e agilizam a construção dos
templates. Tais métodos provêem tratamento de texto e atalhos de acesso a elementos dos
modelos UML.
A documentação existente não está bem estruturada tornando difı́cil, algumas vezes, a busca
por métodos existentes. Como implementa o padrão MDA, é possı́vel e recomendado inserir o
ambiente no processo de desenvolvimento do sistema de informação.
A utilização do iQgen para geração de código fornece um nı́vel alto de abstração, pois utiliza
como entrada diagramas de classe UML produzidos nas fases de Análise e Projeto. Porém, não
é possı́vel realizar o mapeamento de modelos. Empresas familiarizadas com a arquitetura MDA
e dispostas a utilizar uma ferramenta comercial facilmente se interessarão por este gerador e
poderão tirar proveito desta caracterı́stica rapidamente.
A Tabela 3.4 apresenta um resumo dos pontos relevantes ao uso do iQgen.
Caracterı́stica
Licença
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
Nı́vel
Comercial
Alta
Alta
Sim
XMI
Ilimitado
UML
Alta
Sim
Observações
Criação de templates escritos em JSP
Possui muitos métodos auxiliares
Navegação e crı́tica de modelo UML
Diagramas UML
De acordo com os templates
Não permite mapeamento entre modelos
Modelos produzidos nas fases de Análise e Projeto
-
Tabela 3.3 Pontos relevantes ao uso do iQgen
40
3.4
TRABALHOS RELACIONADOS
e-Gen
Desenvolvido pela Gentastic!, o e-Gen [eG05] é um ambiente gerador de código comercial. Assim
como seu maior concorrente, o iQgen, o e-Gen possui uma interface gráfica que facilita a escrita
dos templates, visualização do modelo e geração de código.
Figura 3.3 Interface gráfica do e-Gen Modeler
O ambiente possui três componentes: o Modeler, o Design Portal e o e-Gen Design Data
Importer (eDDI).
O Modeler provê suporte para a definição de um modelo abstrato, arquitetura, framework
e, ainda, integração com sistemas de controle de versão. A Figura 3.3 apresenta a interface
principal do e-Gen Modeler.
O Design Portal fornece o acesso à arquitetura e à modelagem de negócio, geração de código
e, ainda, à integração com outros softwares inseridos no ambiente empresarial de desenvolvimento. A Figura 3.4 apresenta a interface principal do e-Gen Desgin Portal.
O eDDI, como o próprio nome indica, é responsável pela importação dos dados de design
de várias fontes como: diagramas UML, documentos XML, etc.
O e-Gen aceita diversos formatos de entrada, porém preferencialmente digramas UML ou
modelos de dados. Ele pode também produzir código ASCII para qualquer linguagem de programação através de templates escritos através de uma linguagem própria. Seguindo uma linha
oposta à seguida por outros ambientes, esta ferramenta fornece uma IDE para a construção
dos templates. Esta caracterı́stica facilita o trabalho para os iniciantes, porém atrapalha desenvolvedores familiarizados com o processo de edição manual de linhas de código. Também é
fornecida a linguagem eGENScript para criação dos templates.
41
3.4 E-GEN
Figura 3.4 Interface gráfica do e-Gen Design Portal
O e-Gen é um gerador MDA e, assim como os outros geradores deste tipo, utiliza os templates
para criação do PSM.
O ambiente possui uma documentação bastante completa na qual estão incluı́dos vários
tutoriais com exemplos de utilização do ambiente e um guia dos comandos do eGENScript.
Por ser um gerador de código ativo, o e-Gen pode ser facilmente inserido no processo de
desenvolvimento.
3.4.1
Pontos Relevantes
O e-Gen é uma ferramenta comercial que atualmente encontra-se em sua versão 2.5.1 e já atingiu
um grau de maturidade avançado.
A ferramenta valoriza sua interface gráfica e apresenta módulos que vão desde importação
e visualização de modelos até a IDE para construção dos templates. Os templates são escritos
em linguagem própria, chamada de eGENScript.
A ferramenta é capaz de gerar código para praticamente qualquer linguagem de programação.
O ambiente é bem documentado, possui tutoriais para diversos tipos de aplicação, bem como
um guia da linguagem eGENScript. Como implementa o padrão MDA é possı́vel e recomendado
inserir o ambiente no processo de desenvolvimento do sistema de informação.
A utilização do e-Gen para geração de código fornece um nı́vel alto de abstração, pois utiliza
como entrada para o sistema modelos (em sua maioria diagramas de classe UML) produzidos
nas fases de Análise e Projeto. No entanto, não dá suporte ao mapeamento de modelos. Em-
42
TRABALHOS RELACIONADOS
presas familiarizadas com a arquitetura MDA e dispostas a utilizar uma ferramenta comercial
facilmente se interessarão por este gerador e poderão tirar proveito desta caracterı́stica rapidamente.
A Tabela 3.4 apresenta um resumo dos pontos relevantes ao uso do e-Gen.
Caracterı́stica
Licença
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
Nı́vel
Comercial
Alta
Alta
Sim
XML
Ilimitado
UML
Alta
Sim
Observações
Templates escritos em linguagem própria
IDE facilita desenvolvimento de templates
Navegação e importação de modelos
Diagramas UML e modelos de dados
De acordo com os templates
Não permite mapeamento entre modelos
Modelos produzidos nas fases de Análise e Projeto
-
Tabela 3.4 Pontos relevantes ao uso do e-Gen
3.5
Qualiti Coder
O Qualiti Coder [Cod05] é um gerador de código produzido pela Qualiti, empresa pernambucana, sediada no Porto Digital. A ferramenta possui licença comercial e é distribuı́da na forma
de um plug-in para IDEs, entre eles Eclipse [Ecl05a] e JBuilder [JBu05].
O Qualiti Coder, diferentemente do iQgen e do e-Gen, funciona como um wizard integrado
ao ambiente de desenvolvimento. Esta caracterı́stica torna simples a sua utilização.
A versão de demonstração utilizada para avaliação possui alguns wizards para geração de
classes com diversos padrões de código como “Adapter”, “EJB Data Collection”, “JDBC Data
Collection”, “Singleton”.
Como entrada no sistema são aceitas apenas arquivos de classes Java e C#, que são as únicas
linguagens para as quais o Qualiti Coder produz código. O código é transformado através do
JaTS [COS+ 01].
O ambiente é bem documentado e possui funcionalidades para realizar refactoring, auditoria
de código e coletar métricas.
A criação de wizards só pode ser realizada pela fabricante por demanda.
3.5.1
Pontos Relevantes
Não se teve acesso ao código fonte dos wizards, fato este que, infelizmente, impossibilitou uma
avaliação mais criteriosa do gerador.
A Tabela 3.5 apresenta os pontos relevantes ao uso do Qualiti Coder.
3.6
Conclusões
Este capı́tulo apresentou os principais ambientes geradores de código com enfoque na geração
de código Java. Foram analisadas, de acordo com a sua relevância ao tema, ferramentas open-
43
3.6 CONCLUSÕES
Caracterı́stica
Licença
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
Nı́vel
Comercial
Baixa
Média
Sim
Classes
Limitado
Não
Baixa
Não
Observações
Wizards criados apenas sob demanda pelo fabricante
Utilizado apenas como plug-in de IDE
Em forma de wizards na IDE
Java e C#
Apenas para Java e C#
Apenas no nı́vel de implementação
-
Tabela 3.5 Pontos relevantes ao uso do Qualiti Coder
source (XDoclet e AndroMDA) e ferramentas comerciais (iQgen, e-Gen e Qualiti Coder), dentro
de um vasto conjunto de ferramentas disponı́veis.
A tabela 3.6 apresenta um resumo com as principais caracterı́sticas dos ambientes analisados.
Open-source
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
XDoclet
sim
alta
alta
não
Java
vários
não
baixa
não
AndroMDA
sim
alta
alta
não
xmi
vários
UML e ER
alta
sim
iQgen
não
alta
alta
sim
xmi
vários
UML
alta
sim
e-Gen
não
alta
alta
sim
xml
vários
UML
alta
sim
Coder
não
baixa
baixa
sim
Java
java
não
baixa
não
Tabela 3.6 Principais caracterı́sticas dos ambientes analisados
Enquanto o XDoclet é uma ferramenta que pode ser facilmente utilizada por desenvolvedores
para facilitar algumas atividades, o AndromMDA, pode gerar uma arquitetura completa do
sistema. O iQgen e o-Gen são ferramentas comerciais bastante completas e bem documentadas,
enquanto que o Qualiti Coder cria uma dependência do fabricante para criação dos wizards.
Nos ambientes open-source não verificou-se a existência de uma interface gráfica que auxiliasse a geração de código ou visualização de modelos.
Em nenhum dos ambientes analisados foi possı́vel utilizar simultaneamente ou mapear diferentes modelos de entrada.
Durante a pesquisa e avaliação das ferramentas, ficou claro que quando o assunto é geração
de código não existe a ferramenta definitiva. Cada uma possui aspectos positivos e negativos.
Portanto a tarefa de escolha de um ambiente gerador de código deve contemplar uma extensa
comparação entre as principais caracterı́sticas de cada uma das ferramentas analisadas, dependendo principalmente do contexto onde se pretende utilizá-las.
CAPÍTULO 4
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM
MAPEAMENTOS DE MODELOS
Este capı́tulo apresenta o ambiente XO2 , um ambiente gerador de código MDA baseado em
mapeamentos de modelos. Primeiramente, será mostrada uma visão geral do ambiente e seus
principais elementos. Em seguida, serão apresentados os diversos tipos de arquivos de entrada.
Logo após, a arquitetura do ambiente será explicada e, finalmente, o documento M3 L para
mapeamento de modelos será detalhado.
4.1
Visão Geral
O XO2 é um ambiente gerador de código, baseado no mapeamento de modelos de Análise e
Projeto e foi projetado primeiramente para atender às necessidades de sistemas de informação
orientados a objetos que possuem persistência de dados em SGBDs relacionais. Sua utilização,
contudo, não está limitada a apenas este tipo de geração de código. Com o XO2 pode-se gerar
virtualmente qualquer tipo de código, através da criação de templates personalizados, criados
pelos próprios usuários de acordo com suas necessidades.
A grande maioria dos ambientes geradores de código utiliza apenas um modelo de entrada,
geralmente um diagrama de classes UML. Porém, apenas um diagrama de classes não é suficiente
para descrever mesmo a estrutura mais simples de um sistema.
Nesse aspecto, o XO2 , com o intuito de possibilitar a utilização de um ou mais modelos,
fornece um nı́vel maior de abstração e a capacidade de lidar com mais detalhes das fases de
análise e projeto de um sistema de informação.
O ambiente XO2 segue a arquitetura MDA [KWB03], desta forma, precisam ser definidos:
um modelo independente de plataforma (PIM), um modelo especı́fico para a plataforma de
implementação (PSM), além de regras de transformação entre os modelos.
O conceito de Geração Ativa de Código foi utilizado para que todo o código produzido possa
ser reaproveitado em futuras gerações de código.
Uma abordagem de mapeamento entre modelos possibilita ao analista e ao arquiteto lançar
mão de uma gama de outros modelos para auxiliar na descrição e no detalhamento do sistema
modelado. Como será visto mais adiante, a utilização do modelo ER em conjunto com o modelo
OO aumentará substancialmente o poder de criação dos templates e geração de código tornando
o processo de geração de código mais preciso e completo. A Figura 4.1 ilustra uma visão geral
do ambiente XO2 .
O sistema permite que sejam utilizados até três tipos diferentes de arquivos de entrada: um
documento XMI (modelo OO), um documento M3 L (mapeamento de modelos) e um documento
com as regras de transformação (template). Tais arquivos descrevem o sistema modelado e as
regras de transformação que serão processadas pelo ambiente.
O documento XMI é constituı́do pelo conjunto de elementos do modelo de análise e projeto
escrito originalmente em linguagem UML.
45
46
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
Figura 4.1 Visão Geral do XO2
O documento M3 L contém um mapeamento de modelos e é escrito em linguagem XML.
O documento M3 L é opcional e foi proposto por este trabalho com objetivo de descrever os
mapeamentos dos elementos do diagrama de classes em elementos de outros modelos, como por
exemplo: tabelas e colunas, widgets HTML, etc.
Finalmente, os templates são arquivos escritos seguindo o padrão Velocity e descrevem as
regras de transformação de elementos do modelo de análise em estruturas de código de uma
linguagem de programação qualquer. A Figura 4.1 ilustra três possı́veis tipos de código de saı́da:
Java, SQL e textos ASCII. Isso mostra que, na verdade, o ambiente pode gerar uma gama bem
maior de tipos de código.
4.2
Arquivos de Entrada
Os arquivos de entrada formam a base do ambiente XO2 , eles são os responsáveis por descrever
o problema a ser resolvido. Como foi explicado na seção anterior, o ambiente possui três tipos
de arquivos de entrada, dos quais dois são obrigatórios, o XMI e o template de transformação,
e um opcional, o documento M3 L.
Nas seções seguintes serão explicados os detalhes e as particularidades de cada um dos tipos
de entrada do ambiente XO2 .
4.2.1
O Diagrama de Classes
Seguindo a metodologia RUP [Kru00], o diagrama de classes, contido em um documento XMI,
é produto das fases de análise e projeto, quando o analista define o conjunto de entidades de
negócio do sistema. O documento XMI é produzido por uma ferramenta CASE1 . Este docu1
Do inglês Computer-Aided Software Engineering. Ferramenta que auxilia na construção de modelos e diagramas utilizados pela Engenharia de Software.
4.2 ARQUIVOS DE ENTRADA
47
mento representa o modelo PIM da arquitetura MDA e contém os dados relevantes ao negócio.
Os detalhes sobre a arquitetura utilizada durante a implementação devem estar presentes no
modelo PSM.
O usuário do ambiente XO2 não precisa conhecer os detalhes de um documento XMI pois
o processo de manipulação é realizado pelo ambiente. A versão atual do ambiente XO2 é
compatı́vel com a versão 1.4 da linguagem UML. Para o usuário do ambiente, o documento XMI
é uma camada de abstração transparente, que representa as entidades do modelo e como elas
relacionam-se entre si. Mesmo sem precisar conhecer o XMI, pequenas correções ou alterações
no modelo podem ser realizadas diretamente no documento, a fim de tornar o processo mais
rápido.
Um fato importante sobre a geração de código é que a qualidade do código produzido pelo
ambiente está diretamente ligada à qualidade dos modelos e dos templates utilizados como
entrada.
4.2.2
O Template Velocity/XO2
O XO2 foi concebido para atender às caracterı́sticas da arquitetura MDA, portanto, tem-se a
necessidade de uma linguagem para produção de templates na qual as regras de transformação
entre os modelos PIM e PSM possam ser descritas com um certo nı́vel de detalhes. A linguagem
deve ser simples de utilizar, ter um rápido aprendizado e ao mesmo tempo ser poderosa. Duas
abordagens poderiam ser empregadas: criar uma nova linguagem ou utilizar uma linguagem já
existente.
Criar uma nova linguagem seria bastante complicado, principalmente, pelo tempo reduzido e
desvio de foco que este trabalho teria. Optou-se, então, por utilizar uma linguagem já existente
e que já estivesse consolidada. A linguagem deveria ser voltada para a criação de templates e
documentos texto.
Foi analisada a utilização de JSP [Ber03], por fazer parte da arquitetura Java, linguagem
nativa deste trabalho. No entanto, a utilização de JSP requeriria dos usuários conhecimentos
mais aprofundados da linguagem Java e do jargão JSP que, de certa forma, difere da linguagem
Java.
Poder-se-ia, ainda, ter utilizado XDoclet [WR03], no entanto, toda a filosofia do ambiente
XO2 deveria ser revisitada, já que o XDoclet pressupõe que as classes já estejam criadas e repletas
de anotações Javadoc. Caso fosse utilizado um ambiente como o XDoclet, teria-se que gerar
documentos com código-fonte Java acrescido de comentários que indicassem as transformações,
isso colocaria alguns passos a mais no processo e sua utilização não traria grandes benefı́cios.
Feitas as considerações acima, foi escolhida a linguagem VTL - Velocity Template Language
[CG03], pela sua simplicidade e por prover todos os recursos necessários para a transformação
de modelos. Foi fator importante na escolha da linguagem VTL a sua capacidade de extensão
através do acréscimo de novos elementos para atender às necessidades do XO2 . A compatibilidade com a linguagem VTL foi mantida tornando todos os comandos da linguagem utilizáveis
em um template XO2 . E, para tornar mais simples certas funcionalidades como a criação de
arquivos e a depuração, foram introduzidos alguns comandos que serão detalhados mais adiante.
Na criação dos templates, pode-se utilizar qualquer elemento definido no diagrama de classes.
Isso é possı́vel porque o XO2 adiciona o modelo UML ao contexto Velocity. O modelo é “contextualizado” no Velocity na forma de um modelo UML/XO2 que será explicado mais adiante
48
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
e, também, na forma de elementos MOF/UML, tornando a criação de templates mais flexı́vel.
Figura 4.2 Diagrama UML
A Figura 4.2 representa o diagrama de classes que será utilizado nos exemplos a seguir.
O diagrama é formado por duas classes: Carro e Marca. A classe Carro é constituı́da pelos
atributos: modelo do tipo string e ano e velocidade do tipo int. A classe Carro ainda
possui os métodos acelerar e frear, que recebem um inteiro com a quantidade de kilômetros
a incrementar ou decrementar na velocidade atual do carro e retornam a velocidade depois do
acréscimo ou decremento. O estereótipo entity da classe Carro será utilizado nos próximos exemplos para identificar as entidades que deverão ter código gerado. A classe Marca é constituı́da
pelos atributos nome e pais, ambos do tipo String.
O Exemplo 4.1 exibe o trecho de um template XO2 utilizado para listar o nome de todas as
classes do diagrama da Figura 4.2.
Exemplo 4.1 Template XO2
1
2
3
4
5
6
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
− c l a s s e : $ c l a s s e . name
#f o r e a c h ( $ a t r i b u t o i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
a t r i b u t o : $ a t r i b u t o . name
#end
#end
A linha 1 serve para recuperar e iterar por todas as classes do modelo. Na linha 2, o nome
da classe da iteração é impresso. Na linha 3, é feita uma iteração pelos atributos da classe,
que serão impressos na linha a seguir. O código-fonte gerado pelo exemplo pode ser visto no
Exemplo 4.2.
Exemplo 4.2 Código-fonte gerado pelo XO2
1 − c l a s s e : Marca
2 a t r i b u t o : nome
3 atributo : pais
4 − c l a s s e : S t r i n g − c l a s s e : Carro
5 a t r i b u t o : modelo
6 a t r i b u t o : ano
7 atributo : velocidade
É importante perceber que a classe String foi exibida na saı́da, pois na linguagem Java
string é uma classe e não um tipo primitivo.
49
4.2 ARQUIVOS DE ENTRADA
No Exemplo 4.3 tem-se um template para criação do código Java com a declaração das
classes: desta vez, será gerado código apenas para as classes que possuem o estereótipo entity.
Para isso será utilizado um filtro através de uma estrutura condicional if. Deverão, ainda, ser
criados atributos e métodos da classe.
Exemplo 4.3 Template XO2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
#i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” ) )
public f i n a l c l a s s $ { c l a s s e . name} {
/* * A t r i b u t o s */
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
$ a t t r i b u t e . v i s i b i l i t y $ a t t r i b u t e . dataType $ a t t r i b u t e . name ;
#end
/ * * Metodos * /
#f o r e a c h ( $ method i n $ c l a s s e . getMethods ( ) )
$ method . g e t S i g n a t u r e ( ) {
}
#end
/ * * Gets e S e t s * /
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
public $ a t t r i b u t e . dataType
g e t $ u t i l . getFirstToUpperC ase ( $ a t t r i b u t e . name ) ( ) {
return t h i s . $ a t t r i b u t e . name ;
}
public void s e t $ u t i l . getFirstToUpperCa se ( $ a t t r i b u t e . name ) (
$ a t t r i b u t e . dataType $ a t t r i b u t e . name ) {
t h i s . $ a t t r i b u t e . name = $ a t t r i b u t e . name ;
}
#end
}
#end
#end
O exemplo introduz uma série de novidades. Na linha 2, tem-se a condição if indicando que
apenas as classes que contiverem o estereótipo entity serão tratadas, as demais serão descartadas. Na linha 7, as propriedades (visibility e datatype) de um atributo são exibidas. Na
linha 12, tem-se o uso do método getSignature, esse método é uma das facilidades introduzidas pelo XO2 e retorna a assinatura completa de um método no padrão Java. Outros métodos
utilizados pelo ambiente serão apresentados no decorrer deste trabalho. O código a partir da
linha 17 ilustra a criação dos métodos de acesso aos atributos. Em geral, para cada atributo da
classe será criado um método get e um set.
Pelo resultado do Exemplo 4.4, percebe-se que que o tamanho do código do template é, na
maioria dos casos, menor que o código da classe gerada.
Exemplo 4.4 Código-fonte gerado pelo XO2
50
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
1 public f i n a l c l a s s Carro {
2
3
/* * A t r i b u t o s */
4
private S t r i n g modelo ;
5
private int ano ;
6
private int v e l o c i d a d e ;
7
8
/ * * Metodos * /
9
public int a c e l e r a r ( int kmh) {
10
}
11
public int f r e a r ( int kmh) {
12
}
13
14
/ * * Gets e S e t s * /
15
public S t r i n g getModelo ( ) {
16
return t h i s . modelo ;
17
}
18
public void setModelo ( S t r i n g modelo ) {
19
t h i s . modelo = modelo ;
20
}
21
public int getAno ( ) {
22
return t h i s . ano ;
23
}
24
public void setAno ( int ano ) {
25
t h i s . ano = ano ;
26
}
27
public int g e t V e l o c i d a d e ( ) {
28
return t h i s . v e l o c i d a d e ;
29
}
30
public void s e t V e l o c i d a d e ( int v e l o c i d a d e ) {
31
this . velocidade = velocidade ;
32
}
33 }
Nos exemplos apresentados até aqui, todo o código gerado foi exibido na interface gráfica
do ambiente. No entanto, na prática faz-se necessária a criação de arquivos onde o códigofonte possa ser armazenado. Esses arquivos, dependendo da complexidade e completude dos
templates, poderão ser compilados ou executados logo após a sua geração. O Exemplo 4.5
introduz as tags xo2.newfile e xo2.endfile que são utilizadas para a criação de arquivos
para armazenar o código-fonte produzido pelo ambiente.
Exemplo 4.5 Template XO2
1
2
3
4
5
6
7
8
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
#i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” ) )
#xo2 . n e w f i l e : $ ! { c l a s s e . name } . j a v a
public f i n a l c l a s s $ { c l a s s e . name} {
/* * A t r i b u t o s */
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
51
4.2 ARQUIVOS DE ENTRADA
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$ a t t r i b u t e . v i s i b i l i t y $ a t t r i b u t e . dataType $ a t t r i b u t e . name ;
#end
/ * * Metodos * /
#f o r e a c h ( $ metodo i n $ c l a s s e . getMethods ( ) )
$ metodo . g e t S i g n a t u r e ( ) {
}
#end
/ * * Gets e S e t s * /
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
public $ a t t r i b u t e . dataType g e t $ u t i l . getFirstToUpperCase (
$ a t t r i b u t e . name ) ( ) {
return t h i s . $ a t t r i b u t e . name ;
}
public void s e t $ u t i l . getFirstToUpperCase ( $ a t t r i b u t e . name ) (
$ a t t r i b u t e . dataType $ a t t r i b u t e . name ) {
t h i s . $ a t t r i b u t e . name = $ a t t r i b u t e . name ;
}
#end
}
#xo2 . e n d f i l e
#end
#end
Percebe-se que o código é bastante parecido com o do Exemplo 4.3, apenas foi adicionado
o código das linhas: 3 e 31. Na linha 3, informa-se para o ambiente que a partir dali todo o
conteúdo produzido deverá ser armazenado em um arquivo cujo nome é formado pelo nome
da classe acrescido da extensão “.java”. O conteúdo será armazenado em um documento denominado “Carro.java”. O ambiente irá armazenar o conteúdo de saı́da até que um comando
xo2.endfile seja encontrado.
O XO2 permite também que um mesmo template produza código em arquivo e código
impresso na tela. Isto é importante para realizar depurações ou até mesmo para se acompanhar
o processo de geração de código. Para tal, é preciso saber que todo o código de saı́da que não
estiver entre as tags xo2.newfile e xo2.endfile será impresso na tela.
O processo de desenvolvimento RUP indica que o código seja desenvolvido de forma iterativa
e incremental, ou seja, é provável que um código desenvolvido seja revisitado nas próximas
iterações de desenvolvimento para adição de novas funcionalidades ou correções de erros. Por
isso, faz-se necessário que o código-fonte produzido por um ambiente gerador de código, possa
ser alterado pelo desenvolvedor sem que tais alterações sejam perdidas nas próximas iterações.
Para possibilitar a geração ativa de código, o ambiente XO2 faz uso do conceito de escopo
protegido. Segundo este conceito, áreas especı́ficas de código serão criadas no código-fonte para
que o desenvolvedor possa escrever seu código sem que este seja perdido em futuras iterações.
A sintaxe de inı́cio de escopo protegido é a seguinte:
]xo2.begin : identif icador
52
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
e para finalizar:
]xo2.end : identif icador
onde identif icador é um identificador único para aquele escopo e deve ser igual no inı́cio e final
do escopo.
No Exemplo 4.6 mostra-se a utilização dos escopos protegidos. Cria-se um escopo protegido
para cada método, esse escopo protegido será utilizado pelos desenvolvedores para colocar as
regras de negócio necessárias para o funcionamento correto do sistema.
Exemplo 4.6 Template XO2
1
2
3
4
5
6
7
8
9
10
11
...
/ ** Metodos * /
#f o r e a c h ( $ metodo i n $ c l a s s e . getMethods ( ) )
$ metodo . g e t S i g n a t u r e ( ) {
/ ** #xo2 . b e g i n : $ method . g e t S i g n a t u r e ( ) : * /
/ ** #xo2 . end : $ method . g e t S i g n a t u r e ( ) : * /
}
#end
...
Pode-se notar no exemplo, linhas 6 e 7, a utilização das tags xo2.begin e xo2.end as
quais possuem a assinatura do método. Para cada método encontrado na classe será criado um
escopo protegido. Pode-se perceber, ainda, que as tags do escopo protegido foram colocadas
como comentários Java, isso faz-se necessário já que as tags serão armazenadas no arquivo de
saı́da e devem ser ignoradas pelo compilador para não provocar erros de compilação. Sempre
que o ambiente encontra um escopo protegido, o código contido na versão original do arquivo
(de uma iteração anterior) deve ser recuperado e armazenado no documento produzido.
Nas próximas vezes que o código for gerado, o conteúdo dos escopos protegidos será preservado. O desenvolvedor, no entanto, ficará com a tarefa de manter o escopo consistente com as
definições encontradas no modelo. Por hora, o escopo protegido de um método será removido
caso o seu método seja removido do modelo.
Em determinadas situações necessita-se imprimir algumas informações na tela, seja para
fins de depuração ou para informar o que está sendo processado no momento. Caso não esteja
dentro de um bloco xo2.newfile tudo será exibido na tela. Contudo, caso deseje-se imprimir
algo na tela mesmo dentro de um bloco xo2.newfile deverá ser utilizado o comando xo2.print.
Este comando não é “multi-linha” e sua saı́da será sempre na tela. A sintaxe do comando é a
seguinte:
]xo2.print : saida
onde saida é o conteúdo que se deseja ter impresso na tela. Pode conter texto puro ou tags do
template para serem processadas.
Muitas vezes o arquiteto lida com templates bastante extensos. Nessas horas é importante
lançar mão de um recurso chamado parsing. Através do comando parse o arquiteto poderá
53
4.2 ARQUIVOS DE ENTRADA
incluir vários templates dentro de um template. O código fica mais estruturado e mais organizado
e sua manutenção e entendimento são facilitados. A sintaxe do comando parse é a seguinte:
]parse(arquivo)
onde arquivo é o caminho do template a ser processado. Pode-se também utilizar uma variável
que referencie o caminho do arquivo.
O Exemplo 4.7 ilustra a utilização do comando parse. Caso a classe possua um estereótipo
entity o template executado será o “entity.vm”, caso contrário, será executado o “auxiliar.vm”.
Exemplo 4.7 Template XO2
1
2
3
4
5
6
7
8
9
...
#i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” ) )
#p a r s e ( ” e n t i t y . vm” )
#e l s e
#p a r s e ( ” a u x i l i a r . vm” )
#end
...
Com a apresentação desta subseção espera-se que o leitor tenha os subsı́dios necessários para
entender os templates que serão apresentados no restante deste trabalho.
4.2.3
O Mapeamento de Modelos
O documento M3 L - Model Mapping Markup Language, foi criado para suprir a inexistência
de um padrão capaz de armazenar o mapeamento entre um modelo orientado a objetos e os
demais modelos utilizados no processo de construção de um sistema.
No documento M3 L estão contidos os principais dados sobre cada modelo mapeado. A
Figura 4.3 ilustra o conceito de mapeamentos utilizados pelo ambiente XO2 .
Figura 4.3 Mapeamentos
Por conter os principais dados sobre cada modelo, o ambiente não precisa conhecer as particularidades de cada modelo em si.
54
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
Na versão atual do ambiente XO2 , o mapeamento foi realizado entre o modelo Orientado a
Objetos e o modelo Entidade-Relacionamento, conhecido como mapeamento OO-ER.
A estrutura do documento de mapeamento foi criada a partir de estudos feitos nos trabalhos
de Amber [Amb00]. Com o documento M3 L, ultrapassando a esfera do mapeamento OOER, pode-se representar praticamente qualquer tipo de mapeamento. Para isto, foi criado um
documento de mapeamentos que pode sofrer modificações e atender aos mais diversos requisitos.
O mapeamento utilizado segue a regra 1-1 (um para um). Isto indica que cada elemento de
um modelo deverá corresponder a um e somente um elemento de cada outro modelo mapeado.
A Figura 4.4 mostra os principais elementos de um mapeamento M3 L.
Figura 4.4 Principais elementos do mapeamento M3 L
O elemento maps é uma coleção de elementos do tipo map que por sua vez representa o
mapeamento de um elemento. O map pode representar um elemento do diagrama de classes
(e.g. classe ou atributo) e, ainda, um elemento do modelo relacional (e.g. tabela ou coluna).
Para representar os elementos de cada modelo são criados elementos do tipo node. Cada
node representa um nó do mapeamento. A versão atual do M3 L, permite utilizar N nós para
mapear vários modelos, apesar dos exemplos apresentados possuı́rem apenas dois nós.
O node possui uma série de propriedades (properties) que descrevem os dados relevantes
de cada modelo. Cada node corresponde a um modelo. O Exemplo 4.8 mostra a criação de um
mapeamento da classe Pessoa para a tabela PESSOA. A criação do mapeamento é realizada pela
tag map e pela atribuição de um valor ao atributo name.
O Exemplo 4.8 representa os principais componentes de um mapeamento.
Exemplo 4.8 Nó de mapeamento
1 <map name= ‘ ‘ Carro ’ ’>
2
<node i n d e x = ‘ ‘ true ’
3
name= ‘ ‘ Carro ’
4
<node i n d e x = ‘ ‘ f a l s e
5
name= ‘ ‘CARRO’
6 </map>
’
’
’
’
model = ‘ ‘ oo ’ ’
xo2Type = ‘ ‘ xo2 . uml . XO2Class ’ ’/>
’ model = ‘ ‘ e r ’ ’
xo2Type = ‘ ‘ ERTable ’ ’/>
As linhas 2 e 4 criam dois nós da classe modelada, um para o modelo OO e outro para o
modelo ER. Os atributos index, model, name e xo2Type são obrigatórios e formam a base do
mapeamento. O index indica se aquele nó será utilizado como ı́ndice nas buscas. Já model indica
a qual modelo pertence o nó. O name indica o nome do elemento no seu modelo (e.g. o nome da
classe Carro no diagrama de classes). Por fim, xo2Type indica o tipo daquele elemento, podendo
ser: classe (XO2Class), atributo (XO2Attribute), tabela (ERTable) e coluna (ERTableColumn).
55
4.2 ARQUIVOS DE ENTRADA
Um nó pode receber novas propriedades para aumentar o seu nı́vel de detalhes. Para fazê-lo
cria-se elementos property dentro de um nó. Um elemento property deve ter um nome e o seu
valor deve ser colocado como conteúdo texto do elemento property, como ilustra o Exemplo
4.9.
Exemplo 4.9 Inserindo property em um nó
1 ..
2
<node i n d e x = ‘ ‘ true ’ ’ model = ‘ ‘ oo ’ ’
3
name= ‘ ‘ Carro ’ ’ xo2Type = ‘ ‘ xo2 . uml . XO2Class ’ ’>
4
<p r o p e r t y name=” i s I n n e r C l a s s ”>f a l s e </p r o p e r t y >
5
</node>
6
<node i n d e x = ‘ ‘ f a l s e ’ ’ model = ‘ ‘ e r ’ ’
7
name= ‘ ‘CARRO’ ’ xo2Type = ‘ ‘ ERTable ’ ’/>
8 ..
Como forma de tornar mais simples e organizado o acesso aos elementos do documento, podese criar conjuntos de mapeamentos. O agrupamento de mapeamentos ajuda no entendimento
e organização do código XML e deve ser utilizado para representar atributos de uma classe e
colunas de uma tabela. O agrupamento deve ser armazenado dentro de um elemento map. No
Exemplo 4.10, exemplifica-se a criação do mapeamento de um atributo de uma classe em uma
coluna de uma tabela realizados dentro de um mapeamento classe/tabela.
Exemplo 4.10 Mapeamentos agrupados
1 <map name=” Carro ”>
2 ...
3
<maps>
4
<map name= ‘ ‘ modelo ’ ’>
5
<node i n d e x = ‘ ‘ true ’ ’ model = ‘ ‘ oo ’ ’
6
name= ‘ ‘ modelo ’ ’ xo2Type = ‘ ‘ xo2 . uml . XO2Attribute ’ ’/>
7
<node i n d e x = ‘ ‘ f a l s e ’ ’ model = ‘ ‘ e r ’ ’
8
name= ‘ ‘CARRO MODELO ’ ’ xo2Type = ‘ ‘ ERTableColumn ’ ’/>
9
</map>
10
</maps>
11 </map>
Como já foi dito anteriormente, o documento pode representar o mapeamento entre vários
modelos. No Exemplo 4.11 será ilustrado um mapeamento entre três modelos, sendo eles: o
modelo OO, o modelo ER e um modelo para representar elementos da GUI.
Exemplo 4.11 Mapeamentos
1 ...
2 <map name= ‘ ‘ modelo ’ ’>
3
<node i n d e x = ‘ ‘ true ’ ’ model = ‘ ‘ oo ’ ’
4
name= ‘ ‘ modelo ’ ’ xo2Type = ‘ ‘ xo2 . uml . XO2Attribute ’ ’/>
5
<node i n d e x = ‘ ‘ f a l s e ’ ’ model = ‘ ‘ e r ’ ’
6
name= ‘ ‘CARRO MODELO ’ ’ xo2Type = ‘ ‘ ERTableColumn ’ ’/>
7
<node i n d e x = ‘ ‘ f a l s e ’ ’ model = ‘ ‘ g u i ’ ’
8
name= ‘ ‘ Modelo ’ ’ xo2Type = ‘ ‘ e t c ’ ’>
9
<p r o p e r t y name=” r e q u i r e d ”>true</p r o p e r t y >
56
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
10
<p r o p e r t y name=” w i d g e t ”>e d i t </p r o p e r t y >
11
</node>
12 </map>
13 . . .
A quantidade de nós deve ser igual ao número de modelos mapeados. No exemplo, há
a criação de um modelo referente à representação gráfica dos atributos de uma classe e foi
necessário criar a propriedade required, que indica a obrigatoriedade do campo, e a propriedade
widget, que informa o tipo de componente gráfico que representará o atributo da classe.
No documento M3 L há o conceito de herança. Através do conceito é permitido que um
mapeamento herde os elementos de outro mapeamento. As duas principais utilidades de utilizar
herança no documento são: representar de forma fiel as heranças OO e estruturar o código
agrupando mapeamentos que se relacionam e, assim, evitar repetição. Quando um mapeamento
“herda” de outro diz-se que todos os maps contidos no “pai” estarão contidos no “filho”. Para
indicar que um mapeamento herda de outro basta colocar o atributo XML extends no elemento
map. A Figura 4.5 acrescenta uma herança entre Carro e Automovel.
Figura 4.5 Diagrama UML com herança
O Exemplo 4.12 mostra o código necessário para mapear a classe Automovel a uma tabela e
representar o mapeamento do atributo marca. Em seguida, faz também a declaração da relação
de herança do mapeamento Carro com Automovel.
Exemplo 4.12 Mapeamento com herança
1 ...
2 <map name=” Automovel ”>
3
<node i n d e x=” t r u e ” model=” oo ”
4
name=” Automovel ” xo2Type=” xo2 . uml . XO2Class ”/>
5
<node i n d e x=” f a l s e ” model=” e r ”
6
name=”AUTOMOVEL” xo2Type=”ERTable”/>
7
<maps>
8
<map name=” marca ”>
9
<node i n d e x=” t r u e ” model=” oo ”
4.2 ARQUIVOS DE ENTRADA
10
11
12
13
14
15
16
17
18
19
20
21
22
57
name=” marca ” xo2Type=” xo2 . uml . XO2Attribute ”/>
<node i n d e x=” f a l s e ” model=” e r ”
name=”CD MARCA” xo2Type=”ERTableColumn”/>
</map>
</maps>
</map>
<map name=” Carro ” extends=” Automovel ”>
<node i n d e x=” t r u e ” model=” oo ”
name=” Carro ” xo2Type=” xo2 . uml . XO2Class ”/>
<node i n d e x=” f a l s e ” model=” e r ”
name=”CARRO” xo2Type=”ERTable”/>
</map>
...
Para tornar mais breve o exemplo, os atributos da classe Carro foram omitidos. Entre as
linhas 2 e 15, encontra-se a criação de um mapeamento de nome Automovel. Em seguida,
foi criado um mapeamento Carro e na sua declaração (linha 16) informa-se, através da tag
extends, que este será uma herança do mapeamento Automovel. Para fins práticos, todos
os mapeamentos que estiverem contidos em Automovel também estarão contidos em Carro e,
assim, poderão ser acessados pelo ambiente.
O documento M3L permite overriding ou redefinição de elementos. Este conceito torna
possı́vel que um elemento definido no mapeamento “pai” possa ser redefinido pelo “filho”. O
Exemplo 4.13 apresenta uma modelagem diferente, onde o mapeamento marca está definido de
uma forma em Automovel e de outra em Carro.
Exemplo 4.13 Mapeamento com redefinição
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
<map name=” Automovel ”>
<node i n d e x=” t r u e ” model=” oo ”
name=” Automovel ” xo2Type=” xo2 . uml . XO2Class ”/>
<node i n d e x=” f a l s e ” model=” e r ”
name=”AUTOMOVEL” xo2Type=”ERTable”/>
<maps>
<map name=” marca ”>
<node i n d e x=” t r u e ” model=” oo ”
name=” marca ” xo2Type=” xo2 . uml . XO2Attribute ”/>
<node i n d e x=” f a l s e ” model=” e r ”
name=”CD MARCA” xo2Type=”ERTableColumn”/>
</map>
</maps>
</map>
<map name=” Carro ” extends=” Automovel ”>
<node i n d e x=” t r u e ” model=” oo ”
name=” Carro ” xo2Type=” xo2 . uml . XO2Class ”/>
<node i n d e x=” f a l s e ” model=” e r ”
name=”CARRO” xo2Type=”ERTable”/>
<maps>
<map name=” marca ”>
<node i n d e x=” t r u e ” model=” oo ”
name=” marca ” xo2Type=” xo2 . uml . XO2Attribute ”/>
58
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
25
<node i n d e x=” f a l s e ” model=” e r ”
26
name=”NM MARCA” xo2Type=”ERTableColumn”/>
27
</map>
28
</maps>
29 </map>
30 . . .
Percebe-se que, depois da redefinição do mapeamento Carro realizada entre as linhas 16 e
29, mesmo havendo uma herança de Carro para Automovel, para o ambiente a definição do
atributo marca da classe Carro que estará em vigor é definida por ele mesmo. O mapeamento
da classe Automovel permanece inalterado e não será afetado pela sobreposição.
Foram apresentados nesta seção os elementos constituintes de um mapeamento XO2 , esperase com isso que o leitor tenha capacidade de entender o restante deste documento.
4.3
Arquitetura das Classes XO2
Nesta seção apresenta-se uma visão geral das classes que constituem o ambiente XO2 . São
apresentados os principais pacotes, suas funções no ambiente, suas principais classes e métodos,
além de seus relacionamentos com outros pacotes do ambiente. A Figura 4.6 apresenta os
principais pacotes do ambiente, sendo eles: xo2, gui, uml, mapping e util.
Figura 4.6 Principais pacotes do ambiente XO2
4.3.1
O pacote xo2
Este pacote forma o núcleo do ambiente. Possui as classes responsáveis pela leitura de todos
os os documentos de entrada. A Figura 4.7 representa o diagrama de classes das principais
entidades do sistema. Apenas foram mantidos na figura os atributos e métodos relevantes.
A classe XO2CMD centraliza as funcionalidades principais do ambiente. Tem como responsabilidades a leitura dos documentos XMI (realizada através do MDR), a transformação dos dados
para a estrutura de classes do ambiente XO2 , a realização de chamadas às classes responsáveis
por diferentes funções e, finalmente, executar o mecanismo de geração de código.
A classe JavaReader é responsável pela leitura de qualquer arquivo com código-fonte. Ela
4.3 ARQUITETURA DAS CLASSES XO2
59
Figura 4.7 O pacote XO2
lê os arquivos para verificar se o código-fonte gerado deverá preservar algum escopo protegido.
Desta forma, quando o ambiente recebe o comando xo2.newfile (para armazenar o código em um
arquivo) a classe deverá fazer a varredura do arquivo origem à procura de escopos protegidos.
O conteúdo do escopos protegidos ficará armazenado temporariamente e será inserido no devido
lugar do código gerado.
A leitura do documento XML que contém os mapeamentos entre modelos e a criação das
classes de mapeamento são de responsabilidade da classe M3LReader que utiliza a API Xerces
[Apa05b] para realizar a leitura dos documentos XML. Assim que é executado o ambiente
verifica se o usuário informou um arquivo de mapeamento, caso ele tenha informado o sistema
inicializa a classe M3LReader, fazendo a leitura do documento de mapeamentos e deixando-a
pronta para retornar os mapeamentos solicitados pelo usuário.
4.3.2
O pacote gui
O pacote gui é responsável pela apresentação do ambiente para o usuário. O usuário tem duas
opções quando deseja executar o XO2 : executar o ambiente a partir da linha de comando ou
executar o ambiente a partir da interface gráfica.
A execução do ambiente a partir da linha de comando já foi explicada na seção anterior. A
interface gráfica foi criada para facilitar a utilização do ambiente fornecendo meios de selecionar
graficamente os arquivos de entrada do ambiente e fornecendo uma estrutura completa que
permite criar visualmente o documento M3 L com os mapeamentos entre os modelos.
A Figura 4.8 ilustra a interface gráfica de mapeamento de modelos fornecida pelo ambiente
XO2 .
No topo da interface gráfica encontram-se duas abas, que representam as duas opções do
ambiente quando executado: “Mapeamento”, que serve para produzir mapeamento de modelos,
e “Geração”, para executar o mecanismo de geração de código.
A interface gráfica de mapeamento permite visualizar, ao mesmo tempo, os elementos contidos no arquivo XMI e os elementos do Modelo Entidade-Relacionamento contidos no esquema
do banco de dados2 , o que possibilita a inserção do relacionamento entre esses elementos no
Documento de Mapeamento, visualizado como uma árvore de mapeamentos.
A interface permite que o usuário utilize um documento de mapeamento já existente (informando a localização e o nome do documento) ou que crie um novo documento.
O usuário seleciona o elemento do modelo OO na árvore da esquerda, faz a sua associação
(mapeamento) a um elemento do modelo ER na árvore da direita e através de um clique no botão
“+” (adicionar) será criado um elemento no documento de mapeamento. Suas propriedades
poderão ser alteradas através da edição dos campos que encontram-se abaixo da árvore central.
Como percebe-se, nesta versão do ambiente, a interface gráfica permite apenas realizar o
2
Na versão atual do ambiente são aceitos apenas documentos ANSI SQL.
60
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
Figura 4.8 A interface gráfica de mapeamento de modelos
mapeamento entre os modelos OO e ER, apesar do ambiente XO2 aceitar mapeamentos entre
o modelo OO e qualquer outro tipo de modelo.
A Figura 4.9 ilustra a aba de geração de código que é responsável pela seleção dos arquivos
de entrada, execução da geração de código e console para exibição das mensagens do ambiente.
4.3.3
O pacote uml
Para a implementação do ambiente XO2 resolveu-se utilizar um subconjunto dos elementos da
linguagem UML. A intenção não foi distorcer o padrão, mas sim criar uma forma mais rápida e
menos complicada de acesso aos elementos. O objetivo é reduzir bastante o código escrito nos
templates. É importante lembrar que esta é apenas mais uma forma de acessar os elementos do
modelo, pois será mantido o acesso aos templates seguindo o padrão UML.
A leitura dos documentos XMI, como falado anteriormente, é realizada no pacote xo2.
O pacote uml realiza o tratamento do modelo lido e o converte no modelo UML proposto pelo
ambiente XO2 . Os documentos XMI são verborrágicos, pois precisam ser versáteis e extensı́veis.
Porém, muitas estruturas criadas nestes documentos são de pouca utilidade para a geração de
código a partir dos diagramas de classe. Durante o decorrer desta seção serão explicadas as
principais entidades, as decisões de projeto que foram tomadas, por quê em alguns momentos
a modelagem original não foi seguida e de que forma o acesso aos elementos do modelo foi
4.3 ARQUITETURA DAS CLASSES XO2
61
Figura 4.9 A interface gráfica de geração de código
simplificada.
A Figura 4.10 ilustra a estrutura básica da modelagem UML do ambiente XO2 formada pela
interface XO2Element e implementada pela classe XO2ElementImpl. Quase todos os elementos
do pacote uml estendem a classe XO2ElementImpl. Os atributos da classe são: id, name,
visibility, owner, stereotypes e taggedValues. O identificador do elemento no modelo é
armazenado no atributo id, enquanto que name armazena o nome do elemento. O atributo
visibility indica a visibilidade (protected, public, package e private). O atributo owner
referencia o elemento no qual ele está contido, pois segundo o padrão UML os elementos estão
sempre contidos em outros elementos. A coleção stereotypes representa um conjunto de
elementos da classe XO2Stereotype. Finalmente, taggedValues é uma coleção de elementos do
tipo XO2TaggedValue. As classes XO2Stereotype e XO2TaggedValue serão explicadas a seguir.
Figura 4.10 A interface XO2lement
A classe XO2Stereotype é a representação de um estereótipo e possui um id e um name. O
primeiro representa o identificador do estereótipo no modelo e o segundo o nome ou valor do
estereótipo.
62
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
A classe XO2TaggedValue representa um Tagged Value e é formada por name e value. O
primeiro representa uma chave e o segundo representa um valor para a chave.
Como a Figura 4.11 ilustra, um pacote é representado pela classe XO2Package. Além
dos atributos oriundos da herança da classe XO2ElementImpl, a classe XO2Package possui:
ownedElements, ownedAssociations, ownedDependencies, entre outros atributos gerados pela
implementação de interfaces como XO2Namespace, XO2AssociationOwner, etc.
A interface XO2Namespace define que a classe que implementá-la deverá conter um atributo
ownedElements, sendo este uma coleção de elementos (classes, interfaces, pacotes).
A interface XO2AssociationOwner define uma entidade que pode possuir associações representadas por objetos da classe XO2Association. Vale lembrar que, assim como na modelagem original, todas as associações dos elementos de um pacote estão contidas no atributo
ownedAssociations. A interface XO2DependencyOwner possibilita que os relacionamentos de
dependência, oriundos de XO2Dependency, possam estar contidos no pacote, neste caso dependências entre pacotes, no atributo ownedDependencies.
As interfaces XO2GeneralizationOwner e XO2RealizationOwner seguem o mesmo princı́pio
da XO2DependendcyOwner, indicam a capacidade de armazenar generalizações e realizações nos
atributos ownedGeneralization e ownedRealizations. Os relacionamentos e as classes relativas serão explicadas a seguir.
Figura 4.11 A classe XO2Package
Seguindo a semântica da modelagem MOF original, classe, interface e datatype implementam
a interface XO2Classifier. A Figura 4.12 ilustra um classifier e os principais elementos a ele
atrelados.
Na modelagem UML do XO2 , uma classe é um objeto de XO2Class, enquanto que uma interface UML é representada por XO2Interface. Ambas possuem os atributos inerentes a herança
da classe XO2ElementImpl e, ainda, implementam XO2DependencyOwner, XO2RealizationOwner
e XO2GeneralizationOwner, interfaces que permitem o armazenamento de dependências, realizações e generalizações. A coleção features armazena o conjunto de atributos e métodos
contidos da classe. A Figura 4.13 conduz ao detalhamento das classes necessárias para a representação mas completa dos classifiers, atributos e métodos.
4.3 ARQUITETURA DAS CLASSES XO2
63
Figura 4.12 A interface XO2Classifier
Figura 4.13 A classe XO2Method
Assim como na modelagem original MOF, um datatype ou tipo de dados é, também, uma
implementação da interface XO2Classifier. A classe XO2DataType possui um atributo isClass
64
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
que indica se aquele tipo é um tipo básico ou um objeto de uma classe: caso seja uma classe, o
atributo classifier conterá o objeto referente ao tipo. No padrão UML tem-se originalmente
o datatype como uma generalização de tipo Primitive, para representação de tipos primitivos
como int e boolean; ProgrammingLanguageDataType, para representar tipos especı́ficos da
linguagem de programação; e Enumeration, para representar conjuntos. Na modelagem proposta, a combinação do atributo name com isClass e classifier possibilita representar todos
os possı́veis tipos de dados. Por exemplo, para armazenar o tipo básico int o atributo name de
datatype tem valor “int” enquanto que o atributo isClass tem valor “false” e classifier é
nulo. Já para representar um tipo originário de uma classe como é o caso do String, o atributo
name tem como valor o nome da classe, no caso, “String” enquanto que o atributo isClass tem
valor “true” e classifier tem como valor o objeto String.
A interface XO2Feature representa um feature (atributo ou método) do classifier. Um
atributo é representado pela classe XO2Attribute que possui, além dos atributos herdados de
XO2ElementImpl, o atributo dataType do tipo XO2DataType.
Um método é representado pela classe XO2Method e contém, além dos atributos herdados de
XO2ElementImpl, uma coleção de atributos do tipo XO2BehavioralFeature para representar
os parâmetros do método.
A classe XO2Parameter implementa a interface XO2BehavioralFeature e tem como função
representar os parâmetros de um método. Ela também é uma herança da classe XO2ElementImpl
e possui os atributos type do tipo String e dataType que são do tipo XO2DataType. Ambos
representam um tipo, a diferença está no fato do primeiro ser apenas uma referência para o
tipo. Isto ocorre porque o ambiente utiliza a técnica lazy evaluation para a atribuição dos tipos,
ou seja, é feita apenas no final da leitura de todo o documento XMI. Um método pode conter
zero ou mais parâmetros e o parâmetro de retorno do método, caso haja, terá o valor “return”
no atributo name.
A Figura 4.14 ilustra a modelagem dos relacionamentos no ambiente XO2 .
A interface XO2Association define uma associação UML. Segundo a modelagem do ambiente XO2 , XO2association deve ser implementada pelas classes XO2AssociationImpl e
XO2AssociationClass.
Para representar uma associação foi definida a classe XO2AssociationImpl que possui o
atributo ends que representa o conjunto de terminações de uma associação.
Para representar uma terminação da associação utiliza-se a classe XO2AssociatonEnd que
herda os atributos da classe XO2ElementImpl e possui os atributos navigable, multiplicity e
participant. O atributo navigable indica o sentido da navegação da associação. O atributo
Multiplicity é do tipo XO2Multiplicity que possui dois atributos, lower e upper, inteiros
para representar as cardinalidades da terminação. Por fim, o atributo participant armazena
o elemento que está relacionado à terminação.
A linguagem UML permite criar uma classe associativa que surge da associação entre duas
classes. Para representar uma classe associativa utiliza-se a classe XO2AssociationClass. Como
a linguagem Java não possui herança múltipla (herdar simultaneamente de XO2AssociationImpl
e XO2Class), fez-se com que a classe implementasse a interface XO2Association e estendesse a
classe XO2Class. A classe é um hı́brido de associação e classe, por isso possui a mesma estrutura
da classe XO2AssociationClass e herda os atributos de XO2Class e XO2AssociationImpl.
As representações de realização, XO2Realization, e de dependência, XO2Depedency, são
bastante parecidas. Ambas possuem os atributos supplier e client que pertencem ao tipo
4.3 ARQUITETURA DAS CLASSES XO2
65
Figura 4.14 Classes que representam os relacionamentos
XO2Classifier. Estes atributos representam os elementos e o seu papel no relacionamento. A
declaração de XO2Generalization é similar por possuir dois atributos do tipo XO2Classifier.
No entanto, por motivos conceituais, estes são conhecidos como parent e child, para descrever
melhor o papel de cada um no relacionamento.
A Figura 4.15 ilustra de forma mais clara a estrutura em que uma classe está contida em
um documento XMI.
Figura 4.15 Estrutura de um documento XMI
É relevante notar que os elementos em destaque representam os elementos transparentes
para o usuário do ambiente XO2 . Fica claro que o acesso direto ao documento XMI é bem mais
66
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
complicado para acessar por exemplo, um atributo ou tipo de parâmetro de método do que
acessá-los através da árvore de objetos criada pelo ambiente XO2 .
4.3.4
O pacote mapping
As classes responsáveis pela representação dos mapeamentos encontram-se no pacote mapping e
representam através de objetos Java todos os elementos contidos no documento de mapeamento
de modelos. Esses objetos são instanciados pela classe M3LReader do pacote xo2 e ficarão
disponı́veis para o ambiente. A Figura 4.16 apresenta o diagrama das classes do pacote.
Figura 4.16 O pacote mapping
A classe MapNode é a representação da entidade nó e representa todas as propriedades
referentes a um nó de um mapa dos mapeamentos do ambiente XO2 . A classe possui cinco
atributos: index, name, model, xo2Type e properties.
O atributo index é um booleano que indica se aquele nó é ı́ndice, ou seja, que será indexado
para tornar as consultas mais rápidas. Num tı́pico documento de mapeamento, o nó referente
ao modelo orientado a objetos terá seu atributo properties com valor “true” e os demais terão
valor “false”.
O atributo name indica o nome do nó. Na maioria dos casos o name é utilizado para armazenar
o valor principal daquele nó, ou seja, o valor principal daquele elemento em sua modelagem.
Tomando-se o Exemplo 4.10, percebe-se que o mapeamento idade representa o atributo idade
de uma classe Pessoa e tem valor “idade” para o nó do modelo OO e PESSOA IDADE para o
nó do modelo ER. A explicação é simples: como o nó do modelo representa os dados de um
atributo na classe, este será o nome do atributo, já no nó do modelo ER o atributo name deve
representar o nome da coluna da tabela, neste caso PESSOA IDADE. Não é possı́vel criar mais de
um nó com o mesmo nome em um mapeamento.
O atributo model indica a que modelo o nó está atrelado. Assim como o atributo name, não
é possı́vel criar mais de um nó para o mesmo modelo em um mapeamento.
O atributo xo2Type armazena o tipo do elemento no seu modelo de origem. Ele serve como
referência para, por exemplo, indicar que o mapeamento de um atributo de classe de um modelo
OO para uma coluna de uma tabela de um modelo entidade-relacionamento. Alguns valores
possı́veis para um atributo xo2Type são: UMLClass (classe), UMLAttribute (atributo), ERTable
(tabela) e ERColumn (coluna).
Os atributos ou propriedades que foram citados acima formam o conjunto básico de propriedades de um mapeamento. Contudo, caso o usuário deseje criar novas propriedades através
dos elementos property, estas serão armazenadas no atributo properties da classe Node. Isto
torna a modelagem de mapeamentos de modelos flexı́vel e, principalmente, extensı́vel.
4.3 ARQUITETURA DAS CLASSES XO2
67
A classe Map representa um mapeamento. O elemento map é a principal entidade do mapeamento, e representa a ligação entre uma entidade de um modelo e uma entidade de outro
modelo. A classe map é formada pelos seguintes atributos: name, nodes, maps e inheritance.
O atributo name armazena o nome daquele mapeamento. Apesar de aceitar qualquer nome
o usuário deve estar atento a alguns detalhes. O nome do mapeamento é utilizado como ı́ndice
de busca, ou seja, é mandatório que este tenha valor único em todo o documento. Também é
desejável que se utilize o caminho completo para a classe, desta forma os mapeamentos ficarão
organizados de forma intuitiva facilitando o entendimento e utilização do documento. Utilizando
esta convenção, um mapeamento de nome org.uml.package representaria a classe Package que
estaria dentro do pacote uml e este por sua vez estaria contido no pacote org.
Um das vantagens da utilização do mapeamento de modelos está na sua capacidade de
agrupar fı́sica e logicamente um conjunto de mapeamentos dentro de um mapeamento: este
conjunto é armazenado no atributo maps de tipo MapContainer. Quando vazio, este atributo
indica que não há mapeamentos internos. A classe MapContainer será explicada mais adiante.
Há, ainda, a possibilidade de criar herança entre dois elementos do tipo map. O ambiente
XO2 coloca no atributo inheritance do mapeamento “filho” o nome do mapeamento “pai”,
fruto de um auto-relacionamento de map. Isto indica que, se o mapeamento funcionario herda
do mapeamento pessoa, o atributo inheritance do funcionario terá valor “pessoa”. Assim
como no atributo maps, quando não há herança o atributo inheritance fica vazio.
A classe MapContainer cria o conceito de conjunto de mapeamentos. Em um documento
de mapeamento, ela pode aparecer em dois momentos: na raiz do documento, para armazenar
todos os elementos do tipo map, e dentro de um map, para armazenar os mapeamentos internos.
Como é apenas um elemento agrupador, a classe não possui nome.
A classe Maps, responsável pela representação de mapeamentos, é acessı́vel a partir dos
templates. O principal método desta classe é getMapProperty.
O método getMapProperty permite o acesso ao mapeamento, caso este tenha sido criado.
É com ele que pode-se indicar quais referências dos modelos serão utilizadas. O método recebe
como parâmetro o objeto no modelo OO (ı́ndice), o modelo no qual pretende-se buscar a referência e em seguida a propriedade que deseja-se retornar. A Figura 4.17 ilustra o mapeamento
da classe carro e de seus atributos para a tabela CARROS e suas colunas.
Figura 4.17 Mapeamento Classe/Tabela.
Para representar este mapeamento foi criado o arquivo de mapeamento do Exemplo 4.14.
Exemplo 4.14 Documento M2 L
1 . . . <map name=”Carro”>
2
<node i n d e x=”t r u e ” model=”oo ” name=”Carro ”
3
xo2Type=”xo2 . uml . XO2Class”/>
68
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
4
<node i n d e x=” f a l s e ” model=”e r ” name=”CARROS”
5
xo2Type=”ERTable”/>
6
<maps>
7
<map name=”i d ”>
8
<node i n d e x=”t r u e ” model=”oo ” name=”i d ”
9
xo2Type=”xo2 . uml . XO2Attribute”/>
10
<node i n d e x=” f a l s e ” model=”e r ” name=”ID”
11
xo2Type=”ERColumn”>
12
<p r o p e r t y name=”type”>INTEGER</p r o p e r t y >
13
</node>
14
</map>
15
<map name=”modelo”>
16
<node i n d e x=”t r u e ” model=”oo ” name=”modelo ”
17
xo2Type=”xo2 . uml . XO2Attribute”/>
18
<node i n d e x=” f a l s e ” model=”e r ” name=”MODELO”
19
xo2Type=”ERColumn”>
20
<p r o p e r t y name=”type”>VARCHAR(255) </ p r o p e r t y >
21
</node>
22
</map>
23
<map name=”ano”>
24
<node i n d e x=”t r u e ” model=”oo ” name=”ano ”
25
xo2Type=”xo2 . uml . XO2Attribute”/>
26
<node i n d e x=” f a l s e ” model=”e r ” name=”ANO”
27
xo2Type=”ERColumn”>
28
<p r o p e r t y name=”type”>INTEGER</p r o p e r t y >
29
</node>
30
</map>
31
<map name=” v e l o c i d a d e ”>
32
<node i n d e x=”t r u e ” model=”oo ” name=”modelo ”
33
xo2Type=”xo2 . uml . XO2Attribute”/>
34
<node i n d e x=” f a l s e ” model=”e r ” name=”VELOCIDADE”
35
xo2Type=”ERColumn”>
36
<p r o p e r t y name=”type”>INTEGER</p r o p e r t y >
37
</node>
38
</map>
39
</maps>
40 </map>
41 . . .
O Exemplo 4.15 apresenta o código do template necessário para gerar um código SQL que
criasse a tabela CARROS e, seguida, consultasse todos os seus registros.
Exemplo 4.15 Código para criar uma tabela e realizar uma consulta
1
2
3
4
5
6
7
8
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
CREATE TABLE ‘ $ maps . getMapProperty ( $ c l a s s e , ” e r ” , ”name ” ) ‘ (
#f o r e a c h ( $ a t r i b u t o i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
#i f ( $ a t r i b u t o . c o n t a i n s S t e r e o t y p e ( ”PK” ) )
#s e t ( $ chave=$ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ”name ” ) )
#end
‘ $ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ”name ” ) ‘
4.3 ARQUITETURA DAS CLASSES XO2
9
10
11
12
13
14
15
69
$ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ” type ” ) NOT NULL,
#end
PRIMARY KEY ( ‘ $ chave ‘ )
) #end
...
s e l e c t * from $ maps . getMapProperty ( $ c l a s s e , ” e r ” , ”name ” )
...
O código produzido no Exemplo 4.15 ilustra como o mapeamento pode ser utilizado de
forma simples e já retornando resultados bastante interessantes. Na linha 2, informa-se para o
ambiente retornar a propriedade name, do modelo ER relacionada com um objeto do modelo
OO, que neste caso será a tabela CARROS. Entre as linhas 5 e 7, verificou-se que o atributo da
classe contém o estereótipo PK, indicação de chave primária. Caso a condição seja satisfeita, será
colocado o nome do campo na tabela referente à chave primária na variável chave. Em seguida,
nas linhas 8 e 9, imprimiu-se cada um dos campos da tabela referente a um atributo da classe.
Na linha 11, a chave da tabela é definida pela variável $chave. Por fim, na linha 14, cria-se
uma consulta SQL que retorne todos os campos da tabela. O código produzido encontra-se no
Exemplo 4.16.
Exemplo 4.16 Código produzido pelo ambiente
1
2
3
4
5
6
7
8
9
10
11
...
CREATE TABLE ‘CARROS‘ (
‘ ID ‘ INTEGER NOT NULL,
‘MODELO‘ VARCHAR( 2 5 5 ) NOT NULL,
‘ANO‘ INTEGER NOT NULL,
‘VELOCIDADE‘ INTEGER NOT NULL,
PRIMARY KEY ( ‘ id ‘ )
)
...
s e l e c t * from CARROS
...
4.3.5
O pacote util
No pacote util encontram-se as classes auxiliares do ambiente, no entanto, apenas serão dados
os detalhes da classe Util, já que esta é a mais importante para a compreensão deste trabalho.
Como o leitor pôde verificar, o ambiente por si só já oferece uma série de ferramentas para
criar templates bastante completos. Porém, com a utilização do ambiente, o usuário sente a
necessidade de um número maior de métodos para agilizar seu trabalho. Meios de criar listas
de elementos com separadores, alterar a capitalização de caracteres, retornar lista de pacotes
importados por um classe foram criados e armazenados na classe Util para simplificar a criação
dos templates.
Durante a sua execução, a classe Util é passada como variável de contexto para o Velocity.
Dessa maneira, ela ficará disponı́vel em todo template através de chamadas aos seus métodos
estáticos.
O método mkTitle da classe Util tem como objetivo desmembrar as palavras compostas
de uma string. O método tem como parâmetros: uma string contendo o nome de um atributo
70
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
ou classe e retorna uma string com as palavras separadas por espaço. Por exemplo, tendo
como entrada o valor “NomePessoa” o método retornará o valor “Nome Pessoa”. Este método
é bastante útil para tratar nomes de atributos, classes, métodos que utilizam o padrão de
codificação Java [Sun05a].
Os métodos getFirstToUC e getFirstToLC recebem uma string como parâmetro e retornam
a mesma com o primeiro caracter em letra maiúscula e minúscula respectivamente.
Os métodos lc e uc, retornam todos os caracteres de uma string passada como parâmetro
em letras maiúsculas e minúsculas respectivamente.
O método commaArray apresenta um recurso bastante interessante, pois inúmeras vezes
durante a confecção dos templates depara-se com a necessidade de criar listas de elementos
contidos numa coleção. Além do mais, precisa-se utilizar separadores para criar tais listas.
Utilizando apenas a sintaxe fornecida pelos templates Velocity ficaria bastante trabalhoso
criar as listas. Sendo assim, criou-se o método commaArray, que na sua versão mais simples
recebe uma coleção como parâmetro e retorna os elementos da coleção separados por vı́rgulas.
Na versão mais completa, recebe um objeto da classe Collection como parâmetro, além do
conteúdo a ser impresso antes e depois do elemento, o separador entre os objetos da coleção e,
ainda, se o próprio elemento deve ser impresso ou não. O Exemplo 4.17 ilustra a utilização do
método commaArray.
Exemplo 4.17 Utilização do método commaArray
1 ...
$ u t i l . commaArray ( $ c l a s s e . g e t A t t r i b u t e s ( ) , ” ( ” , ” ) ” , ” , ” , t r u e ) . . .
A classe Util está contextualizada no template, sendo assim pode ser utilizada como uma
variável qualquer. Aplicado a uma coleção com os atributos da classe da Figura 4.5 que contém
os atributos marca, modelo, ano e velocidade o método commaArray tem como retorno o código
do Exemplo 4.18.
Exemplo 4.18 Retorno produzido pelo método commaArray
1 ( marca ) , ( modelo ) , ( ano ) , ( v e l o c i d a d e )
Como o exemplo ilustra, este método é bastante útil na criação de templates para produção
de código SQL.
Os métodos extendz e implementz são utilizados na criação de templates que geram código
java para classes e interfaces. Eles recebem como parâmetro o modelo UML e uma classe ou
interface e retornam uma string contendo, caso haja, as declarações extends e implements já
com as classes e interfaces que serão estendidas e implementadas. O Exemplo 4.19 mostra a
utilização dos métodos.
Exemplo 4.19 Utilização dos métodos extendz e implementz
1 . . . p u b l i c c l a s s $ c l a s s e . name
2
$ u t i l . e x t e n d z ( $ modelo , $ c l a s s e )
3
$ u t i l . implementz ( $ modelo , $ c l a s s e ) {
4 } ...
No Exemplo 4.20, tem-se o código produzido pelo Exemplo 4.19 quando aplicado a uma
classe Carro que estende a classe Automovel e implementa a interface Movel.
4.4 BIBLIOTECAS UTILIZADAS
71
Exemplo 4.20 Código produzido pelos métodos extendz e implementz
1 p u b l i c c l a s s Carro
2
e x t e n d s Automovel
3
implements Movel {
4 }
Estes foram os principais métodos auxiliares do criados no ambiente. Caso o usuário necessite
criar algum outro método este poderá ser criado na classe e automaticamente se tornará acessı́vel
pelo ambiente.
4.4
Bibliotecas Utilizadas
Para a construção de um ambiente que utiliza diferentes tecnologias e padrões, é importante realizar uma pesquisa cuidadosa por bibliotecas de componentes e APIs que já estejam validadas.
Durante a fase de projeto do ambiente, foi realizado um levantamento das tecnologias envolvidas baseando-se nas necessidades do projeto. A Figura 4.18 ilustra os principais bibliotecas
utilizadas pelo ambiente XO2 .
Figura 4.18 Principais componentes externos e apis utilizados pelo XO2
Primeiramente, tinha-se conhecimento da necessidade de uma biblioteca que auxiliasse na
leitura dos documentos XMI e que também fornecesse meios para acesso e manipulação dos
metadados contidos no documento. A biblioteca MDR foi escolhida por possibilitar de forma
simples a leitura, escrita e manipulação de documentos XMI. O MDR faz uso da API JMI, que
também foi utilizada pelo ambiente XO2 para acessar os elementos contidos no modelo UML.
Como já foi discutido anteriormente, foi tomada como decisão de projeto utilizar o Velocity
para criação dos templates. Para a leitura, manipulação e escrita dos documentos XML de
mapeamento foi utilizado o parser Xerces [Apa05b] fornecido pelo projeto Apache [Apa05a].
Um dos principais recursos do ambiente XO2 é a possibilidade do usuário utilizar a interface
gráfica para criar os documentos M3 L e para executar o mecanismo de geração de código.
72
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
A princı́pio, foi escolhida a API JFC/Swing [Sun05c], no entanto sua utilização é bastante
trabalhosa por possuir uma arquitetura mais robusta. Assim, optou-se pela API SWT [Ecl05b]
do projeto Eclipse [Ecl05a] por ser mais simples de utilizar.
A utilização de bibliotecas já estabelecidas tornou mais simples e ágil o desenvolvimento do
ambiente XO2 e permitiu seguir os padrões existentes.
4.5
O processo de desenvolvimento com o XO2
O processo de desenvolvimento de sistemas auxiliado pelo ambiente gerador de código XO2
é composto por quatro etapas, são elas: criação do Modelo OO (documento XMI), criação do
documento de mapeamento (documento M3 L, criação dos templates (documento VM) e geração
de código-fonte. A Figura 4.19 apresenta as etapas e os artefatos do processo de geração de
código do ambiente XO2.
Figura 4.19 Etapas do processo de geração de código do XO2
4.5.1
Criação do Modelo Orientado a Objetos
O processo é iniciado pela criação do Modelo OO com a visão de projeto do Modelo de Análise
(Conceitual) do sistema. O resultado desta etapa é a criação de um artefato com os detalhes
de arquitetura e plataforma necessários para a implementação do sistema. A construção do
modelo deve ser guiada por um processo de desenvolvimento de software. Neste estudo de caso
foi utilizada a atividade “Projetar Casos de Uso” do RUP.
Esta primeira etapa consiste na transformação do artefato PIM (Modelo de Análise) em um
artefato PSM (Modelo de Projeto) seguindo a arquitetura MDA. Esta etapa não é apoiada pelo
ambiente XO2, podendo ser utilizada para tanto, uma ferramenta de modelagem UML, como
ArgoUML [Tig05], Rational Rose [Rat05] ou Gentleware Poseidon [Gen05].
Ao final desta etapa, o documento XMI com os elementos do modelo de análise deve estar
definido.
4.5.2
Criação do Documento de Mapeamentos
A segunda etapa do processo consiste em produzir o documento de mapeamento M3 L, contendo os relacionamentos entre os elementos do Modelo de Projeto e os elementos do Modelo
Entidade-Relacionamento, responsável pela persistência dos dados do sistema, e demais modelos
utilizados.
O ambiente XO2 auxilia esta etapa através da “Interface para Mapeamento de Modelos”,
conforme foi apresentado na Figura 4.8. Esta funcionalidade permite visualizar ao mesmo tempo
os elementos do Modelo OO (lado esquerdo da figura) contidos no arquivo XMI e os elementos
do Modelo ER (lado direito da figura) contidos no esquema do banco de dados, o que possibilita
4.5 O PROCESSO DE DESENVOLVIMENTO COM O XO2
73
a inserção do relacionamento entre esses elementos no documento M3 L, visualizado como uma
árvore de mapeamentos (centro da figura).
Ao final desta etapa, o documento M3 L deve estar definido.
4.5.3
Criação dos Templates
A terceira etapa do processo de geração de código do ambiente XO2 consiste na criação de
templates contendo as regras de transformação.
Durante esta etapa é importante reconhecer padrões repetitivos de código. Quanto maior
for o conhecimento sobre o código produzido, mais padrões repetitivos serão reconhecidos e
conseqüentemente mais fluente será a produção de código.
Depois de identificados os padrões de código, será necessário escrevê-los como regras de
transformação nos templates. Cada padrão de código dá origem a uma regra de transformação.
Ao final desta etapa, um (ou mais) template deverá ser definido.
4.5.4
Geração do Código-fonte
A última fase do processo diz respeito à geração do código-fonte. É necessário que os três
artefatos produzidos nas fases anteriores estejam de acordo com o sistema modelado. Caso haja
inconsistência entre os modelos e os templates, a ferramenta informará ao usuário e apontará
os erros encontrados.
O ciclo de geração está concluı́do, porém, de acordo com as necessidades do negócio, o ciclo
poderá ser iterado várias vezes. A ferramenta permite que o código produzido em cada iteração
seja preservado ou atualizado de acordo com os requisitos da iteração.
Ao final desta etapa o código-fonte produzido está padronizado e com um tempo de desenvolvimento menor, está menos suscetı́vel a erros, e tem sua manutenção bastante facilitada, pois
a simples correção no template será propagada em todos os documentos gerados.
O ambiente XO2 pode ser integrado ao processo de desenvolvimento. Quando isto acontece os
benefı́cios da geração de código podem ser obtidos em sua plenitude, pois o ambiente deixa de
ser uma ferramenta de apoio à fase de implementação para ser uma peça chave nas etapas de
definição da arquitetura, análise e projeto, implementação e testes do sistema, como ilustra a
Figura 4.20.
Figura 4.20 Inserção do XO2 no processo de desenvolvimento tradicional
74
XO2 - UM GERADOR DE CÓDIGO MDA BASEADO EM MAPEAMENTOS DE MODELOS
A caracterı́stica de ser um ambiente gerador de código ativo e que segue a arquitetura MDA
torna o XO2 uma ferramenta poderosa quando aplicada ao processo iterativo, pois poderá
contemplar alterações nos requisitos e manutenção do sistema sem que haja perda do trabalho
realizado em iterações anteriores.
A Tabela 4.1 apresenta um resumo dos pontos relevantes ao uso do ambiente XO2 .
Caracterı́stica
Licença
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
Nı́vel
Open-source
Alta
Alta
Sim
Vários
Ilimitado
Vários
Alta
Sim
Observações
Criação e alteração de templates
Métodos fornecem acesso simples a elementos dos modelos
Mapeamento, visualização de modelos e geração de código
Diagramas UML, Modelos ER, etc
De acordo com o template definido
Permite e facilita o mapeamento entre modelos
Auxilia várias etapas do processo de desenvolvimento
-
Tabela 4.1 Pontos relevantes ao uso do XO2
4.6
Conclusões
Este capı́tulo detalhou o ambiente gerador de código XO2 . Baseado no mapeamento de modelos
e na arquitetura MDA, o ambiente possui três tipos de documentos de entrada: um documento
XMI que contém o modelo UML do sistema, um documento M3 L que representa o mapeamento
dos modelos e um template que apresenta as regras de transformação entre os modelos.
Também foram apresentados os principais pacotes de desenvolvimento, as principais bibliotecas utilizadas, a interface gráfica, e as principais funcionalidades do XO2 .
Finalmente, foram apresentadas as quatro etapas do processo de desenvolvimento com o
ambiente gerador de código. Tais etapas podem ser facilmente inseridas no processo de desenvolvimento dos sistemas de informação que utilizam o processo tradicional (RUP) devido ao
fato do ambiente ser um gerador de código que segue a arquitetura MDA.
CAPÍTULO 5
TESTES E RESULTADOS
No capı́tulo anterior foram apresentadas as principais caracterı́sticas do ambiente XO2 , detalhando seus principais componentes e sua arquitetura. Este capı́tulo apresenta os testes e
resultados sobre os estudos de caso utilizados para validar o ambiente desenvolvido.
O primeiro estudo de caso tem como foco a avaliação da capacidade de leitura de modelos
UML e geração de código para produção de websites dinâmicos utilizando a linguagem de programação Perl [WCO00]. Neste estudo de caso, as funcionalidades de mapeamento de modelos
não foram testadas.
O segundo estudo de caso tem como objetivo utilizar todo o potencial do ambiente XO2 .
Para tal, foram criados templates capazes de gerar código de implementação de toda a arquitetura do SIG@UFPE - Sistema de Informação e Gestão Acadêmica [UFP05]. Tal código
dificilmente poderia ter sido produzido automaticamente sem uma estrutura que possibilitasse
o mapeamento de modelos UML e tabelas já existentes.
Ao final do capı́tulo serão apresentados os resultados obtidos com a utilização do ambiente
gerador de código XO2 .
5.1
Gerando código para sites da web
A fim de provar a capacidade do ambiente XO2 de gerar código de forma análoga aos ambientes
existentes, resolveu-se utilizar uma linguagem de programação simples e capaz de, em poucas
linhas de código, criar websites dinâmicos. A linguagem de programação Perl foi escolhida por
ser interpretada e por lidar com documentos em formato texto de forma nativa.
A aliança da simplicidade da sintaxe Perl e da tecnologia CGI [BGG00] torna bastante
poderosa a produção de websites com conteúdo dinâmico.
O código escrito para este estudo de caso tem como objetivo produzir páginas web dinâmicas
criadas automaticamente durante a navegação dos usuários no website.
O analista definirá um diagrama de classes e os templates fornecidos pelo arquiteto deverão
gerar a arquitetura pronta para ser executada. Desta forma, o código produzido pelo ambiente
XO2 deverá ser colocado em ambiente de produção de um servidor web e, sem a interferência
dos desenvolvedores, poderá ser executado. O ambiente também deverá produzir um script
SQL de criação do banco de dados.
A base de código produzida deverá permitir que os administradores do site possam atualizar
o cadastro dos elementos definidos durante a fase de análise. É importante perceber que, de
acordo com os templates escritos, o ambiente poderá produzir código para diferentes sites,
inclusive de áreas de negócio diferentes.
A Figura 5.1 ilustra a arquitetura que deverá ser produzida para o cadastro das entidades
modeladas.
Dois tipos de documentos deverão ser criados pelo ambiente. O primeiro, um documento
agrupador (“menu.pl” e “CreateSQL.sql”) criado para todas as classes do sistema, e o segundo,
75
76
TESTES E RESULTADOS
Figura 5.1 Documentos responsáveis pelo cadastro
um documento individual (“List.pl”, “Show.pl” e “Update.pl”) criado para cada entidade do
sistema.
O documento “menu.pl” é responsável pela montagem e exibição do menu de navegação do
website. Nele estarão contidas todas as opções fornecidas aos usuários. O documento “CreateSQL.pl” contém um script Perl de criação do esquema de banco de dados para todas as
entidades do sistema. Por simplificação, as tabelas possuirão os nomes de suas classes correspondentes e as colunas das tabelas serão nomeadas de acordo com os atributos das classe.
Para cada entidade do sistema deverá ser criado um documento <Classe>List.pl que
permite a listagem de todos os elementos daquele tipo cadastrados na base de dados e, para
cada elemento listado, fornece links para o detalhamento, atualização e criação de novos objetos.
O detalhamento da entidade ficará a cargo do script Perl <Classe>Show.pl para exibição ou
atualização da entidade. O documento <Classe>Update.pl conterá os comandos de atualização
de banco de dados para realizar inserções, atualizações e remoções.
A Figura 5.2 ilustra o diagrama de classes do Modelo de Projeto das entidades de negócio
utilizadas. O modelo já é uma conversão do PIM em PSM.
Figura 5.2 Modelo de projeto
A Figura 5.2 mostra duas classes entidades do sistema. A primeira é a classe Cliente que
possui um cadastro de todos os clientes da loja. A classe é formada pelos atributos: id e nome.
A classe Produto tem como atributos: id, descricao e preco. Os atributos id de cada classe
foram marcados com o estereótipo PK para indicação de chave-primária das tabelas criadas.
O documento “CreateSQL.sql” será utilizado para criação do esquema de banco de dados
contendo todas as tabelas. O script deverá produzir um script SQL compatı́vel com o banco de
5.1 GERANDO CÓDIGO PARA SITES DA WEB
77
dados MySQL [DuB02].
O código produzido deve ser semalhante ao do Exemplo 5.1.
Exemplo 5.1 Código-fonte do arquivo CreateSQL.sql
1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE ‘ C l i e n t e ‘ (
‘ id ‘ INT ( 1 1 ) NOT NULL a u t o i n c r e m e n t ,
‘ nome ‘ TEXT NULL,
PRIMARY KEY ( ‘ id ‘ )
) TYPE=MyISAM AUTO INCREMENT=1 ;
CREATE TABLE ‘ Produto ‘ (
‘ id ‘ INT ( 1 1 ) NOT NULL a u t o i n c r e m e n t ,
‘ d e s c r i c a o ‘ TEXT NULL,
‘ preco ‘ DOUBLE NULL,
PRIMARY KEY ( ‘ id ‘ )
) TYPE=MyISAM AUTO INCREMENT=1 ;
Na linha 1, tem-se o comando SQL CREATE TABLE seguido do na tabela “Cliente”. Em
seguida, na linha 2 especifica-se a coluna id de tipo INT(11) e, como é a chave-primária da
tabela, obrigatoriamente terá valor diferente de nulo. Ainda precisou-se definir o valor do campo
auto-incrementável, ou seja, será preenchido automaticamente pelo próprio banco de dados. Na
linha 3, define-se o campo nome de tipo TEXT e que pode ter um valor nulo. Na linha 4, declarase a coluna id chave-primária da tabela Cliente. Por fim, na linha 5, informa-se ao banco de
dados que a chave-primária receberá incrementos unitários. O código das linhas 7 a 12 contém
a declaração da tabela Produto similar à declaração da tabela Cliente.
A etapa de criação dos templates no processo de geração de código exige a identificação de
padrões repetitivos de código. Esses padrões repetitivos, depois de identificados, poderão ser
escritos nos templates para produção de código.
A análise do Exemplo 5.1 expõe os seguintes padrões:
P1 Cada classe do modelo que possuir o estereótipo entity deverá dar origem a uma tabela.
P2 A tabela deverá possuir o mesmo nome da classe.
P3 Cada atributo da classe deverá dar origem a uma coluna na tabela.
P4 A coluna deverá possuir o mesmo nome do atributo.
P5 Caso o atributo possua o estereótipo PK, ele não poderá ser nulo, deverá ser auto-incrementável
e ainda deverá ser declarado como PRIMARY KEY.
A criação do script SQL será realizada pelo documento “sql.vm” cujo conteúdo é baseado
no reconhecimento de padrões apresentado e encontra-se no Exemplo 5.2.
Exemplo 5.2 Template de criação do arquivo CreateSQL.sql
1
2
3
4
#macro ( t i p o b d $ t i p o )
#i f ( $ t i p o . name == ” i n t ” )
INT ( 1 1 )
#e l s e i f ( $ t i p o . name == ” S t r i n g ” )
78
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
TESTES E RESULTADOS
TEXT
#e l s e i f ( $ t i p o . name == ” d o u b l e ” )
DOUBLE
#end
#end
#xo2 . n e w f i l e : CreateSQL . s q l
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
#i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” ) )
CREATE TABLE ‘ $ c l a s s e . name ‘ (
#f o r e a c h ( $ a t r i b u t o i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
#i f ( $ a t r i b u t o . c o n t a i n s S t e r e o t y p e ( ”PK” ) )
‘ $ a t r i b u t o . name ‘ #t i p o b d ( $ a t r i b u t o . dataType ) NOT NULL a u t o i n c r e m e n t ,
#s e t ( $ chave= $ a t r i b u t o . name )
#e l s e
‘ $ a t r i b u t o . name ‘ #t i p o b d ( $ a t r i b u t o . dataType ) NULL,
#end
#end
PRIMARY KEY ( ‘ $ chave ‘ )
) TYPE=MyISAM AUTO INCREMENT=1 ;
#end
#end
#xo2 . e n d f i l e
Como não foi utilizado o mapeamento de modelos neste exemplo, foi necessário escrever
um código que faça a conversão dos tipos da linguagem Java para o banco de dados MySQL.
O código encontra-se na macro Velocity (linhas 1 a 9) que fará a conversão de tipos. Podese notar que a macro irá receber um tipo da linguagem Java e irá transformá-lo em um tipo
correspondente no banco MySQL, este tipo será retornado pela macro. Para o exemplo, apenas
foram tratados os tipos int, String e double. Outros tipos podem ser adicionados no futuro.
Os padrões P1 e P2 são representados no template pelo código que encontra-se entre as linhas
11 e 16. Na linha 11, é exibida a sintaxe de criação do documento “CreateSQL.sql” indicando
que o conteúdo produzido dali em diante será armazenado no documento “CreateSQL.pl”. Nas
linhas 13 e 14, faz-se a iteração e seleção de todas as classes do modelo que possuem o estereótipo
entity. A linha 16 produzirá o código para criar as tabelas.
Os padrões P3, P4 e P5 estão representados entre as linhas 18 e 28. Percebe-se que há dois
tipos de colunas nas tabelas das entidades modeladas: as que não são chave-primária, como
nome, descricao e preco; e as do tipo chave-primária, no caso, a coluna id das duas tabelas.
Na linha 18, a verificação do estereótipo PK é feita no atributo. Em seguida, é executada a
macro tipobd que irá converter o tipo do atributo da classe para um tipo correspondente no
banco de dados. Observe que o valor NOT NULL não permite que a coluna aceite valores nulos.
Já o auto increment fornecerá um novo valor a cada registro adicionado. Na linha 20, utiliza-se
uma atribuição para armazenar na variável chave o nome do atributo chave-primária da tabela.
Caso o atributo não seja chave-primária, seu código será produzido pela linha 22. Enquanto
a chave-primária não deve permitir valores nulos, neste estudo de caso, resolveu-se que os demais
5.1 GERANDO CÓDIGO PARA SITES DA WEB
79
campos pudessem assumir valor nulo.
Na linha 25 a chave-primária da tabela é definida. Na linha 26, definiu-se o valor do incremento e, por fim, na linha 30 informa-se o final do arquivo.
Não serão dados detalhes sobre a criação dos documentos “menu.sql” e “List.sql” por não
agregarem conhecimento aos exemplos aqui apresentados. A seguir serão apresentados os templates para criação dos documentos “Show.pl” e “Update.pl”.
O documento “Show.pl” exibirá os detalhes (todos os atributos) de uma entidade tanto para
exibição quanto para inserção ou atualização. O conteúdo do documento “ClienteShow.pl” está
representado no Exemplo 5.3.
Exemplo 5.3 Arquivo ShowCliente.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/ u s r / b i n / p e r l
i f ($FORM{ ’ acao ’ } eq ’ i n s e r i r ’ ) {
} e l s i f ($FORM{ ’ acao ’ } eq ’ a t u a l i z a r ’ ) {
$ s t h = $ dbh−>p r e p a r e ( ”
SELECT id , nome
FROM C l i e n t e WHERE i d=$FORM{ ’ id ’ } ” ) ;
$ sth−>e x e c u t e ( ) ;
( $ id , $nome ) = $ sth−>f e t c h r o w a r r a y ;
}
p r i n t <<PAGINA;
<html>
<form name=”form ” method=”p o s t ” a c t i o n =”C l i e n t e U p d a t e . p l ”>
<i n p u t type=”hidden ” name=”acao ” v a l u e=”$FORM{ ’ acao ’}” >
<i n p u t type=”hidden ” name=”i d ” v a l u e=”$FORM{ ’ id ’}” >
<t a b l e >
<t r >
<td>nome</td>
<td>
<i n p u t type=” t e x t ” name=”nome” v a l u e=”$nome”>
</td>
</t r >
<t r >
<td>&nbsp ;</ td>
<td>
<i n p u t type=”submit ” name=”Submit ” v a l u e=”submit”>
</td>
</t r >
</t a b l e >
</html>
O documento “Show.pl” de cada entidade cria um formulário com os campos vazios de
acordo com a ação escolhida pelo usuário com o objetivo de inserir uma nova entidade ou um
formulário com os campos preenchidos por um objeto da entidade através dos seus dados que
encontram-se armazenados em uma tabela do banco de dados. O comando SQL que se inicia na
linha 4 e termina na linha 8 cria um cursor no banco de dados e o armazena na variável sth. O
comando prepare, similar ao prepared statement da API JDBC [Ree00] da linguagem Java,
recebe o comando SQL como parâmetro e será processado na linha 7. Na linha 8, o valor do
cursor será atribuı́do às variáveis id e nome através do comando fetchrow array. Serão criados
80
TESTES E RESULTADOS
dois campos hidden no formulário HTML, um para armazenar o id do objeto, no caso de uma
atualização, e outro para armazenar a ação a ser executada (inserir ou atualizar), representados
nas linhas 13 e 14. Todos os atributos da classe exceto a chave-primária serão impressos em
linhas de uma tabela HTML, como mostra a linha 19.
O template utilizado para produzir os documentos “Show.pl” de cada classe está representado no Exemplo 5.4.
Exemplo 5.4 Arquivo Show.vm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
#i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” ) )
#xo2 . n e w f i l e : show $ { c l a s s e . name } . p l
#!/ u s r / b i n / p e r l
i f ($FORM{ ’ acao ’ } eq ’ i n s e r i r ’ ) {
} e l s i f ($FORM{ ’ acao ’ } eq ’ a t u a l i z a r ’ ) {
$ s t h = $ dbh−>p r e p a r e ( ”
SELECT $ u t i l . commaArray ( $ c l a s s e . g e t A t t r i b u t e s ( ) )
FROM $ c l a s s e . name WHERE i d=$FORM{ ’ id ’ } ” ) ;
$ sth−>e x e c u t e ( ) ;
( $ u t i l . commaArray ( $ c l a s s e . g e t A t t r i b u t e s ( ) , ” $ ” , ” ” , ” , ” , t r u e ) )
= $ sth−>f e t c h r o w a r r a y ;
}
p r i n t <<PAGINA;
<html>
<form name=”form ” method=”p o s t ” a c t i o n =”$ { c l a s s e . name} Update . p l ”>
<i n p u t type=”hidden ” name=”acao ” v a l u e=”$FORM{ ’ acao ’}” >
<i n p u t type=”hidden ” name=”i d ” v a l u e=”$FORM{ ’ id ’}” >
<t a b l e >
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . getAttributesWOStereoType ( ”PK” ) )
<t r >
<td> $ a t t r i b u t e . name</td>
<td>
<i n p u t type=” t e x t ”
name=” $ a t t r i b u t e . name”
v a l u e=” $$ { a t t r i b u t e . name}”>
</td>
</t r >
#end
<t r >
<td>&nbsp ;</ td>
<td>
<i n p u t type=”submit ” name=”Submit ” v a l u e=”submit”>
</td>
</t r >
</t a b l e >
5.1 GERANDO CÓDIGO PARA SITES DA WEB
43
44
45
46
47
48
81
</html>
PAGINA
#xo2 . e n d f i l e
#end
#end
O código entre as linhas 1 e 6 itera por todas as classes do modelo à procura daquelas que
possuem o estereótipo entity. As linhas 8 a 16 contêm o código que diferencia, em tempo de execução, o detalhamento, inserção ou atualização. Destaca-se a utilização do método commaArray
da classe Util. Na linha 11, foi utilizada a forma mais simples do método que retorna todos
os atributos da classe separados por vı́rgula. No entanto, na linha 14, utilizou-se uma forma
mais complexa do método. Ela servirá para produzir o código da linha 8 do Exemplo 5.3. Foi
necessário utilizar a forma mais complexa do método para adicionar o prefixo $ aos nomes do
atributos. O prefixo $ indica uma variável da linguagem Perl, que coincidentemente é o mesmo
sı́mbolo utilizado pela linguagem de template do Velocity para representação de variáveis. O
laço foreach da linha 26 seleciona apenas os atributos que não posuem o estereótipo PK, pois a
chave-primária não poderá ser alterada e, portanto, não precisa ser exibida. Na linha 32 existe
um $$ justamente para que um seja utilizado para receber o nome do atributo e o outro para
imprimir o $ que será utilizado para indicar uma variável no script Perl.
Até agora os scripts produzidos apenas exibiram dados de um objeto da classe ou um
formulário vazio. Com isso, faz-se necessária a criação de meios que permitam a alteração e
persistência dos dados na base de dados. O documento “Update.pl” é responsável por inserir,
atualizar ou remover um registro da entidade na base de dados. Ele, na verdade, é quem executa
a ação passada pelo documento “Show.pl” recebendo os parâmetros e executando queries SQL
de acordo com a ação indicada. No Exemplo 5.5 encontra-se o conteúdo de “UpdateCliente.pl”
que deverá ser produzido pelo template “Update.vm”.
Exemplo 5.5 Arquivo UpdateCliente.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/ u s r / b i n / p e r l
p r i n t ”<html >”;
i f ($FORM{ ’ acao ’ } eq ’ i n s e r i r ’ ) {
$ s t h=$ dbh−>p r e p a r e (
”INSERT INTO C l i e n t e ( nome ) VALUES ( ? ) ” ) ;
$ sth−>e x e c u t e ($FORM{ ’ nome ’ } ) ;
p r i n t ” C l i e n t e a d i c i o n a d o com s u c e s s o ” ;
} e l s i f ($FORM{ ’ acao ’ } eq ’ a t u a l i z a r ’ ) {
$ s t h = $ dbh−>p r e p a r e ( ”UPDATE C l i e n t e SET nome=? WHERE i d =?”);
$ sth−>e x e c u t e ($FORM{ ’ nome ’ } , $FORM{ ’ id ’ } ) ;
$ mensagem = ” C l i e n t e a l t e r a d o com s u c e s s o ” ;
} e l s i f ($FORM{ ’ acao ’ } eq ’ remover ’ ) {
$ s t h = $ dbh−>p r e p a r e ( ”DELETE FROM C l i e n t e WHERE i d =?”);
$ sth−>e x e c u t e ($FORM{ ’ id ’ } ) ;
p r i n t ” C l i e n t e removido com s u c e s s o ” ;
82
TESTES E RESULTADOS
20 }
21 p r i n t ”</html >”;
A maior parte do código de “UpdateCliente.pl” é formado por código SQL, já que as funções
executadas pelo script serão de atualização da base de dados. Nas linhas 4 , 10 e 15 encontramse as condições que devem ser satisfeitas pelo parâmetro acao e que podem assumir os seguintes
valores: inserir, atualizar e remover. Caso seja uma inserção, será executado um comando
SQL no seguinte formato:
insert into [T ABELA] ([COLU N AS]) values ([valores])
onde TABELA é o nome da tabela, COLUNAS são os nomes das colunas da tabela, separados
por vı́rgulas, e VALORES são os valores que deverão ser atribuı́dos aos registros. Nas linhas
5 e 6 prepara-se o comando SQL que será executado na linha 7 pelo comando execute. O
parâmetro $FORM{’nome’} passado para o método execute indica que a interrogação do SQL
será substituı́da pelo valor da variável nome. Caso tudo ocorra sem problemas será exibida uma
mensagem informando que o registro do cliente foi adicionado com sucesso.
Caso a ação seja uma atualização, um comando SQL com a seguinte sintaxe será executado:
update [T ABELA] set [CAM P O = V ALOR, ...] where [CON DICAO]
onde TABELA é o nome da tabela a ser atualizada, CAMPO=VALOR são os pares de campos e
valores a serem atualizados, separados por vı́rgulas, e CONDICAO é uma condição a ser satisfeita
pelo registro. Neste caso, a condição é que o campo id (chave-primária) tenha valor igual ao
id recebido como parâmetro. Caso tudo ocorra sem problemas será exibida uma mensagem
informando que o registro do cliente foi alterado com sucesso.
Caso a ação seja uma remoção, o script “UpdateCliente.pl” deverá executar um comando
SQL de remoção com a seguinte sintaxe:
delete f rom [T ABELA] where [CON DICAO]
onde TABELA é o nome da tabela da qual o registro será removido e CONDICAO é a condição que
selecionará os registros a serem removidos. No exemplo, serão sempre removidos os registros que
possuı́rem o id igual ao do cliente passado como parâmetro. Caso tudo ocorra sem problemas
uma mensagem informando que o registro do cliente foi removido com sucesso será exibida.
O Exemplo 5.6 representa o template criado para produzir os códigos-fonte de atualização
de um registro na base de dados.
Exemplo 5.6 Arquivo update.vm
1
2
3
4
5
6
7
8
9
#f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
#i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” ) )
#xo2 . n e w f i l e : $ { c l a s s e . name} Update . p l
#s e t ( $ a t r i b s = $ c l a s s e . getAttributesWOStereoType ( ”PK” ) )
#!/ u s r / b i n / p e r l
p r i n t ”<html >”;
5.1 GERANDO CÓDIGO PARA SITES DA WEB
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
83
i f ($FORM{ ’ acao ’ } eq ’ i n s e r i r ’ ) {
$ s t h=$ dbh−>p r e p a r e (
”INSERT INTO $ c l a s s e . name
( $ u t i l . commaArray ( $ a t r i b s ) )
VALUES (
$ u t i l . commaArray ( $ a t r i b s , ” ? ” , ” ” , ” , ” , f a l s e ) )
”);
$ sth−>e x e c u t e (
$ u t i l . commaArray ( $ a t r i b s , ”$FORM{ ’ ” , ” ’ } ” , ” , ” , t r u e )
);
p r i n t ” $ c l a s s e . name a d i c i o n a d o com s u c e s s o ” ;
} e l s i f ($FORM{ ’ acao ’ } eq ’ a t u a l i z a r ’ ) {
$ s t h = $ dbh−>p r e p a r e (
”UPDATE $ c l a s s e . name
SET $ u t i l . commaArray ( $ a t r i b s , ” ” , ” = ? ” , ” , ” , t r u e )
WHERE i d =?”);
$ sth−>e x e c u t e (
$ u t i l . commaArray ( $ a t r i b s , ”$FORM{ ’ ” , ” ’ } ” , ” , ” , t r u e ) ,
$FORM{ ’ id ’ } ) ;
p r i n t ” $ c l a s s e . name a l t e r a d o com s u c e s s o ” ;
} e l s i f ($FORM{ ’ acao ’ } eq ’ remover ’ ) {
$ s t h = $ dbh−>p r e p a r e ( ”DELETE FROM $ c l a s s e . name WHERE i d =?”);
$ sth−>e x e c u t e ($FORM{ ’ id ’ } ) ;
p r i n t ” $ c l a s s e . name removido com s u c e s s o ” ;
}
p r i n t ”</html >”;
#xo2 . e n d f i l e
#end
#end
Pelo documento “ClienteUpdate.pl” pode-se notar que várias vezes foi necessário um conjunto com todos os atributos da classe que não possuam o estereótipo PK. Para isso, como
mostra o código da linha 6, foi declarada uma variável para armazenar o conjunto de atributos
da classe que atendem ao critério. A variável atribs receberá a coleção dos atributos que não
possuem o estereótipo e será utilizada no resto do template. Entre as linhas 11 e 16 está o
código para produzir o comando SQL de inserção. Na linha 14, todos os atributos que não
são chave-primária serão resgatados com uma separação por vı́rgulas. Na linha 15, utilizou-se
a versão mais configurável do comando commaArray para retornar apenas o número de interrogações igual ao número de atributos da classe que não são chave-primária. O valor false no
último parâmetro do método informa que o nome do atributo não deverá ser impresso.
84
TESTES E RESULTADOS
Como o leitor já deve ter percebido, os parâmetros recebidos têm sempre a forma:
$F ORM {0 nome parametro0 }
onde nome parametro é o nome do atributo passado para o documento como parâmetro. Neste
caso, na hora de executar o comando SQL de inserção, precisou-se passar cada um dos parâmetros
recebidos, utilizando o método commaArray, com o acréscimo do prefixo ($FORM{’) e do sufixo
(’}) a cada elemento.
A Figura 5.3 ilustra a tela de visualização (“ClienteShow.pl”) que foi gerada automaticamente pelo ambiente XO2 através dos templates apresentados.
Figura 5.3 Tela de atualização produzida pelo XO2
Do lado esquerdo da figura tem-se um menu com opções para listar os registros de cada
entidade modelada. Do lado direito tem-se os campos de cada entidade que são utilizados para
adicionar ou atualizar as entidades na base de dados.
Os templates aqui apresentados foram capazes de produzir um website dinâmico com funcionalidades de consulta e atualização de sistemas modelados, sem que houvesse nenhuma interferência humana.
5.2
Gerando arquitetura em camadas para o projeto SIG@UFPE
Os resultados do estudo de caso anterior foram bastante animadores e provaram que a utilização
do ambiente gerador de código XO2 provê um método simples e com a capacidade de aumentar
a qualidade do código gerado, reduzir o número de bugs, manter a padronização de código e,
ainda, reduzir o tempo de desenvolvimento. No entanto, havia a necessidade de um exemplo
mais desafiador que utilizasse todos os recursos do ambiente.
O SIG@UFPE foi escolhido por possuir uma arquitetura complexa e um modelo de negócios
bem definido. Com isso, criou-se a necessidade de utilizar o módulo de mapeamento de modelos
do ambiente XO2 .
Em 2001, a UFPE, através do projeto SIG@UFPE, decidiu centralizar e tornar acessı́vel suas
informações à comunidade acadêmica. O sistema possui diversos módulos que vão do financeiro
até o módulo acadêmico. Atualmente a equipe de desenvolvimento do projeto é formada por 23
pessoas, entre desenvolvedores, analistas, arquitetos e analistas de suporte.
O sistema SIG@UFPE é subdivido em subsistemas e esses são subdivididos em módulos.
Tal divisão tem como objetivo agrupar as mais variadas funcionalidades fornecidas. A Figura
5.4 ilustra os subsistemas do sistema SIG@UFPE.
Estrutura Fı́sica, Acadêmico, Financeiro, Recursos Humanos e Controle de Acesso são os
subsistemas que constituem o SIG@UFPE.
O primeiro é responsável pelo cadastro organizacional da instituição. Sendo assim, controla
5.2 GERANDO ARQUITETURA EM CAMADAS PARA O PROJETO SIG@UFPE
85
Figura 5.4 Os subsistemas do sistema SIG@UFPE
o cadastro de campus, prédios, salas, órgãos e instituições.
O subsistema acadêmico oferece funcionalidades de oferta de disciplinas, matrı́cula em disciplinas, histórico escolar e avaliação de discentes.
Como o sistema SIG@UFPE faz parte dos serviços prestados a outras instituições, fez-se
necessário o desenvolvimento de um subsistema financeiro responsável pelo controle de pagamentos de taxas e mensalidades.
O subsistema de recursos humanos mantém o cadastro de discentes, docentes e perfis funcionais.
Finalmente, o acesso ao sistema e cadastro de usuários é responsabilidade do subsistema de
controle de acesso.
O SIG@UFPE é um sistema web desenvolvido em plataforma J2SE e que realiza a persistência dos dados em um banco de dados Oracle [Ora05a]. A Figura 5.5 ilustra a distribuição
do sistema.
Figura 5.5 A distribuição do sistema SIG@UFPE
O servidor web Apache [Apa05a] é responsável por receber as solicitações dos navegadores
web e distribuı́-las entre os diversos servidores de aplicação Tomcat [Jak05]. Faz-se necessário
a utilização de diversos servidores Tomcat para distribuição de carga.
86
TESTES E RESULTADOS
O sistema ainda se comunica com dois outros sistemas da instituição. O sistema da biblioteca central fornece informações sobre o estado dos empréstimos dos alunos. Já o sistema
SIPROC - Sistema de Acompanhamento de Processos, fornece informações sobre o andamento
dos processos institucionais.
O sistema SIG@UFPE utiliza o padrão MVC [GHJV95] o qual prega a separação de regras
de negócio, apresentação e controlador.
A camada de apresentação do SIG@UFPE utiliza JSP e Servlets. Já o sistema propriamente
dito utiliza uma arquitetura em camadas como sugere a Figura 5.6. O sistema atualmente possui
mais de 300 tabelas e cerca de 250 classes de negócio distribuı́das em cinco módulos. Com
tamanho porte, erros de código, que em sistemas menores poderiam ser facilmente contornados,
tomam grandes proporções, pois são replicados em dezenas de classes. A padronização do código
é um grande desafio, pois o código-fonte escrito há quase 4 anos e por diferentes desenvolvedores
não encontra-se padronizado. Além disso, muitos erros cometidos em código foram replicados
por desenvolvedores desavisados. Ainda faz parte da lista de problemas manter a consistência
entre modelo e código, cada vez mais agravada pelas inúmeras transformações sofridas pelo
código.
É importante perceber que a grande maioria das tabelas do sistema já estava criada e, durante o estudo de caso, desejou-se conservar a estrutura existente. O ambiente XO2 facilitou
a permanência da estrutura de dados através da utilização de mapeamentos entre o diagrama
de classes UML e as tabelas já modeladas. Isso o torna diferente de outros ambientes geradores de código, que muitas vezes engessam as modelagens forçando os analistas e arquitetos a
implementar padrões de modelagem diferentes dos desejados.
A fachada é uma implementação do design pattern Façade [GHJV95]. O padrão determina
que o sistema deve possuir apenas um ponto de entrada e saı́da. Desta forma, o sistema é
enxergado como uma estrutura única tornando o acesso seguro e organizando. A fachada acessa
diretamente os controladores de cada subsistema. Um controlador de módulo é responsável por
acessar os cadastros de cada entidade de negócios. A camada que realiza a persistência dos
dados é acessada pelo seu cadastro.
Percebe-se que cada nı́vel da arquitetura só enxerga entidades que encontram-se no mesmo
nı́vel ou no nı́vel abaixo mais próximo. Isto torna a arquitetura mais segura e reduz bastante
o número de bugs. Como pode-se perceber, as entidades de negócio não fazem parte especificamente de uma camada, elas permeiam a arquitetura e podem ser utilizadas por qualquer
camada. Cada entidade de negócio dá origem a pelo menos um segmento da arquitetura, sendo
este constituı́do por repositório, cadastro e controlador. A arquitetura permite que várias implementações na camada de negócios coexistam, facilitando assim que um mesmo sistema possa
fazer sua persistência em diferentes tipos de estruturas de armazenamento como bancos de
dados, documentos XML, etc.
Em 2004, a Universidade passou a oferecer o sistema SIG@UFPE como um serviço para
outras instituições e, então, surgiu a necessidade de substituição da camada de persistência
de dados. Os antigos repositórios JDBC deveriam ser substituı́dos por repositórios Hibernate
[Hib05], desta forma, toda a camada de persistência dos dados seria realizada de forma transparente para os desenvolvedores. Além da abstração de persistência dos dados, a utilização do
Hibernate permitiu tornar o sistema independente de plataforma.
Depois da análise no sistema, detectou-se a necessidade da criação de 250 arquivos de mapeamento do Hibernate, cada qual para representar a persistência de uma classe de negócio em
5.2 GERANDO ARQUITETURA EM CAMADAS PARA O PROJETO SIG@UFPE
87
Figura 5.6 Arquitetura em camadas do SIG@UFPE
tabela do banco de dados. Além disso, seria necessário a reescrita do código dos repositórios
das classes de dados para contemplar a utilização do Hibernate, o que levaria a alteração de
mais 250 classes. Até então teria-se, a alteração de 500 classes do sistema. Um dado bastante
desanimador, contando-se o número reduzido de integrantes da equipe (dos quais a maioria não
poderia dedicar-se fulltime à atividade de conversão para o Hibernate).
O ambiente XO2 teve a capacidade de interpretar de forma simples as tabelas já existentes.
O estudo de caso aqui apresentado ilustra os templates XO2 escritos para gerar os arquivos
de configuração do Hibernate e classes de negócio (persistentes) do sistema. A criação dos
repositórios, apesar de ter sido realizada pelo ambiente XO2 , não foi ilustrada.
Para o estudo de caso foi escolhido o subsistema de Estrutura Fı́sica, responsável pelo
controle da estrutura fı́sica da universidade (órgãos, prédios, salas, campus, etc.). A Figura 5.7
apresenta o Modelo OO que será utilizado como artefato de entrada para geração de código.
Por simplificação, foi considerada apenas uma pequena parte do modelo original.
Uma das práticas desta etapa de criação do modelo OO é a utilização de estereótipos para
adicionar semântica aos elementos do diagrama de classes. O estereótipo entity é utilizado para
identificar as classes de negócio. O estereótipo persistent identifica as classes cujos objetos
necessitam ser persistidos. O estereótipo PK é utilizado para identificar o(s) atributo(s) chave
da classe de negócio.
A figura mostra que a classe Prédio possui os atributos: codigoPredio, nomePredio,
identificacaoPredio, corPredio, timestamp (herdado da classe ObjetoSiga) e um objeto
88
TESTES E RESULTADOS
Figura 5.7 Representação UML da classe Prédio
campus (derivado da associação com a classe Campus). O código-fonte gerado pelo ambiente
deve ser parecido com o código do Exemplo 5.7.
Exemplo 5.7 Predio.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package s i g a . e s t r u t u r a F i s i c a . p r e d i o ;
import s i g a . e s t r u t u r a F i s i c a . campus . Campus ;
import s i g a . u t i l . O b j e t o S i g a ;
public c l a s s Predio extends ObjetoSiga {
private int codigoPredio ;
p r i v a t e S t r i n g nomePredio ;
private String identificacaoPredio ;
private String corPredio ;
p r i v a t e Campus campus ;
public Predio ( i n t codigoPredio ,
S t r i n g nomePredio ,
String identificacaoPredio ,
String corPredio ,
Campus campus ) {
setCodigoPredio ( codigoPredio ) ;
setNomePredio ( nomePredio ) ;
setIdentificacaoPredio ( identificacaoPredio );
setCorPredio ( corPredio ) ;
setCampus ( campus ) ;
}
public f i n a l void setCodigoPredio ( i n t codigoPredio ) {
th i s . codigoPredio = codigoPredio ;
}
public f i n a l i n t getCodigoPredio () {
return codigoPredio ;
5.2 GERANDO ARQUITETURA EM CAMADAS PARA O PROJETO SIG@UFPE
31
32
33
34
35
36
37
38
39
40
41
42
43
44 }
89
}
...
p u b l i c b o o l e a n e q u a l s ( Object o ) {
i f ( o i n s t a n c e o f Predio ) {
i f ( c o d i g o P r e d i o == ( ( P r e d i o ) o ) . g e t C o d i g o P r e d i o ( ) ) {
return true ;
} else {
return f a l s e ;
}
} else {
return f a l s e ;
}
}
Pelo código apresentado pode-se reconhecer os seguintes padrões:
P1 Cada classe de negócio produzirá um arquivo com extensão java e deverá ficar armazenado
numa estrutura de diretórios que reproduza o seu pacote. Desta forma, a classe Predio
será armazenada em: siga/estruturaFisica/predio/Predio.java.
P2 No inı́cio do documento da classe, deverá ser criado o comando para identificar a que
pacote pertence a classe.
P3 Todos os comandos import devem ser gerados automaticamente e ainda precisa ser criado um escopo protegido para que outras cláusulas import possam ser adicionadas pelos
desenvolvedores.
P4 A declaração da classe, com seu modificador de visibilidade (public, private, etc). Caso
a classe seja uma implementação de alguma interface, a cláusula implements deverá ser
criada. Além disso, se ela for herança de uma classe deverá possuir a cláusula extends.
P5 A declaração de todos os atributos da classe. Também serão criados os atributos frutos
de herança e de associações com outras classes.
P6 A criação do construtor da classe. No SIG@UFPE, para a maioria dos casos, é utilizado
um construtor com todos os atributos da classe. Portanto, apenas este será criado automaticamente. Deverá ser criado um escopo protegido para construtores no caso do
desenvolvedor necessitar criar um ou mais construtores.
P7 Para cada método da classe será criado um método no escopo. Mais adiante serão dados
mais detalhes sobre como esta atividade pode ser facilitada pelo método getSignature da
classe XO2Method. Um escopo protegido para os métodos criados pelo desenvolvedor
deverá ser criado.
P8 Para cada atributo da classe deverão ser criados os métodos de acesso, ou seja, um método
get e um método set. Esses métodos estão de acordo com a técnica de encapsulamento,
tornando os atributos da classe protegidos.
90
TESTES E RESULTADOS
P9 Será fornecido também um método equals. Esse método será utilizado para comparar
objetos e deverá ser implementado pelo desenvolvedor, pois objetos diferem na forma de
comparação.
A linha de código a seguir ilustra a criação do arquivo que conterá o código-fonte de classe.
#n e w f i l e : $ c l a s s e . getPathOS ( ) / $ ! { c l a s s e . name } . j a v a
O método getPathOS retornará o caminho completo para a classe de acordo com o sistema
de arquivos do sistema operacional. Dessa forma, todos os arquivos referentes às classes básicas
serão armazenados em seus respectivos diretórios.
Na linha de código abaixo está representado o código para a criação da indicação do pacote.
package $ c l a s s e . getPath ( ) ;
Diferente do getPathOS o método getPath retorna o caminho da classe na sintaxe Java, ou
seja, os pacotes separados por “.”.
Para a criação das diretivas e importação pode-se utilizar o código abaixo.
#f o r e a c h ( $ imp i n $ u t i l . g e t I m p o r t s ( $ modelo , $ c l a s s e ) )
import $ imp ;
#end
O laço foreach faz a iteração pelo conjunto de import retornado pelo método getImports
da classe Util. O método é mais uma das facilidades fornecidas pelo ambiente XO2 e define as
classes e pacotes a serem importados baseando-se nos atributos cujo tipo seja uma outra classe
e também através de herança classes e implementação de interfaces.
A declaração da classe é realizada pelo código a seguir.
$ { c l a s s e . v i s i b i l i t y } f i n a l c l a s s $ { c l a s s e . name}
extends ObjetoSiga
$ u t i l . implementz ( ) {
Primeiro determina-se a visibilidade da classe. As classes de negócio SIG@UFPE são sempre
declaradas como final, para não permitir herança. Pode-se perceber que as classes sempre são
herança da classe ObjetoSiga que é uma classe base e que reúne as propriedades que precisam
ser refletidas em todas as classes de negócio. Poderia ser utilizado o método extendz da classe
Util, porém isso não foi necessário devido a rigidez com que é seguida a regra de herança no
SIG@UFPE. Para a cláusula implements foi utilizado o método implementz para indicar todas
as interfaces implementadas pela classe.
Em seguida, deve-se declarar todos os atributos da classe. Para o SIG@UFPE será considerado atributo da classe todo atributo da própria classe e atributos oriundos de associações
com outras classes, baseando-se no sentido da navegação da relação. O código para criação dos
atributos encontra-se a seguir.
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . g e t A t t r i b u t e s C u s t o m ( ” oa ” , ” ” ) )
$ a t t r i b u t e . v i s i b i l i t y $ a t t r i b u t e . dataType $ a t t r i b u t e . name ;
#end
O método getAttributesCustom recebe dois parâmetros. O primeiro é uma String que
pode ser formada por “o” - atributos da própria classe, “i” - atributos oriundos de herança e
5.2 GERANDO ARQUITETURA EM CAMADAS PARA O PROJETO SIG@UFPE
91
“a” - atributos oriundos de associações. O segundo indica o tipo das coleções, caso necessário.
De acordo com os parâmetros será retornada uma coleção com os atributos da classe.
O construtor da classe deve receber todos os parâmetros e fazer a atribuição de cada um
deles. Optou-se por atribuir diretamente os valores, mas poderia ser criada uma variante para
que o método set de cada atributo fosse utilizado. O código encontra-se abaixo.
1
2
3
4
5
6
7
p u b l i c $ { c l a s s e . name} (
$ u t i l . commaArray (
$ u t i l . getAttributeNameType ( $ c l a s s e . g e t A t t r i b u t e s C u s t o m ( ” oa ” , ” ” ) ) ) {
#f o r e a c h ( $ a t t r i b u t e i n $ c l a s s e . g e t A t t r i b u t e s ( ) )
t h i s . $ a t t r i b u t e . name = $ a t t r i b u t e . name ;
#end
}
Na linha 1, inicia-se a criação da assinatura do método construtor da classe com a declaração
public seguida do nome da classe. Na linha 2, será dada continuidade na assinatura do método
colocando os atributos e tipos separados por vı́rgula. O Método getAttributeNameType recebe
como parâmetro de entrada uma coleção com os atributos da classe e retorna pares com os
nomes e tipos dos atributos separados por espaço e, em seguida, eles serão listados com uma
vı́rgula separadora pelo método commaArray. Por fim, o laço foreach fará a atribuição dos
valores.
A criação das assinaturas dos métodos é facilitada pelo método getSignature. É preciso
apenas iterar pela coleção de métodos da classe e criar os métodos. Também é apresentada a
criação do escopo protegido do método, que será útil para que o código escrito pelo desenvolvedor
seja preservado em futuras gerações de código. O código para criação dos métodos encontra-se
abaixo.
1
2
3
4
5
6
#f o r e a c h ( $ metodo i n $ c l a s s e . getMethods ( ) )
$ method . g e t S i g n a t u r e ( ) {
/ ** #xo2 . b e g i n : $ metodo . g e t S i g n a t u r e ( ) * /
/ ** #xo2 . end : $ metodo . g e t S i g n a t u r e ( ) * /
}
#end
Os métodos de acesso ficam no final do documento pois geralmente não sofrem alterações.
Como ilustra o código abaixo, para cada atributo será criado um método get que retorna o
valor do atributo e um método set que recebe um parâmetro com o valor a ser atribuı́do e não
possui retorno.
Para seguir a nomenclatura padrão será preciso que o nome dos atributos, originalmente
começando com caracter em caixa baixa, tenha o seu primeiro caractere alterado para caixa
alta, para isso houve a utilização do método getFirstToUC.
1
2
3
4
5
6
7
8
#f o r e a c h ( $ a t r i b u t o i n $ c l a s s e . g e t A t t r i b u t e s C u s t o m ( ” o i a ” , ” ” ) )
p u b l i c $ a t r i b u t o . dataType g e t $ u t i l . getFirstToUC ( $ a t r i b u t o . name ) ( )
{
r e t u r n t h i s . $ a t r i b u t o . name ;
}
p u b l i c v o i d s e t $ u t i l . getFirstToUC ( $ a t r i b u t o . name )
( $ a t r i b u t o . dataType $ a t r i b u t o . name ) {
92
TESTES E RESULTADOS
9
t h i s . $ a t r i b u t o . name = $ a t r i b u t o . name ;
10 }
11 #end
Por fim, é necessário criar um método equals que será utilizado para comparação de objetos.
O código abaixo mostra a construção do método equals da classe de negócio.
1
2
3
4
5
6
7
8
9
10
11
12
p u b l i c f i n a l b o o l e a n e q u a l s ( Object o ) {
boolean retorno = f a l s e ;
i f ( o i n s t a n c e o f $ { c l a s s e . name } ) {
/ ** #xo2 . b e g i n : e q u a l s ( ) * /
/ ** #xo2 . end : e q u a l s ( ) * /
} else {
retorno = f a l s e ;
}
return retorno ;
}
Como percebe-se, a base do método foi criada. No entanto, o código que compara os objetos
não foi completado, deixando o desenvolvedor livre para utilizar a forma desejada de verificação
de igualdade dos objetos.
A partir de agora será detalhada a criação do template que produzirá o arquivo de configuração do Hibernate. Deveria-se ter criado o documento M3 L mapeando todas as classes
persistentes em tabelas do banco.
O arquivo do Hibernate para a classe Predio é semelhante ao do Exemplo 5.8
Exemplo 5.8 Predio.hbm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml v e r s i o n =”1.0” e n c o d i n g =’ u t f −8’?>
<!DOCTYPE h i b e r n a t e −mapping PUBLIC
”−// H i b e r n a t e / H i b e r n a t e Mapping DTD 3 . 0 / /EN”
” h t t p : / / h i b e r n a t e . s o u r c e f o r g e . n e t / h i b e r n a t e −mapping − 3 . 0 . dtd”>
<h i b e r n a t e −mapping package=” s i g a . e s t r u t u r a F i s i c a . p r e d i o ”>
< c l a s s name=”P r e d i o ” t a b l e =”SIGA PREDIO” >
<i d name=”c o d i g o P r e d i o ” column=”CD PRED” >
<g e n e r a t o r c l a s s =”s e q u e n c e”>
<param name=”s e q u e n c e”>SQ CD PRED</param>
</g e n e r a t o r >
</id>
<p r o p e r t y name=”nomePredio ” column=”NM PRED” />
<p r o p e r t y name=” i d e n t i f i c a c a o P r e d i o ” column=”NU IDENT” />
<p r o p e r t y name=”c o r P r e d i o ” column=”NM COR PRED” />
<timestamp name=”timestamp ” column=”TS PRED” />
<many−to−one name=”campus” column=”CD CAMPUS”
c l a s s =” s i g a . e s t r u t u r a F i s i c a . campus . Campus” />
</ c l a s s >
</h i b e r n a t e −mapping>
5.2 GERANDO ARQUITETURA EM CAMADAS PARA O PROJETO SIG@UFPE
93
No código-fonte do Hibernate apresentado é possı́vel reconhecer os seguintes padrões:
P1 Para cada classe com os estereótipos entity e “persistent” deverá ser criado um arquivo
<nome-da-classe>.hbm.xml que deverá ser armazenado numa hierarquia de diretórios
semelhante aos pacotes da classe.
P2 O nome da classe e o nome da tabela correspondente serão utilizados para criar a estrutura
class no documento Hibernate para representar uma classe persistente.
P3 O objeto da classe deverá possuir um identificador. No estudo de caso, os atributos identificadores estão marcados com o estereótipo PK (chave primária). Este atributo também
indica que a coluna correspondente na tabela será a chave-primária da tabela.
P4 Caso a chave-primária seja uma sequence do banco de dados, ou seja, tenha um valor
seqüencial e auto-incrementável, deverá ser criado no arquivo de configuração do Hibernate
um generator e referenciado o nome da sequence que segue o padrão SQ <coluna-da-tabela>.
P5 Para cada atributo da classe deverá ser criado um elemento property contendo o nome
do atributo na classe e o nome do campo correspondente na tabela.
P6 Os atributos da classe oriundos de associações deverão dar origem a um elemento do tipo
many-to-one, indicando o relacionamento entre as classes.
Depois de identificados os padrões de código, será necessário escrevê-los como regras de
transformação nos templates. Cada padrão de código dá origem a uma regra de transformação.
O objetivo será produzir, sem a interferência humana, código Hibernate semelhante ao apresentado no Exemplo 5.8 para todas as entidades do sistema. Com isto, a utilização do Hibernate
na camada de persistência estará quase pronta, restando apenas alterar os repositórios para
acessar os dados através do Hibernate.
Primeiramente, deve-se criar um laço que itere por todas as classes do modelo de projeto.
Tais classes deverão ser filtradas de acordo com o seu estereótipo, assim, apenas as classes
com estereótipo entity e persistent interessarão ao processo de geração de código para o
Hibernate. O Exemplo 5.9 apresenta o trecho do template responsável pela criação do arquivo
.hbm.xml com o nome da classe e pela criação do filtro.
Exemplo 5.9 Trecho de código do template para criação do arquivo hbm
1 #f o r e a c h ( $ c l a s s e i n $ modelo . g e t A l l C l a s s e s ( ) )
2 #i f ( $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” e n t i t y ” )
3
&& $ c l a s s e . c o n t a i n s S t e r e o t y p e ( ” p e r s i s t e n t ” ) )
4 #xo2 . n e w f i l e : $ c l a s s e . getPathOS ( ) / $ ! { c l a s s e . name } . hbm . xml
Na linha 1, o método foreach indica a iteração de todas as classes do modelo. Em seguida,
nas linha 2 e 3, cria-se o filtro para os estereótipos entity e persistent. Por fim, na linha 4,
tem-se a criação do arquivo contendo o caminho completo da classe e adicionando a extensão
.hbm.xml.
O Exemplo 5.10 ilustra a criação do padrão P2 com o cabeçalho, a base do elemento class
e o mapeamento para a tabela.
94
TESTES E RESULTADOS
Exemplo 5.10 Trecho de código do template para criação da classe
1 <?xml v e r s i o n =”1.0” e n c o d i n g =’ u t f −8’?>
2 <!DOCTYPE h i b e r n a t e −mapping PUBLIC
3
”−// H i b e r n a t e / H i b e r n a t e Mapping DTD 3 . 0 / /EN”
4
” h t t p : / / h i b e r n a t e . s o u r c e f o r g e . n e t / h i b e r n a t e −mapping − 3 . 0 . dtd”>
5
6 <h i b e r n a t e −mapping package=” $ c l a s s e . getPath ()” >
7
8
< c l a s s name=” $ c l a s s e . name”
9
t a b l e =”$ maps . getMapProperty ( $ c l a s s e , ” e r ” , ”name”)”>
O código entre as linhas 1 e 4 diz respeito à criação do cabeçalho do documento XML.
Na linha 6, cria-se realmente o documento Hibernate indicando o pacote através do método
getPath do objeto classe. O método retorna o caminho completo do pacote no qual a classe
está armazenada. As linhas 8 e 9 dizem respeito à criação da classe persistente.
O atributo name terá como valor o próprio nome da classe. O valor do atributo table
será preenchido com o componente correspondente à classe do modelo OO no modelo ER.
Neste caso, será armazenado o nome da tabela, utilizando-se o método getMapProperty. O
método realiza um busca por mapeamentos de modelos. Ele recebe três parâmetros: object,
um objeto do modelo OO, que pode ser uma classe ou atributo; model, o nome do modelo
referenciado; property, a propriedade correspondente do modelo referenciado. Explicando
melhor: é informado que o elemento desejado é correspondente à classe do modelo OO no
modelo ER, e que deverá ser retornado o nome do elemento, neste caso, o nome da tabela.
Percebe-se a utilização direta do documento M3 L.
O código do Exemplo 5.11 indica a iteração por todos os atributos da classe e o tratamento
necessário. Os atributos que possuem o estereótipo PK deverão ser selecionados a cada passagem.
A chave-primária receberá um tratamento especial e os atributos serão relacionados com as
colunas correspondentes da tabela.
Exemplo 5.11 Trecho de código do template para criação da chave-primária
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#f o r e a c h ( $ a t r i b u t o i n $ c l a s s e . g e t A t t r i b u t e s C u s t o m ( ” o i a ” , ” ” ) )
#i f ( $ a t r i b u t o . c o n t a i n s S t e r e o t y p e ( ”PK” ) )
#s e t ( $ c h a v e P r i m a r i a = $ a t r i b u t o )
<i d name=” $ a t r i b u t o . name”
column=”$ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ”name ” ) ” >
#i f ( $ a t r i b u t o . getDataType ( ) . e q u a l s ( ” i n t ” ) )
<g e n e r a t o r c l a s s =”s e q u e n c e”>
<param name=”s e q u e n c e”>
SQ $ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ”name ” )
</param>
</g e n e r a t o r >
#e l s e
<g e n e r a t o r c l a s s =” a s s i g n e d ” />
#end
</id>
Na linha 1, através do laço foreach, todos os atributos da classe serão iterados. O método
getAttributesCustom do ambiente XO2 possibilita a escolha da ordem em que os atributos
5.3 RESULTADOS
95
serão retornados. Isso é necessário, pois o ambiente retorna atributos da própria classe (“o”),
atributos oriundos de heranças (“i”) e atributos oriundos de associações (”a”). Dos atributos
iterados deverá ser selecionado o que contiver o estereótipo PK, linha 2, e então o seu nome será
armazenado na variável chavePrimaria para ser utilizado posteriormente, linha 3.
A representação da chave-primária para o Hibernate é indicada pelo elemento id, criado
na linha 4. O atributo name do elemento id terá valor preenchido pelo nome do atributo na
classe de negócio. Ao atributo column deverá ser atribuı́do o nome da coluna correspondente
à chave-primária. Caso a chave seja um atributo do tipo int, o Hibernate deverá criar uma
sequence com a seguinte nomenclatura: SQ <coluna-da-tabela>. A criação da sequence é
ilustrada entre as linhas 7 e 11.
O Hibernate faz uma distinção entre os atributos com tipos básicos (int, string, boolean)
e os atributos que são objetos de outras classes. O Exemplo 5.12 ilustra a criação dos atributos
da classe.
Exemplo 5.12 Trecho de código do template para criação dos atributos da classe
1
2
3
4
5
6
7
8
9
10
11
12
#e l s e
#i f ( $ a t r i b u t o . getDataType ( ) . getAsElement ( ) .
containsStereotype (” p e r s i s t e n t ”))
<many−to−one name=” a t r i b u t o . name”
column=”$ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ”name ” ) ”
c l a s s =” a t r i b u t o . getDataType ( ) . getAsElement ( ) . getFullName ()”/ >
#e l s e
<p r o p e r t y name=” $ a t r i b u t o . name”
column=”$ maps . getMapProperty ( $ a t r i b u t o , ” e r ” , ”name ” ) ” />
#end
#end
...
O else da linha 1 seleciona os atributos que não foram filtrados no if da chave-primária.
Como há distinção no tratamento dos tipos de atributos entre os simples e os que são formados
por objetos de outras classes, esta distinção é realizada nas linha 2 e 3. Verifica-se se o tipo
de dados do atributo é uma classe e se contém o estereótipo persistent. Assim será criado
um elemento many-to-one. Este elemento representa uma associação n-para-um, representado
no Hibernate pelo nome do atributo, a coluna correspondente (chave-estrangeira) e a classe
correspondente ao tipo. O código correspondente encontra-se entre as linhas 4 e 6.
Por fim, os atributos de tipo simples serão adicionados como indica o código das linhas 8 e
9. Cria-se uma propriedade Hibernate com o nome do atributo e a coluna correspondente na
tabela.
5.3
Resultados
No processo de implementação do estudo de caso de utilização do ambiente XO2 no sistema
SIG@UFPE, foram envolvidos: um analista e três desenvolvedores. O analista foi responsável
pela definição da camada de persistência através do Hibernate, por assegurar que os objetivos
e requisitos do sistema fossem mantidos, para medir o esforço de desenvolvimento com e sem
o ambiente XO2 e por garantir que os objetivos da utilização do sistema seriam atingidos. Os
desenvolvedores participaram da construção dos templates e do esforço de escrita de código para
96
TESTES E RESULTADOS
realizar o comparativo.
As métricas são impressionantes, em média um desenvolvedor gasta:
ˆ 4 horas para produzir uma classe básica com testes unitários.
ˆ 8 horas para produzir um repositório de classe básica com testes unitários.
ˆ 4 horas para produzir o arquivo de configuração Hibernate para uma classe persistente.
Calculando o total de horas gastas para re-implementar as 250 classes básicas do sistema,
seus repositórios e seus arquivos Hibernate, seriam necessárias 4000 horas ou 100 semanas de
desenvolvimento de um desenvolvedor.
Através de experimentos, chegou-se à conclusão de que o ambiente XO2 seria capaz de gerar
automaticamente:
ˆ 100% do código das classes básicas e seus testes unitários.
ˆ 50% do código dos repositórios e seus testes unitários.
ˆ 90% do código dos arquivos de configuração Hibernate.
A Tabela apresenta as estimativas de horas de desenvolvimento necessárias para a substituição da camada de persistência de dados do sistema SIG@UFPE.
Classes Básicas
Repositório
Configuração Hibernate
Total (x250)
Convencional (h)
4
8
4
4000
Com XO2 (h)
0
4
0,1
1025
Economia
4 (100%)
4 (50%)
3,9 (90%)
2975 (74%)
Tabela 5.1 Tempo de desenvolvimento (em horas) com e sem ambiente XO2
Acredita-se que esse ganho de produtividade de 74% poderia ainda ser aumentado com o
aperfeiçoamento dos templates. Porém, este número já expressa que o projeto de conversão da
camada de persistência que provavelmente alocaria uma equipe de 4 pessoas durante 25 semanas
(trabalhando 8 horas por dia e 5 dias por semana) levaria apenas 6,5 semanas se houvesse o
auxı́lio do ambiente XO2 . Um número bastante estimulante.
Outro ponto importante é que a manutenção do código gerado, agora padronizado, será
facilitada devido ao cumprimento das regras de codificação e padronização. Poderia, ainda,
ter-se adicionado comentários Javadoc que tornariam o código mais legı́vel, esta etapa pode ser
realizada em futuras gerações de código.
É importante ressaltar que os maiores benefı́cios obtidos com a utilização do ambiente XO2
não foram apenas de produtividade. O código tornou-se mais robusto, já que bugs encontrados
no código legado foram corrigidos e replicados através dos templates.
Por fim, foi consenso entre os membros da equipe que o código produzido tem maior nı́vel
de abstração, qualidade e consistência.
5.4 CONCLUSÕES
5.4
97
Conclusões
Este capı́tulo teve como objetivo apresentar os testes e resultados da aplicabilidade do ambiente
XO2 no processo de desenvolvimento de um sistema de informação.
Como estudo de caso foram utilizados dois cenários reais de geração de código. No primeiro,
teve-se o objetivo de produzir código Perl para a criação de websites dinâmicos. No segundo,
o ambiente XO2 foi utilizado para realizar o processo de conversão da camada de persistência
do o SIG@UFPE - Sistema de Informação e Gestão Acadêmica da Universidade Federal de
Pernambuco.
Os resultados obtidos provaram que o mapeamento de diversos modelos pode ser utilizado
como uma forma de fornecer subsı́dios para a criação de templates mais robustos.
O código produzido pelo ambiente encontra-se em produção na universidade e tem um maior
nı́vel de qualidade, padronização e consistência. Isso comprova-se pelo fato de que toda a base
de código de persistência foi produzida pelo mesmo conjunto de templates.
Houve também um considerável acréscimo na produtividade da equipe, pois esta deixou de
realizar uma série de tarefas repetitivas e pode concentrar-se na criação e aperfeiçoamento das
regras de negócio. Este fato também contribuiu para um sensı́vel crescimento da satisfação e
motivação dos membros da equipe.
Por seguir a arquitetura MDA, a utilização do ambiente XO2 provê um notável aumento no
nı́vel de abstração. Esse fato ocorre pela separação bem definida de papéis e responsabilidades
proposta pela arquitetura MDA.
Finalmente, os resultados mostraram ainda que um ambiente gerador de código pode abreviar o tempo de desenvolvimento, porém esta não é a sua maior vantagem. Código estável, bem
estruturado, padronizado, integração entre as fases de Análise e Projeto e Implementação são
os maiores benefı́cios da introdução do XO2 , um ambiente gerador de código MDA baseado no
mapeamento de modelos, no processo de desenvolvimento de um sistema de informação.
CAPÍTULO 6
CONCLUSÕES
Atualmente, devido a exigências do mercado, o grande desafio de um processo de desenvolvimento de software é a construção rápida de sistemas com qualidade. Neste contexto, esta
dissertação de mestrado apresentou um ambiente, denominado XO2 , para a geração ativa de
código-fonte através do mapeamento de modelos. O ambiente se propõe a automatizar e acelerar
parte da etapa de implementação de um processo de desenvolvimento de software, a partir de
modelos (artefatos) produzidos em etapas anteriores do processo, gerando código-fonte menos
suscetı́vel a erros, padronizado e mais passı́vel de manutenções.
O objetivo principal foi permitir a utilização dos modelos OO e ER (e um mapeamento entre
eles) como entrada do ambiente gerador de código, já que os ambientes existentes permitem
apenas a utilização de um tipo de modelo.
O ambiente XO2 é baseado no arquitetura MDA (Model Driven Architecture) e tem como
objetivo produzir grande parte do código-fonte de um sistema de software orientado a objetos, através de transformações de modelos, independentemente de arquitetura, plataforma e
linguagem de programação utilizados.
A utilização do ambiente XO2 é recomendada desde programadores que desejam produzir
rapidamente pequenos websites dinâmicos até fábricas de software que produzem sistemas de
informação de pequeno, médio e grande porte e que tem como objetivo produzir sistemas com
alto padrão de qualidade e no menor tempo de desenvolvimento possı́vel.
O estudo de caso realizado com o sistema SIG@UFPE validou a proposta e demonstrou a
eficácia do ambiente gerador de código em um sistema e informação de grande porte.
O estudo de caso provou ainda que o código produzido pelo ambiente e implantado na
produção do SIG@UFPE mostrou-se com maior nı́vel de qualidade, padronização e consistência.
Além de aumentar o nı́vel de abstração através da separação bem definida de papéis e responsabilidades proposta pela arquitetura MDA.
Os resultados extraı́dos do estudo de caso de substituição da camada de persistência do
SIG@UFPE mostraram um ganho de 74% de produtividade na implementação e realização de
testes.
O grande diferencial do XO2 em relação aos ambientes geradores existentes é a sua capacidade de produzir código através do mapeamento de diversos modelos. A Tabela 6.1 a seguir
apresenta um comparativo entre o ambiente XO2 e os outros ambientes avaliados por este trabalho.
Percebe-se que os maiores benefı́cios obtidos com a utilização do ambiente XO2 não estão
ligados diretamente ao ganho produtividade. Aumentou-se a qualidade e consistência do código,
visto que esse tornou-se mais robusto e com menor número de bugs. Correções de erros encontrados poderiam ser aplicadas aos templates e replicadas por todo a base de código gerada pelo
ambiente.
Finalmente, o ambiente XO2 mostrou-se apto a ser incorporado ao processo de desenvolvimento de sistemas de informação aumentando o grau de abstração e facilitando a integração
99
100
CONCLUSÕES
Open-source
Extensibilidade
Usabilidade
GUI
Input
Output
Modelos
Abstração
MDA
XDoclet
sim
alta
alta
não
Java
vários
não
baixa
não
AndroMDA
sim
alta
alta
não
xmi
vários
UML e ER
alta
sim
iQgen
não
alta
alta
sim
xmi
vários
UML
alta
sim
e-Gen
não
alta
alta
sim
xml
vários
UML
alta
sim
Coder
não
baixa
baixa
sim
Java
java
não
baixa
não
XO2
sim
alta
alta
sim
vários
vários
vários
alta
sim
Tabela 6.1 Comparativo entre o XO2 e outros ambientes
entre as fases de Análise e Projeto.
Nas seções seguintes serão apresentadas as contribuições deste trabalho bem como indicações
de trabalhos futuros.
6.1
Contribuições
Apesar do grande número de ambientes e teorias existentes sobre ambientes geradores de código,
ainda existem vários pontos que precisam ser melhor explorados. Adiante, serão detalhadas as
principais contribuições deste trabalho.
Um estudo sobre o estado da arte no campo da geração de código foi realizado. As principais
técnicas e teorias foram estudadas de forma a criar uma base sólida de conhecimento para
encontrar as melhores soluções.
Foi realizada uma pesquisa, além do estudo comparativo e sumarização das principais funcionalidades, aspectos positivos e negativos dos ambientes geradores de código mais relevantes.
Isto ajudou na caracterização e determinação do panorama atual dos ambientes geradores de
código.
Para atender à necessidade do mapeamento de modelos foi criado o documento M3 L que
tornou possı́vel representar em linguagem XML os mapeamentos entre modelos realizados a
partir de modelos UML.
Desenvolveu-se uma interface gráfica que permite mapear visualmente diferentes modelos
e produzir o documento M3 L. Essa interface tornou mais simples e intuitiva a visualização e
mapeamento dos modelos.
Para validação da teoria de suporte a mapeamento de modelos no processo de geração de
código seguindo o padrão MDA, foi criado o ambiente XO2 . O ambiente é flexı́vel, modular,
extensı́vel e reutilizável e segue o padrão MDA. O XO2 é capaz de produzir código-fonte de
acordo com os modelos e os templates especificados.
Para possibilitar a escrita dos templates com mais facilidade, clareza e robustez, foi criada
uma extensão da linguagem VTL.
Finalmente, criou-se uma camada de abstração que facilitou o acesso aos elementos do
modelo UML. A utilização desta camada, abrevia a quantidade de código escrito nos templates
provendo um caminho mais curto de acesso aos elementos.
6.2 TRABALHOS FUTUROS
6.2
101
Trabalhos Futuros
Com o surgimento de novas tecnologias e padrões, acredita-se a área de geração de código
ainda possa evoluir bastante através dos novos estudos e implementações que serão detalhados
a seguir.
Na versão atual do XO2 é permitida apenas a utilização do Diagrama de Classes da linguagem UML em conjunção com outros diagramas e outros modelos. Desta forma, uma extensão muito interessante ao ambiente seria permitir a utilização de outros diagramas da linguagem UML como o Diagrama de Seqüência e o de Interação, pois ambos fornecem informações
comportamentais que podem auxiliar na criação do corpo de métodos das diversas classes do
sistema.
Também poderia ser implementada uma extensão para tornar a interface gráfica compatı́vel
com outros modelos, pois a versão atual apenas permite a visualização da estrutura do Diagrama
de Classes UML e Modelo Entidade-Relacionamento. Tal implementação tornaria mais fácil a
utilização de outros modelos no processo de geração de código através do mapeamento de
modelos.
A versão atual do documento M3 L pode evoluir e permitir o uso de referências para outros
documentos e, com isso, aumentar o número de modelos e facilitar a interação entre o ambiente
e os modelos utilizados.
Como extensão pretende-se implementar uma funcionalidade que permita a alteração dos
modelos na própria interface gráfica do ambiente XO2 . Tal funcionalidade tornaria mais ágil
realizar pequenas alterações nos modelos.
Uma outra possibilidade interessante seria permitir engenharia reversa de código-fonte. Tal
funcionalidade permitiria que o próprio código-fonte fosse um dos modelos de entrada do ambiente e facilitaria assim a introdução do ambiente XO2 no processo de desenvolvimento de
sistemas já desenvolvidos. Com a engenharia reversa também seria possı́vel realizar a consistência entre modelos de Análise e Projeto e implementação. Isso permitiria que alterações
realizadas no código de implementação fosse diretamente refletida nos modelos.
APÊNDICE A
VTL - VELOCITY TEMPLATE LANGUAGE
A linguagem VTL foi criada para produzir páginas web dinâmicas a partir de templates. Um
template é um documento que contém uma série de diretivas para a transformação de código
Java. O seu conteúdo é formado pelos elementos estáticos do código a ser produzido, neste caso
HTML, e por elementos dinâmicos, que serão processados durante a execução. Até mesmo um
designer (que normalmente não possui conhecimentos sobre programação) é capaz de criar templates para o ambiente Velocity, pois este fornece as principais caracterı́sticas de uma linguagem
de programação como: controle de fluxo (if, for), variáveis, operadores lógicos, aumentando
assim a flexibilidade durante a criação dos templates.
VTL faz uso de referências para acessar objetos do sistema. Para acessar uma variável
utiliza-se o sı́mbolo ‘‘$’’ na frente do nome da variável (e.g. $nome). As referências também
são utilizadas para acessar atributos e métodos de um objeto (e.g. $pessoa.getNome()). O uso
dos caracteres ‘‘$!’’ faz com que o engenho do Velocity não retorne nenhum valor quando a
variável, atributo ou método não existir.
As diretivas VTL são iniciadas pelo sinal ‘‘#’’. A diretiva set atribui valores ou referências
a uma variável. O Exemplo A.1 atribui à variável idade o mesmo valor do atributo idade do
objeto pessoa. Enquanto que a variável cont terá 2 acrescido ao seu valor. Como pode-se
notar, em VTL o usuário não precisa se preocupar com os tipos das variáveis.
Exemplo A.1 Atribuição de valores em VTL
1 #s e t ( $ i d a d e = $ p e s s o a . i d a d e ) #s e t ( $ c o n t = $ c o n t +2);
A linguagem VTL permite, também, o uso de diretivas de controle de fluxo como nas
linguagens imperativas. A diretiva condicional if deve ser finalizada com um end e possui
elseif e else como diretivas opcionais. O Exemplo A.2 mostra que se a condição idade >
18 for satisfeita a saı́da produzida será: “Permitido”, caso contrário será: “Negado”.
Exemplo A.2 Diretiva condicional if em VTL
1 #i f ( $ idade >18)
2
Permitido .
3 #e l s e
4
Negado .
5 #end
103
104
VTL - VELOCITY TEMPLATE LANGUAGE
Existe também a diretiva foreach que permite iterar por todos os elementos de uma determinada coleção. No Exemplo A.3, a variável aluno poderá ser referenciada apenas no escopo
do laço foreach. Assim, aluno é uma referência para um objeto da coleção alunos.
Exemplo A.3 Laço de repetição em VTL
1 #f o r e a c h ( $ a l u n o i n $ a l u n o s ) $ a l u n o . nome #end
A diretiva foreach também pode ser utilizada para criar uma laço for, como mostra o
Exemplo A.4. O laço será iterado três vezes e o valor de cada iteração será retornado.
Exemplo A.4 Laço de repetição em VTL
1 #f o r e a c h ( $ i i n [ 1 . . 3 ] ) $ i #end
A diretiva include possibilita a inserção de documentos no template sem que estes sejam
processados. Já a diretiva parse serve para incluir um outro template a ser processado.
A VTL permite dois tipos de comentários que estão ilustrados no Exemplo A.5.
Exemplo A.5 Comentários em VTL
1 ## Comentario s i m p l e s
2
3 #* Comentario multi −l i n h a *#
O Exemplo A.6 mostra um template Velocity onde os dados de um objeto da classe Pessoa
são exibidos. Um objeto dessa classe possui atributos como nome, idade e telefone e, ainda,
uma coleção de objetos da classe Pessoa que representam os seus dependentes.
Exemplo A.6 Exemplo Velocity
1
2
3
4
5
6
7
8
9
10
11
#s e t ( $ d e p e n d e n t e s = $ p e s s o a . g e t D e p e n d e n t e s ( ) )
Nome : $ p e s s o a . nome
Idade : $ p e s s o a . i d a d e
Telefone : $pessoa . t e l e f o n e
Dependentes :
#f o r e a c h ( $ dependente i n $ d e p e n d e n t e s )
Nome : $ dependente . nome
Idade : $ dependente . i d a d e
#end
A primeira linha declara uma referência para a coleção dependentes do objeto da classe
pessoa. As linhas 3, 4 e 5 exibem os dados da classe e seus valores. Entre as linha 8 e 11 está
o código para exibir o nome e a idade de cada dependente.
REFERÊNCIAS BIBLIOGRÁFICAS
[Amb00]
Scott W. Ambler. Mapping Objects to Relational Databases, 2000.
[and03]
David S. Platt and. Introducing Microsoft .Net. Microsoft Press, 2003.
[And05]
AndroMDA. http://www.andromda.org. Última visita em 1 de Setembro, 2005.
[Apa05a]
Apache. Apache. http://www.apache.org. Última visita em 1 de Setembro, 2005.
[Apa05b]
Apache. Xerces. http://xml.apache.org/xerces-j/. Última visita em 1 de Setembro,
2005.
[BCNN91] Carlo Batini, Stefano Ceri, Shamkant B. Navathe, and Sham Navathe. Conceptual
Database Design: An Entity-Relationship Approach. Addison-Wesley, 1991.
[Ber03]
Hans Bergsten. JavaServer Pages (3rd Edition). O’Reilly, 2003.
[BGG00]
Gunther Birznieks, Scott Guelich, and Shishir Gundavaram. CGI Programming with
Perl. O’Reilly, 2000.
[BRJ98]
Grady Booch, James Rumbaugh, and Ivar Jacobson. The Unified Modeling Language
User Guide. Addison-Wesley, 1998.
[CG03]
Jim Cole and Joseph D. Gradecki. Mastering Apache Velocity. Wiley, 2003.
[Cod05]
Qualiti Coder. http://coder.qualiti.com. Última visita em 1 de Setembro, 2005.
[COS+ 01] Fernando Castor, Kellen Oliveira, Adeline Souza, Gustavo Santos, and Paulo Borba.
Jats: a java transformation system. XV Simpósio Brasileiro de Engenharia de
Software, 2001.
[DuB02]
Paul DuBois. MySQL Cookbook. O’Reilly, 2002.
[Ecl05a]
Eclipse. Eclipse. http://eclipse.org. Última visita em 1 de Setembro, 2005.
[Ecl05b]
Eclipse. SWT. http://eclipse.org/swt/. Última visita em 1 de Setembro, 2005.
[eG05]
Gentastic! e Gen. http://www.gentastic.com. Última visita em 1 de Setembro, 2005.
105
106
[GDB02]
REFERÊNCIAS BIBLIOGRÁFICAS
Timothy J. Grose, Gary C. Doney, and Stephen A. Brodsky. Mastering XMI: Java
Programming with XMI, XML, and UML. Wiley, 2002.
[Gen05]
Gentleware. http://www.gentleware.com. Última visita em 1 de Setembro, 2005.
[GHJV95] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns:
Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995.
[Har01]
Elliotte Rusty Harold. XML Bible, 2nd Edition. Wiley, 2001.
[Her03]
Jack Herrington. Code Generation in Action. Manning Publications, 2003.
[Hib05]
Hibernate. http://www.hibernate.org. Última visita em 1 de Setembro, 2005.
[iQg05]
InnoQ iQgen. http://www.innoq.com/iqgen. Última visita em 1 de Setembro, 2005.
[Jak05]
Apache Jakarta. Tomcat. http://jakarta.apache.org/tomcat. Última visita em 1 de
Setembro, 2005.
[JBu05]
Borland JBuilder. http://www.borland.com/jbuilder. Última visita em 1 de Setembro, 2005.
[JDG03]
Nicholas Lesiecki Joseph D. Gradecki. Mastering AspectJ: Aspect-Oriented Programming in Java. Wiley, 2003.
[Joh05]
James
H.
Johnson.
Micro
Projects
Cause
Constant
http://www.agilealliance.org/articles/articles/Chapter30-Johnson.pdf.
Change.
Última
visita em 1 de Setembro, 2005.
[JR03]
David Jordan and Craig Russell. Java Data Objects. O’Reilly, 2003.
[KB04]
Cynthia Andres Kent Beck. Extreme Programming Explained : Embrace Change.
Addison-Wesley, 2004.
[Kru00]
Philippe Kruchten. The Rational Unified Process: An Introduction (2nd Edition).
Addison-Wesley, 2000.
[KWB03] Anneke Kleppe, Jos Warmer, and Wim Bast. MDA Explained: The Model Driven
Architecture: Practice and Promise. Addison-Wesley, 2003.
[LC97]
Mary E. S. Loomis and Akmal B. Chaudhri. Object Databases in Practice. Prentice
Hall, 1997.
REFERÊNCIAS BIBLIOGRÁFICAS
[MDR05]
107
MDR. Metadata Repository. http://mdr.netbeans.org. Última visita em 1 de Setembro, 2005.
[Mei05]
Silvio Meira. O fim da vida do ’estagiáro’. http://www.meira.com. Última visita em
1 de Setembro, 2005.
[MH01]
Richard Monson-Haefel. Enterprise JavaBeans. O’Reilly, 2001.
[Net05]
Netbeans. http://www.netbeans.org. Última visita em 1 de Setembro, 2005.
[Nic05]
Phillip L. Nico. The Death of the Programmer. http://www.csc.calpoly.edu/ pnico/.
Última visita em 1 de Setembro, 2005.
[Ora05a]
Oracle. http://www.oracle.com. Última visita em 1 de Setembro, 2005.
[Ora05b]
Oracle. Toplink. www.oracle.com/technology/products/ias/toplink/. Última visita
em 1 de Setembro, 2005.
[Rat05]
Rational. http://www.ibm.com/software/rational/. Última visita em 1 de Setembro,
2005.
[Ree00]
George Reese. Database Programming with JDBC and Java. O’Reilly, 2000.
[Sun05a]
Sun. Java Code Conventions. http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html.
Última visita em 1 de Setembro, 2005.
[Sun05b]
Sun. Javadoc. http://java.sun.com/j2se/javadoc/. Última visita em 1 de Setembro,
2005.
[Sun05c]
Sun. JFC/Swing. http://java.sun.com/products/jfc/. Última visita em 1 de Setembro, 2005.
[Sun05d]
Sun. JMI. http://java.sun.com/products/jmi/. Última visita em 1 de Setembro,
2005.
[SWA02]
Ron Jeffries Scott W. Ambler. Agile Modeling: Effective Practices for Extreme
Programming and the Unified Process. Wiley, 2002.
[Tag05]
Jakarta Taglibs. http://jakarta.apache.org/taglibs/. Última visita em 1 de Setembro,
2005.
[Tig05]
Tigris. http://argouml.tigris.org/. Última visita em 1 de Setembro, 2005.
108
REFERÊNCIAS BIBLIOGRÁFICAS
[UFP05]
UFPE. SIGA. http://www.siga.ufpe.br. Última visita em 1 de Setembro, 2005.
[VDo05]
VDoclet. http://vdoclet.sourceforge.net. Última visita em 1 de Setembro, 2005.
[WCO00] Larry Wall, Tom Christiansen, and Jon Orwant. Programming Perl. O’Reilly, 2000.
[Wei00]
A. Keyton Weissinger. ASP in a Nutshell. O’Reilly, 2000.
[WR03]
Craig Walls and Norman Richards. XDoclet in Action. Manning Publications, 2003.
[WT04]
Luke Welling and Laura Thomson. PHP and MySQL Web Development. Sams,
2004.
[YJW98]
J. Yoder, R. Johnson, and Q. Wilson. Connecting business objects to relational databases. In Proceedings of the 5th Conference on the Pattern Languages of Programs,
1998.
Download

João Paulo Augusto de Oliveira Ferreira