Uma ferramenta para a aprendizagem de desenvolvimento de sistemas - PDF\nUma ferramenta para a aprendizagem de desenvolvimento de sistemas\nDownload "Uma ferramenta para a aprendizagem de desenvolvimento de sistemas"\nRafael Back Palma\n1 UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA CURSO DE CIÊNCIAS DA COMPUTAÇÃO Uma ferramenta para a aprendizagem de desenvolvimento de sistemas AUTOR: Rodrigo Gonçalves Trabalho de Conclusão de Curso apresentado como parte dos requisitos para obtenção do grau de Bacharel em Ciências da Computação. ORIENTADOR: Prof. Antônio Carlos Mariani Florianópolis, SC 2004/2\n2 Rodrigo Gonçalves Uma ferramenta para a aprendizagem de desenvolvimento de sistemas Trabalho de Conclusão de Curso apresentado como parte dos requisitos para a obtenção do grau de Bacharel em Ciência da Computação. Orientador: Prof. Antônio Carlos Mariani Banca Examinadora Prof. Frank Siqueira Prof. Ronaldo dos Santos Mello\n3 II À minha família, sempre presente.\n4 III Agradecimentos Agradeço em primeiro lugar à meus pais, Valdir José Gonçalves e Ivone Vieira Gonçalves. Não teria feito nem metade do que fiz até hoje se não fosse por seus esforços e atenção dada. Agradeço ao meu orientador, Antônio Carlos Mariani, pela idéia original do projeto e pelas importantes orientações e dúvidas resolvidas durante a confecção deste. Agradeço aos membros da banca examinadora, Frank Siqueira e Ronaldo dos Santos Mello, pelos valorosos comentários sobre o trabalho, que enriqueceram o mesmo. Não posso deixar de agradecer a minha irmã, Renata Gonçalves, que serviu de cobaia ao final do trabalho durante a preparação da apresentação do mesmo. Por último, mas não menos importante, agradeço aos amigos, que ou através de sugestões ou apenas me aturando, contribuíram para a realização deste trabalho.\n5 IV Resumo Neste trabalho apresenta-se uma ferramenta para auxiliar o processo de aprendizagem sobre desenvolvimento de sistemas computacionais. Esta permite a modelagem visual de sistemas computacionais, através de diagramas de classes segundo a notação UML. A partir deste, gera-se de forma automatizada o código correspondente (em ambiente Smalltalk), já incluindo o suporte a persistência dos dados envolvidos sobre um banco de dados relacional através de um framework de persistência. PALAVRAS CHAVE: Ensino, Engenharia de Software, Banco de dados\n6 V Abstract What is presented here is a tool to help the learning process of developing computational systems. This tool allows visual modeling of computational systems, through the use of class diagrams, following the UML notation. Based on this, it generates in an authomated manner the corresponding code (in the Smalltalk environment), already including suport for the persistence of the involved data over a relational database, using a persistence framework for that. KEYWORDS: Teaching, Software Engineering, Database systems\n7 Lista de Figuras 2.1 Um exemplo de estrutura de um banco de dados relacional Um exemplo de modelo de objetos, segundo a notação UML Uma sugestão para o mapeamento genérico. Retirado de W. Ambler O diagrama de classes da representação em memória de um documento XMI As classes responsáveis por representar uma hierarquia de classes segundo o paradigma OO As classes que armazenam as informações sobre um modelo relacional Os geradores de esquemas relacionais O componente de geração de instruções DDL O componente responsável pela geração do suporte à persistência Um exemplo de interface gerada pelo sistema O componente de geração de interfaces O fluxograma de execução do Gerador de Sistemas O sistema exemplo modelado - uma clínica simples A configuração para geração do projeto exemplo A geração do sistema em andamento A interface do modelador de sistemas A barra de açoes do modelador A barra de elementos do modelador\n8 VII 7.4 Um classe no modelador O menu da classe A tela de adição de atributos à classe Uma herança Uma anotação Uma associação A tela de geração de sistema\n9 Lista de Tabelas 6.1 Classes geradas pela ferramenta e seus respectivos métodos Tabelas geradas pela ferramenta\n10 Sumário 1 Introdução 1 2 Bancos de dados relacionais Conceito Modelo relacional Estrutura Integridade Manipulação dos dados Programação Orientada a Objetos Definição Histórico Conceitos básicos Polimorfismo Modelo de objetos Mapeamento do paradigma OO para o modelo relacional Introdução Correspondência entre os conceitos do paradigma OO e o modelo relacional O processo de mapeamento Mapeamento de classes, hierarquias e atributos Atributos\n11 X Mapeamento de classes e hierarquias Mapeamento de propriedades de classes Mapeamento dos relacionamentos entre classes Ferramentas de mapeamento OO-relacional Características e tecnologias utilizadas na ferramenta desenvolvida Visão geral Linguagem adotada Sobre o Smalltalk Sobre o Squeak Notação utilizada para modelagem de sistemas Recursos da UML aceitos Tipos de dados Mapeamento do modelo OO para o relacional GLORP Persistência Manipulando dados Maiores informações XMI O Gerador de Sistemas Visão geral Documento XMI Diagrama de classes Representação do modelo relacional Gerador de Esquema Relacional Gerador de comandos DDL Gerador de classes Gerador da camada de persistência Gerador de Interfaces\n12 XI 6.10 Gerador de projetos Fluxograma da geração de um projeto Um exemplo de geração de sistema O Modelador de Sistemas Visão geral Interface Diagrama de classes Barra de ações Barra de elementos Elementos da modelagem Classes Heranças Anotações Associações Gerando um sistema Validações Estrutura interna Sobre o trabalho 70 9 Conclusão e trabalhos futuros 74 Referências Bibliográficas Anexos I 10.1 Anexo I - Fonte do sistema exemplo gerado pela ferramenta I 10.2 Anexo II - Fontes da ferramenta desenvolvida XXV 10.3 Anexo III - Artigo CLXVI\n13 Capítulo 1 Introdução Um sistema computacional (também chamado de programa ou software) é uma entidade lógica que pode ter diversas finalidades: desde a solução de um problema complexo de cálculo estrutural até apenas puro entretenimento. Ele pode ter uma representação física (em um sistema para identificação de funcionários, o leitor de digitais) ou ser completamente abstrato (um agente de software rodando em redes de comunicação). Pode-se considerar que um sistema é composto por várias camadas, cada uma com sua finalidade. Uma das possíveis composições pode incluir as seguintes camadas [Larman 2002]: Apresentação - Interface com o usuário do sistema (telas, etc.). Aplicação - Controle de sessões de usuários, estados do sistema, fluxos de execução, etc. Domínio - As regras e serviços que o sistema deve respeitar e prover. Infra-estrutura de negócio - Serviços de baixo nível disponibilizados e utilizados pelo sistema. Serviços técnicos - Serviços de alto nível como persistência de dados 1 e segurança. Fundação - Elementos como banco de dados, rede de comunicação, etc. 1 Armazenar os dados em meio físico não-volátil\n14 O desenvolvimento de sistemas computacionais é o processo de, dado um problema, analisá-lo, definir um sistema que o resolva (ou auxilie na sua resolução) e por fim implementá-lo. Esta atividade relaciona-se diretamente com capacidade de processamento dos computadores, a qual, à medida que evoluiu, permitiu o surgimento de ferramentas e recursos (abstrações como objetos 2 ) nas linguagens de programação que simplificaram o processo. Porém, mesmo com esta evolução, a atividade é considerada complexa para alguém começando a familiarizar-se com a mesma. Este fato é observado em alunos de disciplinas de programação de caráter introdutório, em cursos como Ciências da Computação e Sistemas de Informação. As dificuldades enfrentadas por estes são a motivação para este trabalho. Desenvolveu-se neste trabalho uma ferramenta para auxiliar o aprendizado sobre desenvolvimento de sistemas. Esta destina-se àqueles não familiarizados com o processo. Logo deve ser simples de usar, com recursos suficientes para permitir o desenvolvimento de sistemas computacionais de baixa complexidade. Convém salientar que ela não visa ser utilizada sem a supervisão de alguém experiente no desenvolvimento de sistemas. Ela não implementa aspectos que visem ensinar aqueles que a utilizem sobre o desenvolvimento de sistemas, como caixas explicativas, demonstrações de como mapeiam-se elementos do mundo real para elementos em um sistema computacional, etc. Ao falar-se em desenvolvimento de sistemas, diversos tópicos estão envolvidos, dependendo do processo (UP 3, XP 4, etc.) e do paradigma de programação (Orientado a Objetos 5, procedural, etc.) adotado. A criação de uma ferramenta capaz de considerar todos os processos e paradigmas acabaria sendo muito extensa. Logo, este trabalho foca no paradigma orientado a objetos (OO) e nos seguintes tópicos relacionados ao desenvolvimento de software: Modelagem de sistemas através de Modelos de Objetos; 2 Veja a seção Unified Process - um processo de desenvolvimento de software organizado em ciclos iterativos [Larman 2002] 4 Extreme Programming - um processo de desenvolvimento de software orientado pelas necessidades do usuário, que busca adaptar-se facilmente à mudanças de requisitos [What is Extreme Programming? 2004] 5 Veja a seção 3.1 2\n15 3 parte básica da implementação; persistência de dados. O paradigma de programação OO foi adotado dada sua grande aceitação e popularidade, assim como sua capacidade em representar de forma simples entidades do mundo real e suas relações. Os Modelos de Objetos 6 nada mais são que representações gráficas dos elementos do paradigma OO que compõe um sistema. Eles dão uma visão da parte estática deste, que inclui os elementos que fazem parte do sistema e as relações entre os mesmos. A persistência de dados é um dos aspectos mais importantes em grande parte dos sistemas computacionais. Para a persistência de dados decidiu-se pelo uso de um banco de dados que segue o modelo relacional 7. A utilização de um banco de dados deve-se ao interesse em apresentar e familiarizar (em caráter introdutório) o usuário a uma das tecnologias mais utilizadas na Computação. A adoção de um banco de dados relacional em detrimento a um banco objeto-relacional (ou mesmo orientado a objetos) deve-se ao interesse em demonstrar a quem utiliza a ferramenta as diferenças na representação dos dados entre os dois paradigmas (OO e relacional), assim como familiarizar o usuário com o modelo de representação de dados mais utilizado pelos bancos de dados atuais. Não adota-se um processo de desenvolvimento de software, deixando esta escolha a cargo do usuário e seu orientador. A ferramenta desenvolvida pode ser definida em três componentes principais: Um modelador de sistemas segundo o conceito de Modelo de Objetos, utilizando um diagrama de classes conforme a notação UML 8. Um analisador e gerador que, a partir do diagrama de classes, gere o código básico de um sistema compatível com o diagrama, assim como um modelo relacional sobre 6 Veja a seção Maiores informações na seção Unified Modeling Language - Veja a seção 5.3\n16 4 o qual os dados envolvidos pelos elementos da modelagem possam ser persistidos. Um sistema de suporte a persistência dos dados sobre o modelo relacional elaborado. Este relatório compõe-se de três partes principais: uma revisão bibliográfica dos assuntos envolvidos; uma descrição detalhada da ferramenta desenvolvida; e por fim uma análise sobre o resultado do trabalho, levantando problemas, soluções e propostas para outros trabalhos. A revisão bibliográfica está divida em três capítulos: nos capítulos 2 e 3 revisam-se conceitos relacionados ao modelo relacional e à Programação Orientada a Objetos. No quarto capítulo faz-se uma análise detalhada sobre as diversas formas e o processo de mapeamento entre os paradigmas OO e relacional, analisando as vantagens e desvantagens de cada abordagem. A descrição da ferramenta é composta por um capítulo introdutório apresentando as principais características e descrevendo as tecnologias adotadas. O capítulo seguinte trata do Gerador de Sistemas, descrevendo sua estrutura e funcionamento. Por último descreve-se a ferramenta de modelagem (o Modelador de Sistemas ), detalhando sua interface e estrutura interna. A última parte divide-se em dois capítulos: no capítulo 8 discorre-se sobre o trabalho desenvolvido, comentando problemas encontrados, soluções para estes problemas, etc. No capítulo 9 trata-se das conclusões a respeito do trabalho e sugestões para trabalhos futuros.\n17 Capítulo 2 Bancos de dados relacionais 2.1 Conceito Um sistema gerenciador de banco de dados pode ser definido como: um sistema de armazenamento de dados baseado em computador; isto é, um sistema cujo objetivo global é registrar e manter informação [Date 1986]. Seu objetivo é servir como suporte a outros sistemas, fornecendo os dados necessários para que estes executem as tarefas às quais foram destinados. A maneira como este sistema organiza e manipula o banco de dados (o conjunto de informações pelo qual é responsável) dá origem a diversos paradigmas (ou modelos ), dentre os quais o mais difundido é o relacional. Sua popularidade devese à simplicidade, consistência, facilidade de uso e firmes fundações matemáticas que o validam [Stoimenov 1998]. Outros modelos surgiram mais recentemente, como o orientado a objetos, objeto-relacional e os bancos de dados XML 1. 1 Extensible Markup Language\n18 6 2.2 Modelo relacional O modelo relacional preocupa-se com três aspectos principais em relação aos dados: estrutura, integridade e manipulação. Ele foi proposto por E. F. Codd em 1970, sendo o primeiro modelo formal para bancos de dados. Anterior a este existiam modelos como o hierárquico e de rede [Silberschatz, K. Korth e Sudarshan 1999] Estrutura O modelo relacional compõe-se de relações (também chamadas tabelas ) que representam (de forma parcial ou completa) entidades (abstratas ou concretas) que possuam características em comum. As relações são consideradas matematicamente como conjuntos. Cada entidade em uma relação é representada por uma tupla (ou linha ) contendo atributos (ou colunas ) que caracterizam a entidade. Todas as tuplas de uma relação devem possuir os mesmos atributos. Uma mesma relação não deve possuir duas tuplas com os mesmos valores para todos os seus atributos, pois trata-se de um conjunto, que não admite valores repetidos por definição. Os atributos de uma tupla têm tipo fixo e este deve ser simples (escalar ou atômico ) como cadeias de caracteres, blocos de texto, números, etc. Uma tupla não pode ser composta por outras tuplas ou dados complexos (estruturas de dados). Um atributo de uma tupla pode ou não ser informado. Um último elemento integrante do modelo relacional são as visões. Estas são tabelas que não possuem existência própria, sendo constituídas por outras tabelas ou mesmo visões [Date 1995]. Através delas é possível definir diferentes formas de visualizar as informações contidas nas tabelas do esquema relacional (como visualizar apenas tuplas que satisfaçam uma determinada condição).\n19 7 Figura 2.1: Um exemplo de estrutura de um banco de dados relacional Integridade Integridade em um banco de dados refere-se à capacidade do mesmo em manter a consistência dos dados que armazena [Silberschatz, K. Korth e Sudarshan 1999]. No modelo relacional a integridade dos dados baseia-se em dois conceitos principais: chaves primárias e chaves estrangeiras [Date 1995]. Para identificar uma tupla de uma relação, define-se uma chave primária. Esta é um valor único associado a cada tupla que a diferencia das demais na relação a que pertencem. Este valor é representado através de um ou mais atributos da tupla. Não é necessário que esta identificação seja única para o banco de dados como um todo. Para relacionar as tabelas, o modelo relacional fornece as chaves estrangeiras. Através destas define-se um conjunto de atributos em uma relação que representam o valor da chave primária de uma tupla em outra (ou em alguns casos da mesma) relação. Com isto consegue-se estabelecer qualquer associações de grau 1:1, 1:N e N:N 2. Outras formas de integridades também são fornecidas pelos bancos de dados, como validações de domínio, asserções, etc. Para informações sobre as mesmas, pode-se consultar [Date 1995]. 2 Veja um exemplo na figura 2.1\n20 Manipulação dos dados A manipulação dos dados no modelo relacional é definida pela álgebra relacional. Os detalhes a respeito do funcionamento da mesma não serão tratados aqui. Cabe apenas ressaltar que a manipulação resume-se a inserir, alterar, excluir e recuperar tuplas das relações. Para determinar sob quais tuplas as operações irão operar utilizam-se predicados da álgebra relacional que permitem escolher determinadas tuplas com base nos valores dos seus atributos. É possível também operar sobre mais de uma relação ao mesmo tempo ao executar uma determinada manipulação de dados. Nos bancos de dados não é comum utilizar-se a álgebra relacional, mas sim a SQL 3 para manipulação dos dados. Esta é uma linguagem declarativa com forma similar à algebra relacional porém sintaxe mais simples. Um exemplo de consulta em algebra relacional que retorna o nome e idade dos pacientes que sejam do sexo feminino é: π NOME,IDADE (σ SEXO= F (P ACIENT ES)) (2.1) Já em SQL, a consulta ficaria na seguinte forma: SELECT NOME, IDADE FROM PACIENTES WHERE SEXO= F Para mais informações a respeito da manipulação de dados em bancos de dados relacionais pode-se consultar [Date 1995] e [Silberschatz, K. Korth e Sudarshan 1999]. 3 SQL - Structured Query Language\n21 Capítulo 3 Programação Orientada a Objetos 3.1 Definição Programação Orientada a Objetos pode ser definida como a programação que é implementada pelo envio de mensagens a objetos [Pinson 1988]. Tendo como base esta definição, podemos afirmar que este estilo de programação consiste em identificar objetos (abstratos ou concretos) em um domínio e definir mensagens (métodos) para os mesmos. A combinação de mensagens a um ou mais objetos permite chegar a solução de um problema. 3.2 Histórico Simula I ( ) e Simula 67 (1967) foram as primeiras linguagens orientadas a objeto(oo). Simula 67 introduziu conceitos como objetos e classes. Estas linguagens foram desenvolvidas por Ole-Johan Dahl e Kristen Nygaard partindo de uma necessidade de Nygaard, que precisava de uma ferramenta que permitisse uma descrição e simulação de sistemas homem-máquina complexos. Em 1961 surgiu a idéia de desenvolver uma linguagem que podesse ser utilizada tanto para descrever sistemas quanto comandar um computador [Nygaard e Dahl]. A partir de Simula, um grupo de pesquisadores da Xerox desenvolveu\n22 10 o Smalltalk 1, estendendo os recursos de Simula pela integração de uma interface gráfica com o usuário e a execução interativa de programas. Mais tarde (na década de 80) Bjarne Strostrup começa a desenvolver C++, introduzindo conceitos de Simula na linguagem C [Nygaard e Dahl]. 3.3 Conceitos básicos Objeto É o conceito básico do paradigma OO. Representa uma entidade de um determinado domínio (problema). Tecnicamente é uma estrutura de dados que possue um comportamento e um estado definido. Ele abstrai e encapsula detalhes sobre si que não são pertinentes ao sistema (elementos privados), deixando visível apenas aquilo que o sistema requer (elementos públicos). Atributos São características associadas aos objetos que definem um estado ao mesmo. [Rumbaugh 1991] define que um atributo deve ser um valor de dados puro, que não seja representado por um objeto. Esta definição, porém, não é completamente adequada a certas linguagens, como Smalltalk, onde o conceito de dados puros não existe (tudo é objeto). Métodos Representam mensagens que um objeto pode receber, e em resposta executa uma seqüência de ações que podem alterar seu estado. Os métodos podem ou não conter parâmetros que guiem sua execução. Classe É um conjunto de objetos que apresentam a mesma estrutura e comportamento, porém valores de atributos diferentes. Os objetos são sempre instâncias de alguma classe. Uma classe porém pode não possuir instâncias (classe abstrata). As classes também podem herdar a estrutura de outras classes através do conceito de herança. Herança No paradigma OO, uma classe pode derivar uma ou mais classes. As classes derivadas (subclasses) herdam da classe que derivam (superclasse) os métodos e 1 Maior informações sobre o Smalltalk na seção 5.2.1\n23 11 atributos. É possível a uma classe herdar características de mais de uma classe utilizando o conceito de herança múltipla (este porém não é suportado pela maioria das linguagens OO). Relacionamentos São a maneira pela qual os objetos que compõe um sistema relacionamse. Podem ser associações (não há dependência de existência entre os objetos) ou composições (um objeto compõe-se de outros objetos, atrelando a existência destes a sua própria existência). Encapsulamento Consiste na separação dos aspectos externos de um objeto, que são acessíveis por outros objetos, dos aspectos internos de implementação, escondidos dos outros objetos [Rumbaugh 1991]. O encapsulamento auxiliar a tornar os objetos independentes da forma como outros objetos são implementados, permitindo, por exemplo, que altere-se a implementação interna de um objeto sem afetar os demais objetos presentes no sistema. 3.4 Polimorfismo Polimorfismo é um recurso das linguagens OO onde pode-se enviar uma mensagem a um objeto (desde que o mesmo a suporte) sem ter conhecimento da classe exata a que o mesmo pertence. Dessa forma, diferentes objetos de diferentes classes podem responder a uma mesma mensagem de diferentes formas [Pinson 1988]. Outro aspecto do polimorfismo é a possibilidade de passar objetos de diferentes tipos como parâmetros para outros objetos. Em Smalltalk isto fica claro pela possbilidade de um paramêtro poder ser um objeto de qualquer classe. Já em outras linguagens, como Java, o tipo do parâmetros deve respeitar a hierarquia de classes para poder haver polimorfismo (o objeto deve ser da classe ou alguma das subclasses do tipo especificado no parâmetro).\n24 Modelo de objetos Um modelo é uma abstração criada para entender um problema antes de implementar uma solução. Um modelo de objetos descreve a estrutura dos objetos que compõe um sistema - suas identidades, relacionamentos, atributos e operações (métodos) [Rumbaugh 1991]. O objetivo ao construir um modelo de objetos (figura 3.1) é capturar os conceitos do mundo real que são importantes para a aplicação da qual se está construindo o modelo. Ele é representado por um diagrama contendo as classes, arranjadas em hierarquias, compartilhando comportamentos e atributos. As classes também estão relacionadas entre si (associações, composições, etc.). Este modelo não captura os aspectos dinâmicos (eventos e seqüências de operações no decorrer do tempo) e funcionais (as funções exercidas pelo sistema, independente da forma que são feitas internamente) [Rumbaugh 1991]. Figura 3.1: Um exemplo de modelo de objetos, segundo a notação UML\n25 Capítulo 4 Mapeamento do paradigma OO para o modelo relacional 4.1 Introdução The act of determining how objects and their relationships are persisted in permanent data storage, in this case relational databases. [W. Ambler 2003] Um dos paradigmas mais utilizados para o desenvolvimento de sistemas computacionais é o paradigma orientado a objetos. Este, introduzido no capítulo anterior, permite o desenvolvimento de sistemas robustos e com manutenção simplificada, graças a conceitos como encapsulamento 1 e herança. Quando surgiu, como toda nova tecnologia, anunciou-se que ele seria capaz de sanar todos os problemas existentes no desenvolvimento de sistemas ( tudo é objeto ). Dizia-se que a persistência orientada a objetos em bancos de dados era apenas uma questão de tempo [Ambler 2003] 2. Porém a principal forma de persistência dos bancos de dados continua a ser o modelo relacional, por razões já citadas anteriormente (fundações matemáticas, simplicidade, consistência e facilidade de uso) [Stoimenov 1998]. Alternativas a estes 1 Definido na seção No decorrer deste trabalho, os artigos de Scott Ambler são citados diversas vezes. Não foi possível, durante a confecção deste, obter o livro lançado pelo autor. A referência ao mesmo, porém, está presente na bibliografia ( [W. Ambler 2003])\n26 14 surgiram, como os bancos de dados orientados a objetos e os bancos de dados objetorelacional. Estes, porém, ainda não alcançaram a difusão e popularidade dos bancos relacionais. Face a isto, vê-se que há uma impedância no desenvolvimento dos sistemas: de um lado temos o paradigma OO e do outro o modelo relacional. Estes tratam as informações e sua organização de forma diferente. Portanto, a abordagem adotada para um em geral não pode ser aplicada diretamente ao outro. Integrar as duas abordagens é um fator crucial para simplificar o trabalho dos desenvolvedores. Para tal, surgiu o conceito de mapeamento objeto-relacional. Neste, desenvolve-se uma camada de persistência (um componente de software) que permite a um sistema orientado a objetos armazenar suas informações em um modelo relacional Correspondência entre os conceitos do paradigma OO e o modelo relacional Cabe em um primeiro momento discorrer como os conceitos do paradigma OO correspondem aos conceitos do modelo relacional: Classes são representadas por tabelas 3 (uma ou mais tabelas, dependendo da abordagem adotada). Objetos são as linhas das tabelas que representam as classes. Atributos são as colunas das tabelas. Relacionamentos estabelecem-se como relacionamentos baseados em chaves estrangeiras entre as tabelas. Herança é um dos aspectos mais complexos de representar sob o modelo relacional, dado o conceito de polimorfismo presente no paradigma OO. Adiante no capítulo detalha-se o problema. 3 A fim de simplificar o texto, os termos tabela, coluna e linha serão adotados quando for-se referir aos termos-equivalentes relação, atributo e tupla\n27 O processo de mapeamento O processo de mapeamento pode ser dividido em duas grandes etapas: o mapeamento de classes, hierarquias e atributos e o mapeamento das relações entre as classes. 4.3 Mapeamento de classes, hierarquias e atributos Atributos Os atributos das classes são mapeados como colunas no modelo relacional. Este mapeamento envolve atributos de tipo simples, como cadeias de caracteres, números, datas, horários, valores monetários, etc. Atributos que são outras classes do domínio ou tipos complexos são mapeados como outras tabelas, e o atributo torna-se um apontador (chave estrangeira). No paradigma OO (Orientado a Objetos), todo objeto possui um identificador único e global no sistema, que não é parte de seus atributos, send intríseco à linguagem. No modelo relacional, porém, este conceito não existe. No mapeamento, costuma-se adotar (para simplificar o mapeamento e posterior persistência dos dados) um identificador único arbitrário gerado internamente para cada objeto (por comodidade, um valor inteiro), persistido no banco de dados, e este fica armazenado internamente no objeto para o suporte a persistência [W. Rahayu et al. 2000]. Um problema relacionado a estes identificadores arbitrários é como gerá-los. Diversas alternativas foram propostas [W. Ambler 2000], dentre as quais citamse: Obter o maior valor do identificador entre os objetos da classe e incrementá-lo. Manter uma tabela responsável por armazenar o valor do último identificador de cada classe. Ter uma tabela para cada classe persistida que contenha o último identificador gerado.\n28 16 GUIDs / UUIDs - utiliza-se um hash 4 de algum identificador único do computador onde o sistema está rodando associado a data/hora para obter um valor que identifica de forma única o objeto. Sistemas proprietários - aqui destacam-se os campos de auto-incremento e geradores de sequenciais presentes em bancos de dados como Oracle 5, Firebird 6, PostgreSQL 7. HIGH / LOW IDs - supõe que o identificador de um objeto é composto por um valor superior e um inferior. O superior é gerado a cada sessão e o inferior a cada novo objeto persistido no banco de dados. Sobre os atributos, convém salientar que nem todos precisam ser persistidos, pois muitas vezes relacionam-se a aspectos importantes apenas durante uma sessão da qual o objeto faz parte, não tendo importância para outras sessões [W. Ambler 2003] Mapeamento de classes e hierarquias O mapeamento das classes e suas hierarquias para tabelas é o aspecto mais complexo do mapeamento, dado que o modelo relacional não oferece suporte ao conceito de herança. Quatro alternativas principais [W. Ambler 2003] existem para representar as hierarquias de classes, cada qual com vantagens e desvantagens Uma tabela para cada classe concreta Nesta abordagem considera-se cada classe concreta (não abstrata) a ser persistida como uma tabela. Esta abordagem é eficiente quando trabalha-se com consultas e atualização de objetos de forma individual ou limitada as classes folhas (classes que não possuem subclasses). Um sistema de persistência sobre esta abordagem também é relativamente simples. 4 Um número curto gerado a partir de outra informação - uma cadeia de caracteres por exemplo - que a identifica de forma próxima à unica\n29 17 A busca das informações para um objeto nesta abordagem é a mais rápida e simples, pois não necessita relacionar tabelas - os dados estão contidos em uma única tabela. O desempenho também é favorecido pela tabela conter apenas as informações dos objetos da classe em consulta [W. Ambler 2003]. Porém esta abordagem também apresenta problemas [W. Ambler 2003] sob determinadas situações como: Caso inclua-se um novo atributo em uma classe, é necessário alterar todas as tabelas que representam as classes concretas abaixo da mesma para conter o novo atributo. Um objeto que muda de papel dentro do sistema - a alteração do mesmo é custosa, pois envolve copiar todas as informações de uma tabela para a outra. Ela viola os conceitos de normalização 8. Por último, ela não suporta diretamente o polimorfismo - o relacionamento entre tabelas baseia-se no conceito de chaves estangeiras e estas não podem ser estabelecidas com mais de uma tabela ao mesmo tempo (o que seria necessário para o caso de uma tabela relacionando-se com a tabela equivalente a superclasse de n-classes). Esta abordagem tem seu principal uso em casos onde a sobreposição entre classes é limitada (hierarquias simples) e mudanças de tipos dos objetos são raras [W. Ambler 2003] Uma tabela por classe Nesta alternativa, cada classe do sistema (concreta ou abstrata) é mapeada para uma tabela no banco de dados. Cada tabela contém apenas os atributos relativos à classe que representa - os atributos herdados de outras classes ficam nas tabelas responsáveis por representar aquelas classes. Entre as tabelas de uma hierarquia são estabelecidas relações (através de chaves estangeiras) que identificam quais registros nas tabelas representam um deter- 8 [Date 1995] descreve o conceito de normalização\n30 18 minado objeto. Utiliza-se o mesmo identificador para toda a hierarquia de classes (nomeado, por exemplo, como o nome da classe mais superior mais um complemento, como ID ). Dessa forma fica simples relacionar as diversas classes da hierarquia para compor as informações dos objetos. Um artifício nesta abordagem é utilizar um atributo na classe mais alta na hierarquia que defina a qual das classes descendentes aquele registro pertence. Dessa forma é possível identificar, a partir do registro na classe superior, de qual classe descendente ele faz parte. Esta abordagem possui como vantagens [W. Ambler 2003]: excelente suporte ao polimorfismo, pois ao recuperar-se linhas de uma tabela incluise os objetos correspondente à classe desta tabela e todas as suas subclasses; facilidade de execução de operações envolvendo objetos de diferente classes, porém com mesmas classes superiores - uma alteração nos atributos de suas classes superiores é simplificada; a modificação das classes (adição, remoção de atributos) é simplificada, pois envolve alterar apenas uma única tabela; representa os dados de uma forma normalizada. As desvantagens dessa abordagem estão relacionadas a profundidade e complexidade da hierarquia. Quanto mais classes, maior a quantidade de tabelas no sistema e mais custosas podem ser tornar as atualizações ou recuperação de dados dos objetos (muitos relacionamentos entre tabelas). Para tentar sanar este problema, pode-se adotar o uso de visões 9 no banco de dados, que encarregam-se de camuflar esta divisão em n-tabelas em uma única tabela para cada classe concreta [W. Ambler 2003] Uma tabela por hierarquia Aqui transforma-se toda uma hierarquia de classes em uma única tabela, em geral nomeada segundo a classe mais alta. Neste caso a tabela contém os atributos de 9 Definidas na seção 2.2.1\n31 19 todas as classes da hierarquia, além de conter uma coluna funcionando como identificador de qual classe pertence o objeto representado por aquela linha. As vantagens desta abordagem são [W. Ambler 2003]: simplificação da estrutura do banco de dados, que fica reduzida a poucas tabelas; permite realizar a recuperação e atualização dos dados de forma simplificada, tanto de objetos individuais quanto de grupos de objetos (inclusive de atributos pertencentes a classes com subclasses). inclusão simplificada de novas classes - basta adicionar as colunas as tabelas. suporte ao polimorfismo Porém ela peca ao ignorar os conceitos de normalização. Também pode levar a um gasto extra do espaço de armazenamento do banco de dados, pois cada linha da tabela possui todos os atributos de todas as classes da hieraquia. Por último, as tabelas podem crescer de forma muito rápida por representarem diversas classes do sistema [W. Ambler 2003] Utilizar uma estrutura de tabelas genérica Esta abordagem introduz um mapeamento onde as informações sobre a estrutura das classes ficam guardadas em meta-tabelas ao invés de dar origem a outras tabelas. Uma estrutura de tabelas é sugerida na figura 4.1. Vê-se que cada classe é representa por um único registro na tabela Class e um ou mais registros na tabela Attribute. Os valores dos objetos armazenados ficam na tabela Value. Esta abordagem é diferenciada das demais porque pode tratar também os aspectos de relações entre classes, que não são considerados nas abordagens anteriores. Esta alternativa é extremamente flexível, porém não comporta-se bem quando o volume de dados cresce e a manipulação de informações é complexa [W. Ambler 2003].\n32 Figura 4.1: Uma sugestão para o mapeamento genérico. Retirado de W. Ambler\n33 Herança múltipla O mapeamento de herança múltipla de um modelo OO para o modelo relacional dá-se de forma natural para as abordagens citadas, bastando seguir as regras definidas. A única questão que aparece refere-se ao mapeamento de uma tabela por classe, em relação ao estabelecimento das chaves estrangeiras indicando a herança. Neste caso, deve-se estabelecer mais de uma herança (chave-estrangeira) para garantir a integridade dos dados Mapeamento de propriedades de classes Uma característica do paradigma OO é que uma classe pode conter atributos relacionados a ela, como entidade classe, não relacionados a suas instâncias (os objetos) e estes atributos muitas vezes precisam também ser persistidos. Existem diversas maneiras [W. Ambler 2003] de mapear os atributos de classe para o modelo relacional, dentre os quais os mais utilizados são: Uma tabela contendo uma única linha, onde cada coluna corresponde a um atributo da classe - o acesso e atualização dos dados é rápido e simples, porém esta forma pode dar origem a muitas tabelas. Uma única tabela, contendo uma coluna para cada atributo de cada classe do sistema - neste caso, o número de tabelas adicionais é de apenas uma, porém problemas de concorrência (mais de um processo tentando alterar o valor das colunas) tem grande possibilidade de ocorrer. Uma única tabela genérica com múltiplas linhas - os atributos são guardados em tuplas (classe, atributo, valor). Esta forma evita os problemas de concorrência do modelo anterior e requer apenas uma tabela adicional.\n34 Mapeamento dos relacionamentos entre classes O mapeamento de relacionamentos entre classes para o modelo relacional não apresenta diversas maneiras como no caso do mapeamento das classes e sua hierarquia. Cada um dos tipos de relacionamento (um para um, um para vários, vários para vários) possui uma ou no máximo duas formas de serem implementados (o que pode diferenciar a forma de mapeamento é a necessidade da visibilidade no relacionamento ser uni ou bidirecional). Relacionamento um para um Neste tipo de relacionamento, um atributo na tabela funciona como uma chave estrangeira para a outra tabela, estabelecendo o relacionamento entre as duas. Caso deseje-se um relacionamento bidirecional, ambas as tabelas possuirão colunas funcionando como chaves estrangeiras uma para a outra. Relacionamento um para vários Aqui o fato de optar-se por um relacionamento uni ou bidirecional muda a forma como ele é representado. No caso unidirecional, basta definir uma coluna na tabela representante do lado não-unitário do relacionamento que aponte para a linha da tabela do lado unitário. Caso deseje-se uma visibilidade bidirecional, é necessário criar uma tabela que contenha as chaves primárias de cada uma das tabelas integrantes do relacionamento, onde cada linha representa um relacionamento as classes. Relacionamento vários para vários Neste tipo, cria-se uma tabela auxiliar que conterá como colunas as chaves primárias das outras tabelas e onde cada linha representa um relacionamento entre as tabelas. A diferença entre uma composição e uma associação no mapeamento dá-se pelas regras de integridade (chaves estrangeiras) que podem utilizar deleção em cascata, por exemplo 10. Caso o mapeamento seja a um banco relacional que não suporte tais aspectos, cabe ao sistema de persistência adotado manter a integridade e consistência dos dados. 10 Para maiores informações sobre o conceito de deleção em cascata, veja [Date 1995]\n35 Ferramentas de mapeamento OO-relacional Diversas ferramentas existem para o suporte ao mapeamento entre o paradigma OO e o relacional no mercado. Estas concentram-se em dois pontos principais: desempenho e flexibilidade. Para dar flexibilidade ao mapeamento, ao ponto de permitir que modelos relacionais não projetados para persistências de sistemas OO sejam utilizados, as ferramentas deixam a cargo do usuário estabelecer o mapeamento. Em geral este mapeamento é definido através de um documento XML, onde basta alterar o mesmo para mudar o comportamento e regras de persistência do sistema. As ferramentas não apresentam (salvo poucas exceções), mecanismos para um mapeamento automático entre o modelo OO e o relacional. O mais próximo de uma automatização que as ferramentas disponibilizam em geral é a capacidade de gerar as classes e tabelas de acordo com o esquema de mapeamento definido. Isso decorre do fato de buscarem o desempenho como um dos seus pontos chaves. E para tal, muitas vezes um mapeamento automatizado não garante o mesmo (dadas as particulares pertinentes a cada sistema). Dentre as ferramentas analisadas, citam-se: Hibernate É uma ferramenta de persistência para Java. Ela utiliza um arquivo XML para definir o mapeamento e pode gerar as classes e tabelas a partir do mesmo. Usa reflexão para recuperar os atributos a persistir, logo não necessita de programação adicional nas classes persistidas. Castor Apresenta recursos semelhantes ao Hibernate (sendo também para Java), porém adiciona a capacidade de persistir as informações em documentos XML ao invés de um banco relacional. InfoObjects Semelhante as anteriores, porém suporta C++ além de Java. Torque - apresenta recursos equivalentes ao Hibernate.\n36 CocoBase, intellibo, Visual BSF são outras ferramentas existentes equivalentes as anteriores, porém proprietárias. 24\n37 Capítulo 5 Características e tecnologias utilizadas na ferramenta desenvolvida 5.1 Visão geral A ferramenta desenvolvida neste trabalho pode ser dividida em duas grandes partes: uma visual, cujo objetivo é permitir a modelagem de sistemas simples segundo o conceito de Modelos de Objetos 1, usando a notação UML. Esta será nomeada como "Modelador de Sistemas". A outra parte, denominada "Gerador de Sistemas" encarrega-se de, dada uma modelagem, gerar: O código básico da mesma (classes, getters e setters). Um esquema de banco de dados relacional sobre o qual os dados envolvidos podem ser persistidos - incluindo visões para simplificar a visualização dos dados. Uma camada de persistência (mapeando entre os paradigmas OO e relacional) para a persistência dos dados. Interfaces visuais para inclusão/remoção e alteração de entidades do sistema - utilizando a camada de persistência gerada pela própria ferramenta. 1 Seção 5.3\n38 Linguagem adotada Como linguagem sobre a qual a ferramenta foi desenvolvida escolheuse o Smalltalk. Dentre as várias implementações (Dolphin Smalltalk, VisualWorks, etc.) escolheu-se o Squeak Sobre o Smalltalk Smalltalk foi projetado para ser fácil de aprender e usar. É uma linguagem expressiva que usa um subconjunto simples de linguagens, substantivos e verbos humanos. Algo que todos os humanos podem relacionar-se com. Isto facilita uma clara expressão de soluções que mapeiam-se muito bem com o pensamento humano. Esta é uma das razões que leva programas em Smalltalk a serem de um terço a um meio do tamanho de programa escritos em outras linguagens populares. Programas em Smalltalk tipicamente podem fazer duas a três vezes mais trabalho com a mesma quantidade de código. Em alguns casos programas em Smalltalk podem fazer muito mais com muito menos código. ( [Lount 2004]) a ser utilizada foram: As características que levaram a escolha do Smalltalk como linguagem Em Smalltalk, Tudo é um objeto. Inteiros, strings, booleans, definições de classes e blocos de código são representado por objetos. Logo mantém-se uma maneira uniforme de interagir com os elementos da linguagem (através de mensagens enviadas para os objetos). Um objeto pode receber qualquer tipo de mensagem, sendo só verificado se ele pode recebê-la durante a execução do programa - isto evita typecasts 3 no código, como ocorre em outras linguagens Conversão de um objeto em outra classe\n39 27 Smalltalk é um ambiente integrado de desenvolvimento e execução - graças a isto pode-se programar e testar o código de forma simples (aos poucos, conforme ele é construído). Toda a linguagem está disponível no ambiente - para qualquer classe é possível olhar seu código e analisar seu funcionamento, além de também poder alterá-la se houver interesse Sobre o Squeak Squeak é uma implementação aberta e portável do Smalltalk-80. Sua máquina virtual é escrita inteiramente em Smalltalk, tornando fácil depurála, analisá-la e modificá-la. Para obter uma performance prática, um tradutor produz um programa C equivalente cuja performance é comparável a outras implementações comerciais [About Squeak 2004] A escolha do Squeak deveu-se a: Está disponível para várias plataformas (Windows, BeOS, vários Unix - incluindo Linux, etc.); É uma implementação de código aberto e gratuita para uso tanto acadêmico quanto profissional; Uma grande quantidade de componentes (pacotes no linguajar do Squeak) disponíveis, alguns deles utilizados neste projeto Notação utilizada para modelagem de sistemas Como a ferramenta desenvolvida dispõe de uma parte relacionada a modelagem de sistemas (utilizando o Modelo de Objetos), adotou-se a UML como linguagem de notação para a modelagem. 4 Os pacotes disponíveis para o Squeak podem ser encontados no SqueakMAP, localizado em\n40 28 A UML pode ser definida como Uma linguagem para especificação, visualização, construção e documentação de artefatos de sistemas de software, assim como modelagem de negócios e outros tipos de sistemas. As primeiras noções do que mais tarde tornariam-se a UML foram dadas em 1994 por Grady Booch e Jim Rumbaugh. Eles combinaram as notações de diagrama de seus métodos de desenvolvimento de software: OMT (Object Modeling Technique) e Booch. [Rumbaugh 1991] Em 1997 a UML (após várias contribuições por outras pessoas) foi adotada pelo OMG 5 como um padrão para modelagem de sistemas OO. Não vai entrar-se aqui em detalhes sobre a UML e sua notação. Apenas os aspectos importantes relativos à ferramenta desenvolvida serão citados à medida que esta for descrita. Para informações e a especificação da UML, pode-se consultar a documentação do OMG Recursos da UML aceitos A especificação UML propõe uma série de recursos para criação de modelos de objetos, porém muitos não são pertinentes à modelagens simples (foco deste trabalho). Com este fato em mente, limitam-se os componentes da notação aceitos na modelagem aos seguintes: classes, heranças, atributos e métodos de objetos, relações de associação (com graus um para um, um para vários e vários para vários). Quanto as heranças, suporta-se apenas heranças simples. Isto deve-se a dois motivos principais: a linguagem adotada não possui suporte ao conceito de heranças múltiplas; e este é considerado complexo e raramente utilizado dentro do modelo OO, logo não seria adequado ao usuário alvo da ferramenta. No caso das relações, não trata-se a possibilidade de uma relação possuir um ou mais atributos associados a mesma. Na modelagem de sistemas, quando isto ocorre, ao passar-se para a fase de implementação em geral faz-se os atributos passarem a ser membros de um dos elementos da associação, ou cria-se uma terceira entidade res- 5 O Object Management Group (OMG) é um consórcio aberto, sem fins lucrativos, que produz e mantém especificações para a indústria de informática para interoperabilidade entre aplicações empresariais -\n41 ponsável por manter os dados. E isto já pode ser feito durante a própria modelagem do sistema Tipos de dados Os atributos das classes deverão ser tipados 6 para que possam ser persistidos no banco de dados. Porém os tipos serão limitados a um conjunto específico, escolhido para representar mais fielmente os tipos de dados presentes no mundo real. Estes tipos são: Inteiro - um número pertence ao conjunto dos números inteiros; Texto - uma seqüência qualquer de letras, números e símbolos, representada no banco de dados por algum tipo que o mesmo possua que não forneça limitações de tamanho; Racional - um número que podem ser representado na forma de fração - armazenados como o tipo de dados de maior capacidade de armazenamento para ponto flutuante existente no banco de dados; Real - números que não podem ser representados na forma de fração - armazenados como o tipo de dados de maior capacidade de armazenamento para ponto flutuante existente no banco de dados; Data, Hora - momento no tempo; ValorMonetario - representa valores monetários (decimais de duas casas); Imagem - armazena imagens (fotos, desenhos, etc.) - mapeado como tipo BLOB 7 no banco de dados; SimNao - representa um valor que pode ser verdadeiro (Sim) ou falso (Não) - o tipo booleano; 6 Ter um tipo de dados definido 7 Binary Large Object\n42 Qualquer - pode conter dados arbitrários (arquivos binários, etc.) - mapeados como tipo BLOB no banco de dados Mapeamento do modelo OO para o relacional O processo de mapeamento é feito de forma automática, a partir do diagrama de classes. O sistema foi projetado para que qualquer uma das quatro técnicas discutidas anteriormente possa ser utilizada, e daquelas discutidas três implementadas: uma tabela por classe concreta, uma tabela por hierarquia de classes e uma tabela por classe. A adotada no projeto é a de uma tabela por hierarquia de classes. 5.6 GLORP Para este projeto adotou-se, para a persistência dos dados, uma ferramenta já existente, para poder concentrar o esforço em outros aspectos da ferramenta (como o mapeamento automático para o modelo relacional e a ferramenta visual para modelagem). Duas alternativas foram encontradas para a persistência de objetos em bancos de dados relacionais no Smalltalk: Tantalus e GLORP. Inicialmente a idéia foi utilizar o Tantalus, pois era a única ferramenta conhecida e apresentava características que interessavam ao projeto (como não necessitar de código adicional nas classes para que fossem persistidas). Porém o desenvolvedor do Tantalus decidiu parar de desenvolvê-lo, deixando-o inacabado (sem suporte por exemplo a relacionamentos muitos para muitos). Cogitou-se inicialmente tomar o mesmo e desenvolver os recursos que faltavam. Porém, após uma nova pesquisa, tomou-se conhecimento do GLORP (Generic Lightweight Object-Relational Persistence), outra ferramenta para persistência, que veio a ser adotada. O GLORP pode ser definido como uma camada de mapeamento objetorelacional para Smalltalk. Possui versões disponíveis para várias implementações do Smalltalk (VisualWorks, VisualAge, Dolphin Smalltalk, Squeak). É um projeto liderado\n43 31 por Alan Knight e tem por objetivo prover um framework 8 simples, porém poderoso, para ler e gravar objetos de bancos de dados relacionais 9. O GLORP apresenta diversas características que interessam ao projeto, como: Baseado em transações Esta característica foi utilizada para criar o conceito de sessão na ferramenta desenvolvida. Gravações transparentes Para o usuário basta registrar o objeto junto ao sistema de persistência para que o mesmo seja persistido. Uma vez registrado o objeto em uma sessão, não há necessidade de executar comandos específicos para gravar as alterações feitas nos dados. Cache interno dos objetos Garante que se um objeto for recuperado duas vezes, a instância em memória nos dois casos será a mesma - logo não há problemas de consistência de dados. Utilização de proxies - Os objetos relacionados a um objeto recuperado do banco de dados serão carregados à medida que for necessário. Para tal ele utiliza o conceito de proxy, onde para os atributos não recuperados ainda ele instancia uma classe que ao ser acessada converte-se no atributo correto. Gerência do mapeamento centralizada em uma única classe, escondendo do usuário a complexidade de funcionamento do framework de persistência. Suporte a herança, polimorfismo e associações. Como pontos negativos sobre o GLORP temos a persistência apenas sobre o PostgreSQL e Oracle; ser baseado em código - não apresenta uma forma de esta- 8 Um esqueleto de implementação de uma aplicação ou de um subsistema de aplicação, em um domínio de problema particular. É composto de classes abstratas e concretas e provê um modelo de interação ou colaboração entre as instâncias de classes definidas pelo framework. Um framework é utilizado através de configuração ou conexão de classes concretas e derivação de novas classes concretas a partir das classes abstratas do framework - A. Wirfs-Brock [WIA 91] 9 Maiores informações sobre o GLORP estão disponíveis em\n44 belecer o mapeamento que não seja através de código. Existe o interesse em desenvolver um suporte ao mapeamento dinâmico 10, porém não há nada concreto até o momento Persistência No GLORP, toda configuração da persistência fica definida por uma instância de um DescriptorSystem. Esta classe deve ser especializada para cada esquema de persistência que se deseja estabelecer. Dentre os aspectos que precisam ser definidos, dois destacam-se: a definição das tabelas onde serão persistidos os dados e as classes que serão persistidas. Para cada tabela sobre a qual os dados serão persistidos cria-se um método nomeado como tablefor<nomedatabela>, onde <nomedatabela> corresponde ao nome da tabela no banco de dados. Este método recebe como parâmetro um descritor ao qual devem ser adicionados os campos, chaves primárias e chaves entrangeiras da tabela. Um exemplo (este código foi gerado pela própria ferramenta desenvolvida): tableforconsultas: umdescritor intid tpctrlint medico paciente data intid (umdescritor createfieldnamed: intid type: platform serial) beprimarykey. tpctrlint _ umdescritor createfieldnamed: tpctrlint type: platform string. medico _ umdescritor createfieldnamed: medico type: platform integer. paciente _ umdescritor 10 Que poderia ser modificado durante a execução do sistema, sem alteração do código do mesmo, apenas de um modelo de mapeamento - como um documento XML, por exemplo\n45 33 createfieldnamed: paciente type: platform integer. data _ umdescritor createfieldnamed: data type: platform date. umdescritor addforeignkeyfrom: medico to: ((self tablenamed: PESSOA ) fieldnamed: intid ). umdescritor addforeignkeyfrom: paciente to: ((self tablenamed: PESSOA ) fieldnamed: intid ) Da mesma forma, para cada classe a ser persistida, deve-se definir um método da forma descriptorfor<nomedaclasse>, que recebe um descritor ao qual adicionam-se informações sobre a classe a persistir. Exemplo (também gerado pela ferramenta): descriptorforconsultas: umdescritor tabela umdescritor table: (self tablenamed: CONSULTAS ). umdescritor addmapping: (DirectMapping from: #data to: ((self tablenamed: Consultas ) fieldnamed: data )). umdescritor addmapping: (DirectMapping from: #intid\n46 34 to: ((self tablenamed: Consultas ) fieldnamed: intid )). (self typeresolverfor: Consultas) register: umdescritor keyedby: Consultas field: ((self tablenamed: CONSULTAS ) fieldnamed: tpctrlint ). umdescritor addmapping: (OneToOneMapping new attributename: #medico; referenceclass: Medico; mappingcriteria: (Join from: ((self tablenamed: CONSULTAS ) fieldnamed: medico ) to: ((self tablenamed: PESSOA ) fieldnamed: intid ))). umdescritor addmapping: (OneToOneMapping new attributename: #paciente; referenceclass: Paciente; mappingcriteria: (Join from: ((self tablenamed: CONSULTAS ) fieldnamed: paciente ) to: ((self tablenamed: PESSOA ) fieldnamed: intid ))) seguinte trecho: O código sua maior parte é auto-explicativo, porém convém comentar o (self typeresolverfor: Consultas) register: umdescritor keyedby: Consultas field: ((self tablenamed: CONSULTAS )\n47 35 fieldnamed: tpctrlint ) O código apresentado refere-se a uma persistência baseada no conceito de uma tabela por hierarquia de classes. Este trecho destacado define qual atributo e valor do mesmo identificam os elementos desta classe na tabela que contém a hierarquia da qual ela faz parte (para poder realizar a filtragem dos dados ao recuperá-los do banco de dados) Manipulando dados Para manipular dados com o GLORP, é preciso estabelecer uma Unit Of Work, que nada mais é que uma sessão onde existe uma conexão ao banco de dados e um cache dos objetos sendo manipulados na sessão. Neste cache ficam guardados tanto os objetos recuperados quanto os objetos novos que serão gravados no banco de dados quando a sessão terminar. Para estabelecer a Unit of Work, basta instanciar uma GlorpSession para a qual passa-se uma instância do descritor de persistência (sub-classe de DescriptorSystem) e uma conexão ao banco de dados (DatabaseAccessor). Feito isto, com os métodos beginunitofwork e endunitofwork controla-se o início e fim de uma sessão no GLORP. Adicionalmente tem-se o método commitunitofworkandcontinue, que permite persistir no banco de dados as alterações feitas durante a sessão e mantê-la aberta para uso posterior. Para inserir ou excluir objetos estão disponíveis os métodos: registernew: registra um novo objeto (que será inserido no banco de dados posteriormente); delete: remove um objeto da sessão e posteriormente do banco de dados. Para alterar objetos, o GLORP assume que os mesmos devem ser recuperados e então alterados. Como ao ser recuperado ele já é registrado na sessão, ao terminá-la ele será automaticamente atualizado no banco de dados. Para recuperar objetos o GLORP disponibiliza quatro métodos básicos:\n48 36 readoneof: umaclasse recupera um objeto (qualquer) de uma determinada classe; readmanyof: umaclasse recupera todos os objetos de uma dada classe e subclasses; readoneof: umaclasse where: umacondicao recupera um objeto de uma classe / subclasses para o qual a condição informada é valida; readmanyof: umaclasse where: umacondicao semelhante ao anterior porém retorna uma coleção de objetos. umaclasse é a classe do objeto que deseja-se recuperar. umacondicao é um bloco de código Smalltalk onde define-se uma condição que deve ser respeitada na hora de recuperar os objetos. Exemplo: sessao readoneof: Paciente where: [:paciente paciente nome = João ]. Ao receber tal código, o GLORP converte o mesmo em uma cláusula SQL correspondente a condição estabelecida (exemplo: WHERE NOME= JOAO ). Isto também é válido para relacionamentos, portanto: sessao readmanyof: Consulta where: [:consulta consulta paciente nome = João ]. também é uma condição de pesquisa válida. Pode-se também utilizar outros objetos dentro da condição de pesquisa, como: pacienterecuperado _ sessao readoneof: Paciente where: [:paciente paciente nome = João ]. sessao readmanyof: Consulta where: [:consulta consulta paciente = pacienterecuperado]. É importante destacar que o GLORP suporta polimorfismo na recuperação das entidades. Logo, ao recuperar objetos de uma classe também virão objetos de subclasses da mesma.\n49 Maiores informações Caso deseje-se mais informações a respeito do GLORP, pode-se acessar o site Entre outros documentos, estão disponíveis tutoriais sobre o mesmo. 5.7 XMI No primeiro momento do projeto (quando ainda não havia a ferramenta de modelagem visual), foi necessário ter alguma forma de importar modelagens feitas em outras ferramentas para utilizar como testes para a ferramenta de geração. Após uma pesquisa sobre qual a melhor forma de fazer isso, decidiu-se pela utilização do XMI para fazer a importação das modelagens, já que a maioria das ferramentas de modelagem existentes implementa alguma forma de exportação para o mesmo, além de ser um padrão estabelecido pelo OMG. O XMI 11 é um padrão da OMG para troca simplificada de informações referentes a metamodelos, utilizando o formato XML. Através do XMI especificam-se diagramas de qualquer gênero (como diagramas de classe no caso da UML). O XMI não é uma especificação de um formato de XML para metamodelos, mas sim um algoritimo de geração de especificações XML para metamodelos. Dessa forma ele suporta vários tipos de metamodelos (como os da UML). Porém ao mesmo tempo que isto leva a um ganho considerável de flexibilidade e recursos, provoca também uma tendência a incompatibilidade entre os documentos XMI gerados entre algumas aplicações (indo contra o propósito original de permitir a troca simples das informações entre as aplicações). Apesar disto, estas diferenças em geral podem ser contornadas pelos interpretadores dos documentos. 11 XML Metadata Interchange\n50 Capítulo 6 O Gerador de Sistemas 6.1 Visão geral O Gerador de Sistemas é a parte da ferramenta responsável por tomar uma representação de um sistema segundo o conceito de "Modelo de Objetos" e a partir deste gerar: a estrutura básica de código (no ambiente Smalltalk) das classes do sistema (incluindo as relações entre as mesmas); uma camada de persistência compatível com a estrutura de classes geradas; um esquema de banco de dados relacional onde as classes possam ser persistidas; e por último interfaces que permitem a visualização e edição dos dados persistidos. Ele é composto por vários componentes, que são: Documento XMI, Diagrama de Classes, Representação do Modelo Relacional, Gerador de Esquema Relacional, Gerados de comandos DDL 1, Gerador de Classes e o Gerador de Interfaces. 6.2 Documento XMI Como em um momento inicial do projeto necessitou-se importar documentos XMI, desenvolveu-se um componente capaz de importá-los. Como um documento XMI tem a mesma estrutura sintática de um documento XML, pôde-se utilizar 1 Data Definition Language - Linguagem utilizada para definir esquemas de bancos de dados\n51 39 um parser já existente no Squeak para ler o arquivo XMI. Porém, desenvolveu-se toda uma estrutura para a representação em memória deste documento, de forma a poder obter informações sobre o mesmo (como classes, atributos, métodos, heranças e relacionamentos). Esta representação não buscou satisfazer todas as características que um documento XMI pode apresentar mas sim aquelas necessárias ao projeto. A hierarquia de classes que representa um documento XMI está demonstrada na figura 6.1. Figura 6.1: O diagrama de classes da representação em memória de um documento XMI A utilização desta estrutura resume-se em criar um XMIDocumento e através de sua interface adicionar os elementos que o compõe (como classes, heranças, etc.). Como o formato XMI acaba sendo específico da aplicação que o gera, desenvolveu-se parsers para o XMI gerado pelo Borland Together 6 e para o ArgoUML / Poseidon. Este último porém apresentou problemas na importação de determinadas modelagens devido a erros na geração do documento XMI pelo ArgoUML (determinados elementos não eram gerados) e acabou sendo descartado, ficando apenas o parser para documento exportados no formato XMI 1.1 for UML 1.4 a partir do Together. O parser para XMI desenvolvido funciona da seguinte forma:\n52 1. Dado um stream 2 contendo um documento XMI, é estabelecido um XMLDOMParser, mantido internamente para acessar as informações do documento XMI O cabeçalho do documento é analisado e as informações contidas no mesmo são armazenadas em um XMICabecalho, anexo ao XMIDocumento sendo gerado. 3. As classes e tipos de dados são então recuperados (sem os atributos). Para cada um é gerado um XMIClasse 3 e são armazenados também os identificadores internos 4 presentes no documento XMI. 4. Os atributos das classes e tipos de dados são então analisados e inseridos nos respectivos XMIClasse. Através do identificador interno determina-se que XMIClasse corresponde ao tipo de dados definido para o atributo. 5. De forma semelhante aos atributos, os métodos das classes são recuperados e adicionados às XMIClasse correspondentes. 6. Após ter as classes recuperadas, as heranças são analisadas e adicionadas (XMIHeranca) ao XMIDocumento. 7. Por último as associações são recuperadas. 6.3 Diagrama de classes Como todo o funcionamento da ferramenta baseia-se no diagrama de classes do sistema, desenvolveu-se uma estrutura (figura 6.2) para representar o mesmo em memória. Para representá-lo adotou-se o uso de um grafo. Para tal, utilizou-se uma implementação disponível no sistema Mundo dos Atores 5. Nesta implementação 2 Fluxo de dados - no caso, um fluxo de caracteres 3 Não diferencia-se aqui tipos de dados e classes pois para o projeto esta divisão não se fazia necessária 4 Em um documento XMI, os tipos de dados e classes definidas apresentam um identificador interno - um literal string - que o identifica unicamente dentro do documento 5\n53 41 de grafo qualquer objeto pode ser adicionado como um vértice e as arestas podem ser rotuladas por um objeto qualquer. No grafo cada vértice constitui uma classe e as arestas são os relacionamentos entre as classes (tanto associações quanto heranças). Para definir qual tipo de relação uma dada aresta constitui estabelece-se como rótulo da mesma um objeto que identifica seu tipo e no caso de associações também contém atributos como cardinalidade e papéis das classes envolvidas("roles"). Desenvolveu-se, utilizando esta representação, diversos métodos para facilitar a manipulação da hierarquia de classes, como recuperar as sub e superclasses de uma classe, métodos para estabelecer e recuperar os relacionamentos, para copiar atributos de uma classe a todas as suas subclasses, etc. Esta representação também possui a capacidade de analisar um objeto da classe XMIDocumento e incorporar os elementos contidos no mesmo, gerando automaticamente a hierarquia de classes contida no documento. Assim a instrução: (OORDBMHierarquiaDeClassesComParserXMI new xmi: umdocumentoxmi) documento XMI informado. já retorna um objeto OORDBMHierarquiaDeClasses correspondente ao 6.4 Representação do modelo relacional Desenvolveu-se uma representação (figura 6.3) simples de um esquema relacional baseada em três classes: uma representando tabelas, outra representando visões e uma última representando colunas. As duas primeiras contêm um conjunto de colunas e, no caso das tabelas, um subconjunto que representa sua chave primária. Uma coluna pode possuir, além do nome e tipo (tipo este um dos tipos básicos definidos anteriormente - Inteiro, Texto, etc.), uma chave estrangeira, que é o objeto representante do campo da tabela com a qual a chave relaciona-se. As visões são estabelecidas através da inclusão nas mesmas de campos\n54 Figura 6.2: As classes responsáveis por representar uma hierarquia de classes segundo o paradigma OO 42\n55 43 Figura 6.3: As classes que armazenam as informações sobre um modelo relacional definidos em outras tabelas ou visões, além de uma cláusula 6 SQL que determina os critérios para o estabelecimento da visão. A abordagem mais adequada aqui seria utilizar uma linguagem ou mesmo uma representação em forma de objeto desta clásula, mas para o projeto desenvolvido optou-se por definir diretamente a cláusula SQL, pois satisfazia as necessidades do mesmo. 6.5 Gerador de Esquema Relacional Com base na pesquisa feita sobre mapeamento entre os paradigmas OO e relacional, desenvolveu-se um componente (figura 6.4) responsável por, dada uma representação de um diagrama de classes (OORDBMHierarquiaDeClasses), gerar uma representação deste no modelo relacional. O componente foi modelado de forma a poder ser utilizado para qualquer uma das quatro modalidades de persistência, das quais foram implementadas três formas: uma tabela por classe concreta, uma tabela por classe (incluindo abstratas) e uma tabela por hierarquia de classes. O funcionamento do Gerador de Esquema Relacional pode ser descrito através da seguinte seqüência básica de passos: 1. Para cada classe superior da hierarquia (classes que não possuem superclasses), é gerada uma tabela de mesmo nome, contendo apenas uma coluna nomeada intid. Esta, de tipo inteiro, é utilizada como chave primária da tabela. Em seguida, para cada atributo destas classes, é verificado se o mesmo é um tipo simples (utilizando 6 Do tipo WHERE\n56 44 Figura 6.4: Os geradores de esquemas relacionais a classe OORDBMTiposBasicos, que contém uma lista interna dos tipos básicos aceitos). Se for, uma coluna é adicionada a definição da tabela, com o nome e tipo iguais ao do atributo 7 2. Um processo semelhante é desenvolvido então para as demais classes, variando conforme o tipo de abordagem de mapeamento OO-relacional adotado. No caso de uma tabela por classe concreta, o processo para as classes superiores é realizado de forma idêntica para as demais classes. Na abordagem de uma tabela por classe, além dos passos realizados para as classes superiores também é definida uma chave estrangeira entre o campo intid da tabela com o campo intid da tabela que representa sua classe superior. Por último, para a abordagem de uma tabela por hierarquia de classes, os atributos das classes descendentes são adicionados à tabela que representa a classe mais alta na hierarquia. 3. Mapeadas as classes e atributos, os relacionamentos são analisados. Para cada relacionamento são definidos os campos (e tabela, se for o caso) necessários para o mapeamento, conforme descrito no capítulo 4, além das devidas chaves estrangeiras. 4. Como último item, podem ser geradas visões sobre o esquema relacional elaborado (a fim de facilitar a visualização dos dados). No sistema desenvolvido este 7 A conversão para um tipo existente no banco de dados - como de Imagem para BLOB - é feita pelo Gerador de comandos DDL, descrito na seção seguinte.\n57 45 item ocorre apenas no caso do mapeamento de uma tabela por hierarquia, onde são criadas visões responsáveis por mostrar apenas os objetos e atributos de uma determinada classe. Este componente não tem a capacidade de gerar os comandos DDL para criar o banco de dados. Isto é função de outro componente, o Gerador de comandos DDL, descrito a seguir. 6.6 Gerador de comandos DDL Este componente (representado pela classe OORDBMSQL e apresentado na figura 6.5) gera, dado um conjunto de OORDBMTabela, os comandos de DDL do SQL equivalentes a representação de tabelas e campos gerada pelo Gerador de Esquema Relacional. Da mesma forma ele também pode gerar os comandos equivalentes para OORDBMVisoes. Figura 6.5: O componente de geração de instruções DDL Ele pode gerar os comandos DDL de duas formas: uma onde toda a tabela é criada de uma única vez e outra onde cada campo é criado isoladamente. Dessa forma é possível atualizar (inserir novos campos) a estrutura de uma tabela. Para evitar que na hora de gerar as tabelas ocorram problemas devido às chaves estrangeiras (criar uma sem existir ainda a tabela referenciada), ele gera de forma independente os comandos para as tabelas e relacionamentos.\n58 46 Seu funcionamento interno pode ser descrito da seguinte forma: dada a representação de uma tabela ou visão, ele percorre a mesma montando o(s) comando(s) em SQL/DDL para gerá-la. Através de um dicionário interno determina as definições em SQL/DDL correspondentes aos tipos dos atributos ( Inteiro para INTEGER, etc.). De forma semelhante, os comandos para estabelecimento das chaves estrangeiras também são gerados. 6.7 Gerador de classes Representado por apenas uma única classe (OORDBMGeradorDeClasses), ele toma a representação em memória do diagrama de classes (OORDBMDiagrama- DeClasses) e realiza todo o processo de geração das classes dentro do ambiente Smalltalk, utilizando-se de reflexão para analisar se as classes já existentes e em caso positivo, quais atributos/métodos já dispõe. Ele realiza este processo em quatro etapas: 1. Inicialmente ele verifica para cada classe se a mesma já existe ou não no sistema. Em caso negativo, ela é criada, sem atributos ou métodos. Em caso positivo, ele apenas verifica se a categoria e superclasse sob a qual ela está é a correta. Caso não seja, faz as devidas alterações. 2. Em seguida analisam-se os atributos de cada classe e geram-se as varíaveis de instância correspondentes aos mesmos (preservando variáveis definidas anteriormente, caso a classe já exista no ambiente). Feito isso, são criados os métodos para definir e recuperar estes atributos (getters/setters). Na geração destes, incorporam-se métodos de validação de tipo aos mesmos, de forma que se for passado um Texto para um atributo Inteiro, um erro será gerado. Os códigos destas validações ficam contidas na classe OORDBMTiposBasicos, em um dicionário cujas chaves são os tipos ( Inteiro, etc.). 3. As associações entre as classe são analisadas e estabelecem-se os atributos correspondentes em cada classe. A existência ou não de um papel associado ao terminal\n59 47 da relação determina se um atributo deve ou não ser criado (definindo dessa forma a visibilidade do relacionamento). No caso de terminais da associação com cardinalidade unitária, estabelece-se um getter/setter no formato de atributo simples, incluindo código para validar o tipo do objeto. Já em terminais com cardinalidade não-unitária, estabelece-se uma coleção como atributo para conter os objetos associados. Esta coleção pode ser da classe TypedOrderedCollection ou da classe TypedLimitedOrderedCollection, ambas desenvolvidas para o projeto. A primeira restringe o tipo de objeto que pode estar contido na coleção e a segunda restringe além do tipo a quantidade máxima de elementos que podem estar contidos. 4. Por último o gerador analisa a lista de métodos de cada classe. Caso os mesmos ainda não existam nas classes, ele os cria (só a definição, sem um corpo propriamente dito). 6.8 Gerador da camada de persistência O gerador da camada de persistência (figura 6.6) é responsável por analisar a hieraquia de classes e gerar todo o suporte à persistência da mesma baseado no GLORP. Da mesma forma que o Gerador de Esquema Relacional, existem três versões deste componente, correspondendo aos três tipos de mapeamento OO-relacional fornecidos pelo Gerador de Esquema Relacional. O suporte a persistência gerado por este componente consiste em gerar a classe descendente de DescriptorSytem 8 que será responsável por informar ao GLORP como dar-se-á o mapeamento. O gerador utiliza como fonte de informações uma instância de OORDBM- HierarquiaDeClasses e uma coleção de OORDBMTabela e realiza o seguinte processo: 1. Ele gera a base da classe de persistência, que consiste nos métodos constructall- Classes e alltablenames, que definem os nomes das classes e tabelas que estarão 8 Veja a seção 5.6.1\n60 48 Figura 6.6: O componente responsável pela geração do suporte à persistência envolvidas na persistência. 2. Em seguida, para cada OORDBMTabela ele gera um descritor para mesma, considerando os relacionamentos existentes. 3. Da mesma forma, para cada classe ele gera o descritor correspondente. Este componente também é responsável por gerar uma classe que "camufla"o GLORP através de uma interface simples. Esta classe trabalha com dois conceitos chaves: Sessão - tudo o que for relacionado à persistência deve estar contido em uma sessão, que deve ser iniciada e finalizada pelo usuário. Registro - um objeto só torna-se persistente a partir do momento que é registrado dentro de uma sessão. Ela contém os seguintes métodos: - recuperarentidadesdotipo: umaclasse segundo: umacondicao - recuperarentidadedotipo: umaclasse segundo: umacondicao\n61 49 - recuperarentidade: umaclasse segundo: umacondicao - registrar: umobjeto - excluir: umobjeto - iniciarsessao - gravarecontinuarsessao - terminarsessao Estes são mapeados para métodos de nome semelhante existentes no GlorpSession (descritos na seção 5.6.2). O diferencial fica no método iniciarsessao, mostrado a seguir: iniciarsessao self conectarbancodedados. descritor _ DescritorPersistencia new. sessao _ GlorpSession new. sessao system: descritor. sessao accessor: accessor. sessao beginunitofwork Além do processo de iniciar uma nova Unit of Work no Glorp, ele encarrega-se de instanciar a conexão e o descritor de persistência, simplificando a persistência dos dados a uma seqüência de comandos similar a: incluirconsultas paciente sessao medico consulta sessao _ GerenciadorPesistencia new. sessao iniciarsessao. paciente _ sessao recuperarentidadedotipo: Paciente\n62 50 segundo: [:pac pac nome = Paciente1 ]. medico _ sessao recuperarentidadedotipo: Medico segundo: [:pac pac nome = Rodrigo ]. consulta _ Consultas new paciente: paciente; medico: medico; data: Date today. sessao registrar: consulta. sessao terminarsessao 6.9 Gerador de Interfaces A função deste componente do Gerador de Sistemas é, a partir do diagrama de classes, gerar interfaces gráficas através das quais os dados contidos nas classes possam ser editados, assim como instâncias das mesmas incluídas ou removidas do sistema. A geração destas interfaces tem por objetivo facilitar a inclusão e edição de dados pelos usuários em um primeiro momento, pois esconde do mesmo os detalhes relacionados a persistência dos dados. Dessa forma, têm-se um contato inicial com o conceito de persistência (dois usuários, por exemplo, podem compartilhar o mesmo banco de dados e ver as alterações realizadas um do outro). Além disto, ela funciona como uma ferramenta que pode ser incorporada pelo próprio usuário no desenvolvimento do sistema, pois disponibiliza uma forma de visualização e edição dos dados. Para cada classe é gerada uma tela semelhante à figura 6.7. Ela disponibiliza as ações básicas comuns a sistemas que operam com dados persistidos (opções para navegação como Próximo e Anterior, inclusão e exclusão de registros, etc.). Para gerar esta interface, o componente toma como base um diagrama de hierarquia de classes (OORDBMHierarquiaDeClasses). Em um primeiro momento ele pede ao mesmo que expanda os atributos das classes superiores para as inferiores. Esta operação significa que, para cada atributo que existe em uma dada classe, o mesmo vai ser replicado em todas as suas subclasses.\n63 51 Figura 6.7: Um exemplo de interface gerada pelo sistema Figura 6.8: O componente de geração de interfaces Dessa forma, cada classe passa a conter todos os atributos de suas classes superiores além dos atributos definidos nela própria. Esta operação é utilizada para que, quando for gerada a tela, estejam presentes na mesma todos os atributos da classe correspondente, ao invés de apenas os atributos definidos na classe. O sistema então executa o seguinte processo para cada classe da hierarquia: 1. Gera a estrutura básica (definição) da classe que representa a interface gerada - aqui as subclasses de OORDBMGeradorDeInterfaceDeEdicao definem qual será a superclasse. 2. Cria métodos para navegação, edição, gravação e recuperação dos dados entre a interface e o objeto correspondente aos dados visualizados na mesma, considerando a lista de atributos da classe. 3. Estabelece os métodos para iniciar e terminar sessões de persistência, utilizando o Gerenciador de Persistência gerado anteriormente.\n64 52 4. Elabora a interface gráfica, considerando a lista de atributos para determinar como gerar os componentes para edição dos dados na mesma. Para gerar a interface, ele identifica a quantidade de atributos e tamanho que cada um necessita, determinando assim o tamanho da tela criada. Feito isso, o código correspondente aos componentes que exibem os dados de um determinado atributo é gerado, considerando uma posição inicial calculada de acordo com sua posição na lista de atributos e o tipo de atributo. O componente foi estruturado (conforme vê-se na figura 6.8) de forma a permitir a utilização de qualquer conjunto de componentes visuais. A classe OORDBM- GeradorDeInterfaceDeEdicao contém toda a lógica para a geração das interfaces, porém abstrai os detalhes referentes a que classes de componentes visuais são utilizados, ficando isso a cargo das subclasses - no caso OORDBMGeradorDeInterfaceDeEdicaoPrefab. Essencialmente as subclasses ficam responsáveis por definir o código que será gerado, de acordo com parâmetros fornecidos às mesmas pelos métodos da classe OORDBMGeradorDeInterfaceDeEdicao. Convém salientar que, como as interfaces geradas são com componentes do próprio Smalltalk, ficam disponíveis para qualquer plataforma na qual a máquina virtual do Squeak é capaz de executar. É preciso apenas que na plataforma desejada, a máquina virtual para a mesma possua suporte a um ambiente gráfico Gerador de projetos Este é o componente principal do Gerador de Sistemas. É ele que coordena todos os outros componentes, permitindo a geração de um sistema completo (considerando o que a ferramenta desenvolvida propõe-se a fazer). OORDBMProjeto é a principal classe do gerador de projetos. Ela possui três subclasses (OORDBMProjetoClassesConcretas, OORDBMProjetoHierarquiaCompleta, OORDBMProjetoTabelaUnica), conforme o modelo de mapeamento OO-relacional adotado. Estas limitam-se a definir qual tipo de classe deve ser utilizada para gerar as ta-\n65 53 belas e a camada de persistência. Em OORDBMProjeto é possível especificar os parâmetros utilizados na geração do projeto, que são: a categoria sob a qual as classes serão persistidas; o endereço do servidor de banco de dados onde será criado o banco de dados relacional; o nome do banco de dados a criar; o usuário e senha de acesso ao servidor de banco de dados. O gerador também pode ser configurado para executar apenas determinadas etapas do processo, podendo combinar os processos de gerar classes, camada de persistência e banco de dados de qualquer forma desejada (gerar apenas as classes e o banco de dados, somente a camada de persistência, etc.) Fluxograma da geração de um projeto A fim de dar uma visão mais global do funcionamento da ferramenta durante a geração de um projeto, apresenta-se na figura 6.9 uma visão completa do processo, identificando as entidades do sistema responsáveis por cada uma das etapas. Não entrou-se em detalhes sobre as etapas envolvidas em cada um dos subprocessos por estas estarem descritas detalhadamente na seções anteriores e para simplificar a visualização do fluxograma Um exemplo de geração de sistema Para exemplificar o funcionamento gerador de sistemas, escolheu-se um sistema simples e fez-se a modelagem e posterior geração do mesmo. O sistema escolhido foi uma pequena clínica, da qual criou-se um modelo de objetos seguindo os seguintes critérios: 1. Considerou-se como entidades da clínica os médicos, pacientes e as consultas. 2. Um paciente tem um nome, um cpf e um código de cadastro que é definido pela clínica para identificá-lo. 3. Cada médico tem um nome, um cpf e um crm.\n66 Figura 6.9: O fluxograma de execução do Gerador de Sistemas 54\n67 55 4. Médicos e pacientes participam de consultas. Cada consulta é composta por um médico e um paciente, possuindo um momento de tempo (data e hora) e um valor associado. 5. Cada paciente tem consciência das consultas que já fez e pode calcular quanto já gastou com as mesmas. 6. Cada médico sabe que consultas realizou e pode saber quanto já ganhou. A modelagem alcançada, com base nos critérios acima, é apresentada na figura A partir dela foi requisitada a geração do sistema (figuras 6.11 e 6.12). Como resultado obtivemos as seguintes classes e métodos 9 : Figura 6.10: O sistema exemplo modelado - uma clínica simples Já o modelo relacional gerado foi o seguinte: 9 As classes com formato fixo (sem métodos variando de acordo com a modelagem) foram omitidos da listagem\n68 56 Tabela 6.1: Classes geradas pela ferramenta e seus respectivos métodos Classe Métodos CMConsulta data, data:, hora, hora:, intid, intid:, medico, medico:, paciente, paciente:, valor, valor: CMMedico consultasfeitas, consultasfeitas:, crm, crm: CMPaciente codigodecadastro, codigodecadastro:, consultasrealizadas, consultas- Realizadas:, totalgastoemconsultas CMPessoa cpf, cpf:, nome, nome:, datanascimento, datanascimento CMDescritorPersistencia alltablenames, constructallclasses, descriptorforcmmedico:, descriptorforcmmedico:, descriptor- ForCMConsulta:, descriptorforcm- Pessoa:, tableforcmconsulta:, tableforcmpessoa:, typeresolverforcmconsulta, typeresolver- ForCMMedico, typeresolverforcm- Paciente, typeresolverforcmpessoa CMGerenciadorPesistencia CMNavegadorDeCMConsulta CMNavegadorDeCMMedico CMNavegadorDeCMPaciente CMNavegadorDeCMPessoa\n69 57 Figura 6.11: A configuração para geração do projeto exemplo Figura 6.12: A geração do sistema em andamento\n70 58 Tabela 6.2: Tabelas geradas pela ferramenta Tabela Coluna Tipo Chave Estrangeira cmconsulta intid serial tpctrlint text hora time data date paciente integer cmpessoa medico integer cmpessoa valor numeric(15,2) cmpessoa intid serial tpctrlint text nome text datanascimento date cpf text codigodecadastro integer crm integer O código gerado para o exemplo seria por demasiado extenso para ser mostrado aqui. Dado este fato, ele está disponibilizado como o Anexo 1 deste trabalho.\n71 Capítulo 7 O Modelador de Sistemas 7.1 Visão geral A ferramenta visual de modelagem de sistemas desenvolvida neste projeto visa uma interface simples e de fácil uso para a definição da estrutura de um sistema (segundo o conceito de Modelo de Objetos ). Seguindo a notação UML, a ferramenta permite definir classes e relacionamentos entre estas classes - relacionamentos que podem ser tanto de herança quanto associações de cardinalidades diversas (um para um, um para vários, etc.). O foco do desenvolvimento foi a facilidade de uso e não a completude da ferramenta em termos dos recursos disponibilizados pela UML. Caso deseje-se isto, já existem diversas ferramentas no mercado (Together e ArgoUML são exemplos). Como o usuário-alvo da ferramenta desenvolvida é leigo ou iniciante na modelagem de sistemas, não necessita de todo o potencial disponibilizado pela UML. 7.2 Interface A interface com o usuário da ferramenta é apresentada na figura 7.1. Ela é composta pelo Diagrama de classes, Barra de elementos e Barra de ações.\n72 60 Figura 7.1: A interface do modelador de sistemas Diagrama de classes É a área vazia da interface do modelador. Ali são dispostos os elementos da modelagem. Não há limitação quanto ao tamanho, sendo possível rolar o ambiente caso fique muito grande Barra de ações Nela (em destaque na figura 7.2) estão presentes várias ações que podem ser feitas com o diagrama modelado. Estas opções incluem elementos tradicionais de uma ferramenta do gênero como: gravar e recuperar modelagens feitas para arquivos em disco; exportar o diagrama como uma imagem para posterior impressão; eliminar a modelagem atual e iniciar uma nova modelagem. Porém, a que merece destaque é Gerar projeto, que funciona como ponte entre o modelador e o Gerador de Sistemas. Esta ação é descrita mais em detalhes adiante neste capítulo.\n73 61 Figura 7.2: A barra de açoes do modelador Barra de elementos Figura 7.3: A barra de elementos do modelador Apresentada na figura 7.3, está localizada na parte inferior da tela. Ela contém os elementos que podem fazer parte de uma modelagem. São eles: Classe, Associação, Generalização e Nota. Para utilizar os elementos, basta selecioná-los e arrastá-los para o diagrama. No caso de elementos que unem outros elementos (heranças e associações), basta conectá-los aos elementos que se deseja unir. Se houver necessidade, pode-se trocar os elementos unidos por uma relação apenas selecionando o terminal desejado e arrastá-lo até o novo elemento.\n74 Elementos da modelagem Classes As classes seguem uma representação gráfica tradicional (figura 7.4) para diagramas UML utilizada pela maioria das ferramentas existentes. Nesta representação, uma classe é composta essencialmente por três partes principais, que comportam: o nome da classe, seus atributos e por último seus métodos (interface). Figura 7.4: Um classe no modelador O nome da classe é definido de forma simples, bastando apenas digitálo no espaço reservado ao mesmo (por padrão uma classe é nomeada NovaClasse ). Os atributos são definidos também apenas digitando seus nomes em forma de lista no espaço destinado. Para especificar o tipo do atributo (seguindo a idéia de tipos simples explicada na seção 5.4) basta apenas adicionar : (dois pontos) ao final do nome do atributo e em seguida o tipo que o representa ( Inteiro, Texto, etc.). Excluir um atributo significa simplesmente removê-lo desta listagem. Os métodos seguem a mesma lógica que os atributos para serem definidos / removidos. Como um método entende-se a sua assinatura segundo a sintaxe do Smalltalk (ex: metodoquesomaumnumero: umnumero a: outronumero ). A edição de métodos e atributos não sofre qualquer validação durante a modelagem, dando total liberdade ao usuário para modificá-los.\n75 63 Figura 7.5: O menu da classe Uma forma adicional de definir atributos é através da opção de menu (figura 7.5) "Incluir atributo"constante no menu do elemento Classe. Nesta opção é exibida uma tela (figura 7.6) auxiliar onde estão listados todos os tipos possíveis para um atributo (esta lista é montada dinamicamente, acessando a classe OORDBMTiposBasicos e requisitando a mesma a lista dos possíveis tipos). É possível deixar várias instâncias desta tela abertas (uma para cada classe do diagrama). Figura 7.6: A tela de adição de atributos à classe\n76 64 Figura 7.7: Uma herança Heranças As heranças (figura 7.7) não apresentam nenhum destaque especial quanto a sua funcionalidade. Apenas liga-se uma classe com a qual deseja-se estabelecer uma relação de herança Anotações São elementos sem significância sintática ou semântica, que servem apenas para permitir ao usuário estabelecer anotações dentro do diagrama (para, por exemplo, saber o que precisa ser feito ainda naquele diagrama ou razão pela qual determinados relacionamentos/heranças foram estabelecidos). Um exemplo de anotação é apresentação na figura 7.8. Figura 7.8: Uma anotação\n77 Associações As associações (figura 7.9) estabelecem-se da mesma forma que as heranças, apenas ligando-se as classes integrantes da associação. Porém dois aspectos diferenciam os relacionamentos: a possibilidade de definir uma cardinalidade e um papel ( role ) para os mesmos. A definição da cardinalidade segue a sintaxe <limiteinferior> : <limitesuperior> (similar a outras ferramentas de modelagem). O limite superior pode ser * para indicar que não há limite. A cardinalidade é definida no sentido este terminal da relação aceita x elementos da classe conectada ao outro terminal da relação. Figura 7.9: Uma associação Os papéis do relacionamento definem como a entidade do terminal onde está definindo-se o papel enxerga os elementos do outro terminal (por exemplo, Carro enxergaria como rodas os elementos da outra ponta do relacionamento Carro-Roda). Estes papéis posteriormente serão mapeados como atributos simples ou de coleção, dependendo da cardinalidade. Caso não seja informado um papel, não será criado um atributo e conseqüentemente estar-se-á limitando a visibilidade da relação. Os papéis podem ser alterados tanto através do menu associado ao OORDBM- MorphAssociacao quanto diretamente no próprio elemento gráfico (bastando alterar o texto que representa a cardinalidade/papel).


Busca pelo sorriso perfeito faz mercado de odontologia estética disparar\nTucuruvi - SP--(DINO - 26 jul, 2018) -\nO mercado de odontologia estética apresentou um crescimento superior a 300% nos últimos três anos, conforme mostram dados da Sociedade Brasileira de Odontologia Estética.\nQuem vê aqueles dentes perfeitos e brancos nas fotos das redes sociais, muitas vezes não sabe que não se trata de uma pessoa que tem um cuidado especial com seus dentes.\nEsses sorrisos perfeitos são o resultado do uso da lente de contato dental, uma pequena peça feita em cerâmica ou porcelana que é aplicada diretamente sobre o dente, com uma espessura de até 0,8 milímetros de espessura.\nSegundo especialistas em odontologia, a lente de contato dental mudar a cor e o formato dos dentes, podendo alterar totalmente o sorriso de uma pessoa.\nBenefícios decorrentes do uso da lente de contato dental, como o aumento da autoestima dos pacientes, fazem com que a procura por essa técnica aumente consideravelmente ano após ano. Estimativas da Sociedade Brasileira de Odontologia Estética apontam um aumento de mais de 300% de 2014 até agora.\nCelebridades brasileiras, astros internacionais entre muitos outros, já utilizam a técnica que mostra seus sorrisos perfeitos para o mundo todo.\nAinda assim, é preciso ficar atento ao decidir aplicar a técnica. Dentistas alertam para a necessidade de se fazer um estudo da face de cada paciente para que os dentes sejam feitos de forma personalizada. Pular esta etapa pode fazer com que o paciente fique com um sorriso que não é o seu.\nA lente de contato dental não pode ser utilizada por qualquer pessoa. Os pacientes com bruxismo, próteses anteriores a colocação da lente de contato, ou problemas mais graves de alinhamento dos dentes não podem utilizar esta técnica.\nPara os adultos este método é o mais recomendado nos casos de leves manchas, fraturas pequenas, dentes espaçados ou muito pequenos ou correção de alinhamento dos dentes.\nVale lembrar que, por mais que este método pareça perfeito para você, sempre é necessário procurar profissionais qualificados para aplicar as técnicas necessárias, pois trata-se de um procedimento irreversível, e por isso o bom senso e a qualificação do profissional devem ser analisados com muito cuidado.\nEntre em contato com a clínica odontológica\nEMPRESAS ASSOCIADAS à ABRAMACO EXPõEM NOVIDADES NA SERIGRAFIA SIGN FUTURETEXTIL 2018\nTERMINAIS RODOVIáRIOS DE SãO PAULO PROMOVEM EDIçãO 2018 DA SEMANA DE TESTES PARA HEPATITE C\nCORREçãO: BGMRODOTEC AGORA SE CHAMA PRAXIO\nSHOPPING PáTIO HIGIENóPOLIS LANçA PROMOçãO COMPRE E GANHE PARA O DIA DOS PAIS\nCADENCE LANçA CAFETEIRAS E CHALEIRAS EM NOVAS CORES


A Força do Querer: Rubinho vira um demônio para detonar Bibi\nPara Carine tudo e para Bibi nada em A Força do Querer (Foto: Reprodução/Globo)\nPublicado em 08/03/2021 - 18:06 por Thais Teles\nRubinho sente tanto ódio por Bibi agora em A Força do Querer que qualquer uma estará ameaçada se falar de Carine\nSe Rubinho (Emílio Dantas) fosse o tal em A Força do Querer, com certeza, faria de Carine (Carla Diaz) sua nova musa enquanto Bibi (Juliana Paes) comeria o pão que o Diabo amassou. Mesmo sem ser o tal, o bandido agirá como um e fará justamente isso.\nQuem vai pagar por ficar do lado da amiga é justamente Alessia (Hylka Maria). Esta história começará a ser mostrada na Globo depois que Rubinho e Sabiá (Jonathan Azevedo) saírem da cadeia no dia das crianças e voltarem para o morro.\nRubinho já estará muito irritado com Bibi porque ela contou que lhe traiu com Caio (Rodrigo Lombardi). Os dois terão um novo encontro justamente na comunidade e ela para tirá-lo do seu caminho, passará bala. Por azar dela, Rubinho se salva.\nA partir daí ele será mais enfático em dar o seu dinheiro para a Carine e obrigar Bibi a pegar com a amante a pensão de seu filho.\nALESSIA COMPRARÁ BRIGA\nHaverá uma reunião entre os traficantes, Carine chegará como mulher de Rubinho para o desagrado de Alessia. A namorada de Sabiá falará na cara dos dois que eles estão errados em como estão tratando Bibi.\n“Tu tá tão preocupada com Bibi, então dá um recadinho pra ela”, Rubinho afirmará nervoso apontando a arma para Alessia. Ele dirá que é para a ex se virar, se ela quiser a pensão de Dedé (João Bravo) que trafique se for preciso.\nSabiá logo cortará as asas de Rubinho até porque está do lado da Perigosa nessa confusão toda. Só que o recado será dado e Bibi ficará cada vez mais na rua da amargura para pagar as contas.\nA força do quererA Força do Querer finala força do querer rubinhofinal de a força do querer


Parque da Cidade é esvaziado após mortes por febre maculosa em São José dos Campos\nA ameaça de contato com carrapatos esvaziou o Parque da Cidade, um dos principais pontos turísticos e de lazer em São José dos Campos neste sábado (1º). Isso porque cerca de 100 capivaras, principais hospedeiras do carrapato-estrela, que transmite a febre maculosa, vivem no local.\nAs peças teatrais do Festivale, um dos principais eventos de teatro da região, foram transferidas para o Parque Santos Dumont. Um festival gastronômico e artesanal foi mantido, mas mesmo com a atração, o movimento de visitantes foi pequeno.\nA vendedora de sorvetes Ivana Silva trabalha no parque há 20 anos e até o começo desta tarde não tinha vendido nada. Segundo ela, o movimento foi bem abaixo do esperado para um sábado ensolarado. "Trabalho aqui desde o começo do parque e nunca vi dessa maneira. vIM cedo aqui e está parado", afirmou.\nO vendedor de pipocas José Pinheiro disse que já esperava o movimento ficasse baixo. "Vim trabalhar já imaginando que o movimento iria cair bem e concretizou. Nunca vi com pouco movimento assim, muito ruim", disse.\n“Viemos a lazer aqui mas é preocupante, porque algumas pessoas ja morreram por febre maculosa. Cautela nunca é demais, então temos que olhar para todos os lados, porque todo cuidado é pouco”, afirmou a professora Lilian Lorena.\nNeste ano, São José teve quatro mortes confirmadas por febre maculosa. Dois irmãos, de 36 e 39 anos, que morreram entre o fim de julho e o início de agosto após irem a um sítio.\nOutros dois homens tiveram o diagnóstico da morte confirmado por exames na última terça (28) - em três destes quatro óbitos, as famílias das vítimas contaram que eles tiveram contato com ambiente rural na zona norte - onde fica o Parque da Cidade.\nPara evitar mais casos, a prefeitura aplicou carrapaticidade no parque e orienta que os visitantes evitem as áreas próximo ao lago.\nFONTE: G1 Vale do Paraíba (Texto e imagem copiados na íntegra)