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>  ;</ 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>  ;</ 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.