cobol query 1.0: ferramenta para extraÇÃo de dados...

89
UNIVERSIDADE REGIONAL DE BLUMENAU CENTRO DE CIÊNCIAS EXATAS E NATURAIS CURSO DE CIÊNCIAS DA COMPUTAÇÃO – BACHARELADO COBOL QUERY 1.0: FERRAMENTA PARA EXTRAÇÃO DE DADOS EM ARQUIVOS COBOL ANDRÉ LUIZ JACINTO BLUMENAU 2007 2007/1-05

Upload: others

Post on 26-Jan-2020

49 views

Category:

Documents


2 download

TRANSCRIPT

UNIVERSIDADE REGIONAL DE BLUMENAU

CENTRO DE CIÊNCIAS EXATAS E NATURAIS

CURSO DE CIÊNCIAS DA COMPUTAÇÃO – BACHARELADO

COBOL QUERY 1.0: FERRAMENTA PARA EXTRAÇÃO DE

DADOS EM ARQUIVOS COBOL

ANDRÉ LUIZ JACINTO

BLUMENAU 2007

2007/1-05

ANDRÉ LUIZ JACINTO

COBOL QUERY 1.0: FERRAMENTA PARA EXTRAÇÃO DE

DADOS EM ARQUIVOS COBOL

Trabalho de Conclusão de Curso submetido à Universidade Regional de Blumenau para a obtenção dos créditos na disciplina Trabalho de Conclusão de Curso II do curso de Ciências da Computação — Bacharelado.

Prof. Adilson Vahldick – Orientador

BLUMENAU 2007

2007/1-05

COBOL QUERY 1.0: FERRAMENTA PARA EXTRAÇÃO DE

DADOS EM ARQUIVOS COBOL

Por

ANDRÉ LUIZ JACINTO

Trabalho aprovado para obtenção dos créditos na disciplina de Trabalho de Conclusão de Curso II, pela banca examinadora formada por:

______________________________________________________ Presidente: Prof. Adilson Vahldick – Orientador, FURB

______________________________________________________ Membro: Prof. Wilson Pedro Carli – FURB

______________________________________________________ Membro: Prof. José Roque Voltolini da Silva – FURB

Blumenau, 06 de julho de 2007

Dedico este trabalho a todos os amigos, especialmente aqueles que me ajudaram diretamente na realização deste e em especial à minha família pelo incentivo para alcançar mais este objetivo.

AGRADECIMENTOS

A Deus, pelo seu imenso amor e graça.

À minha família, que esteve presente nos momentos mais difíceis.

Aos meus amigos de faculdade, pelo auxílio e pelas cobranças.

A empresa Hbsis Informática que me deu condições e apoio no desenvolvimento deste

trabalho na parte referente à linguagem COBOL.

Ao meu orientador, Adilson Vahldick, por ter acreditado e me ajudado no

desenvolvimento e conclusão deste trabalho.

Os bons livros fazem “sacar” para fora o que a pessoa tem de melhor dentro dela.

Lina Sotis Francesco Moratti

RESUMO

Este trabalho apresenta o desenvolvimento de uma ferramenta para extração de informações em arquivos de dados COBOL via comandos de consulta SQL. São efetuadas as análises léxica, sintática e semântica do comando informado e também a geração de código COBOL para acesso aos arquivos de dados. Em seguida este é compilado e executado (por um compilador externo a aplicação, parametrizado pelo usuário), retornando o resultado da consulta na própria ferramenta. Na concepção desta é adotado o padrão de projetos MVC e o motor de templates Velocity para geração do código de saída. Também é utilizada a ferramenta GALS para a geração dos analisadores léxico e sintático. Para os testes de compilação utilizou-se a ferramenta Micro Focus NetExpress 3.1.

Palavras-chave: COBOL. Banco de dados. Analisadores léxico, sintático e semântico. Geração de código. MVC. Velocity.

ABSTRACT

This work presents the development of a tool for extracting information from COBOL data files through SQL queries. Lexical, syntactical and semantical analyses of the query are performed followed by the COBOL code generate for accessing the data files. The output COBOL code is compiled (the user adapt an external compiler) to an executable file which returns the query result to the user (this result is showed in the tool). The MVC pattern has been adopted during its development as well as the Velocity template engine for code generate. The GALS tool is also used to generate the lexical and syntactical analyzers. The Micro Focus NetExpress 3.1 is use to compilation tests.

Key-words: COBOL. Database. Lexical, syntactical and semantical analysers. Code generate. MVC. Velocity.

LISTA DE ILUSTRAÇÕES

Quadro 1 – Sintaxe da instrução select em COBOL ................................................................20

Figura 1 – Funcionamento de um motor de templates.............................................................23

Quadro 2 – Exemplificação de referências em VTL ................................................................24

Quadro 3 – Exemplificação de diretivas em VTL....................................................................25

Quadro 4 – Exemplificação de macros em VTL ......................................................................26

Quadro 5 – Exemplificação de comentários em VTL ..............................................................26

Figura 2 – Diagrama de casos de uso .......................................................................................33

Quadro 6 – Descrição do caso de uso UC01 – Cadastrar banco de dados ...............................33

Quadro 7 – Descrição do caso de uso UC02 – Cadastrar layout..............................................34

Quadro 8 – Descrição do caso de uso UC05 – Parametrizar sistema.......................................35

Quadro 9 – Descrição do caso de uso UC03 – Cadastrar campo .............................................36

Quadro 10 – Descrição do caso de uso UC04 – Cadastrar chave.............................................37

Quadro 11 – Descrição do caso de uso UC06 – Executar consulta..........................................38

Quadro 12 – Descrição do caso de uso UC07 – Compilar código gerado ...............................38

Figura 3 – Diagrama de atividades...........................................................................................39

Figura 4 – Diagrama de pacotes ...............................................................................................41

Figura 5 – Diagrama de classes do pacote model.metadata ...................................................42

Figura 6 – Diagrama de classes do pacote model.sqlParts ...................................................42

Figura 7 – Diagrama de classes do pacote model.cobolParts ...............................................43

Quadro 13 – Classes do pacote view ........................................................................................44

Quadro 14 – Classes do pacote controller.codeGenerate ..................................................45

Quadro 15 – Classes do pacote controller.manager ............................................................45

Quadro 16 – Definições regulares da BNF...............................................................................46

Quadro 17 – Palavras reservadas e caracteres especiais...........................................................47

Quadro 18 – Gramática referente ao comando describe..........................................................47

Quadro 19 – Gramática referente ao comando select...............................................................48

Quadro 20 – Exemplo de código COBOL para declaração da estrutura dos arquivos ............49

Quadro 21 – Exemplo de código COBOL para o produto cartesiano e gravação do arquivo de

resultado.................................................................................................................50

Figura 8 – Fluxograma do processo de geração de código.......................................................51

Quadro 22 – Parte do conteúdo de um arquivo XML de banco de dados................................53

Quadro 23 – Classe controller.manager.LayoutManager ..................................................55

Quadro 24 – Interface controller.manager. IOInterface..................................................57

Quadro 25 – Método process() da classe controller.manager.RunManager ...................58

Quadro 26 – Principais métodos privados chamados pelo método process() da classe

controller.manager.RunManager .....................................................................59

Quadro 27 – Invocando métodos do controlador controller.manager.LayoutManager

(leitura e gravação) ................................................................................................61

Quadro 28 – Implementação da interface controller.manager. IOInterface pela classe

view.MainShell ...................................................................................................63

Quadro 29 – Alterações no código gerado pela ferramenta GALS..........................................65

Quadro 30 – Método executeAction(int action, Token token) pertencente a classe

controller.analyser.SemantAnalyser ...........................................................66

Quadro 31 – Método correspondente à ação semântica responsável pela verificação da

existência de um layout.........................................................................................67

Quadro 32 – Parte da classe controller.codegenerate.SqlToCobol .................................68

Quadro 33 – Classe controller.codegenerate.CobolGenerate ........................................69

Quadro 34 – Identification division e environment division do arquivo

mainTemplate.vm ..................................................................................................70

Quadro 35 – Data division e working-storage section do arquivo mainTemplate.vm.71

Quadro 36 – Sessão 0000-control do arquivo mainTemplate.vm........................................71

Quadro 37 – Sessões 1000-init , 2000-process e 3000-finish do arquivo

mainTemplate.vm ..................................................................................................72

Quadro 38 – Demais sessões COBOL do arquivo mainTemplate.vm .....................................73

Quadro 39 – Conteúdo do arquivo de compilação ...................................................................74

Figura 9 – Cobol Query 1.0......................................................................................................75

Figura 10 – Cadastro de banco de dados ..................................................................................75

Figura 11 – Cadastro de layout.................................................................................................76

Figura 12 – Cadastro de campo ................................................................................................76

Figura 13 – Cadastro de chave .................................................................................................77

Figura 14 – Atualização das tabelas de campos e de chaves....................................................78

Figura 15 – Parametrização do sistema ....................................................................................78

Figura 16 – Consulta na ferramenta .........................................................................................79

Figura 17 – Mensagens de erro durante uma consulta .............................................................80

Figura 18 – Exemplo de descrição de layout............................................................................81

Quadro 40 – Comparação entre ConnectWare e CobolQuery 1.0. ..........................................82

LISTA DE SIGLAS

API – Application Programming Interface

ASCII – American Standard Code for Information Interchange

BNF – Backus-Naur Form

CASE – Computer-Aided Software Engineering

COBOL – Common Business Oriented Language

DDL – Data Definition Language

DML – Data Manipulation Language

HTML – Hyper Text Markup Language

IDE – Integrated Development Environment

ISAM – Indexed Sequencial Access Method

JDBC – Java Data Base Connectivity

JDK – Java Development Kit

MVC – Model View Controller

ODBC – Open Data Base Connectivity

RF – Requisito Funcional

RNF – Requisito Não-Funcional

SAM – Sequencial Access Method

SQL – Structured Query Language

SWT – Standard Widget Toolkit

UML – Unified Modeling Language

VTL – Velocity Template Language

XML – eXtensible Markup Language

SUMÁRIO

1 INTRODUÇÃO..................................................................................................................14

1.1 OBJETIVOS DO TRABALHO ........................................................................................16

1.2 ESTRUTURA DO TRABALHO......................................................................................16

2 FUNDAMENTAÇÃO TEÓRICA....................................................................................18

2.1 SQL....................................................................................................................................18

2.2 FORMAS DE ACESSO E DE ORGANIZAÇÃO DE ARQUIVOS DE DADOS

PERSISTIDOS EM COBOL.............................................................................................19

2.3 ANÁLISE LÉXICA, SINTÁTICA E SEMÂNTICA .......................................................20

2.4 EXPRESSÕES REGULARES..........................................................................................21

2.5 GRAMÁTICAS LIVRES DE CONTEXTO.....................................................................21

2.6 MOTORES DE TEMPLATES...........................................................................................22

2.6.1 Motor de templates Velocity...........................................................................................23

2.7 GERAÇÃO DE CÓDIGO.................................................................................................27

2.8 TRABALHOS CORRELATOS........................................................................................28

2.8.1 ConnectWare...................................................................................................................28

2.8.2 Totem ..............................................................................................................................29

2.8.3 Extensão da ferramenta Delphi2Java-II para suportar componentes de banco de dados29

3 DESENVOLVIMENTO DO TRABALHO.....................................................................31

3.1 REQUISITOS PRINCIPAIS DO PROBLEMA A SER TRABALHADO.......................31

3.2 ESPECIFICAÇÃO ............................................................................................................32

3.2.1 Modelo de casos de uso...................................................................................................32

3.2.2 Modelo de atividades ......................................................................................................39

3.2.3 Modelo de pacotes e classes............................................................................................40

3.4.5 Especificação da BNF .....................................................................................................45

3.2.4 Estrutura básica do código COBOL................................................................................49

3.4.5 Especificação do gerador de código ................................................................................51

3.3 IMPLEMENTAÇÃO ........................................................................................................51

3.3.1 Técnicas e ferramentas utilizadas....................................................................................52

3.3.2 Implementação da ferramenta .........................................................................................52

3.3.2.1 Armazenamento do metadados.....................................................................................52

3.3.2.2 Implementação da camada de modelo..........................................................................53

3.3.2.3 Implementação das classes controladoras ....................................................................54

3.3.2.4 Implementação da camada de visão .............................................................................60

3.3.2.5 Implementação dos analisadores (léxico, sintático e semântico) .................................64

3.3.2.6 Implementação da geração de código...........................................................................67

3.3.2.7 Definição do template...................................................................................................70

3.3.3 Operacionalidade da implementação ..............................................................................73

3.4 RESULTADOS E DISCUSSÃO ......................................................................................81

4 CONCLUSÕES..................................................................................................................84

4.1 LIMITAÇÕES...................................................................................................................85

4.2 EXTENSÕES ....................................................................................................................85

REFERÊNCIAS BIBLIOGRÁFICAS .................................................................................87

14

1 INTRODUÇÃO

Archbell et al (2003) afirmam que setenta e cinco por cento de todas as transações em

mainframes1 são realizadas por sistemas2 desenvolvidos na linguagem de programação

COBOL. Dizem ainda que mais de sessenta por cento de todos os acessos a informações em

páginas na internet ocorrem em um mainframe. Continua citando que mais de noventa por

cento dos dados financeiros e relacionados a seguros são processados por programas COBOL.

Portanto, é correto afirmar que esta linguagem tem grande importância no cenário de

desenvolvimento de sistemas de informação, tanto na sua história quanto na utilização ainda

hoje em grande escala.

Os sistemas desenvolvidos na linguagem de programação referenciada acima não são

aprazíveis ao mundo orientado a objetos, mas funcionam de forma rápida, precisa e confiável

na concepção de aplicações comerciais de grande porte (ARCHBELL et al, 2003). Por outro

lado, a estrutura de armazenamento das informações é totalmente vinculada ao sistema que a

gerencia, pois os arquivos de dados não possuem nenhuma descrição sobre o tipo de

informação que está armazenada, sendo estas informações gerenciadas pela aplicação. Desta

forma, não há uma maneira de interação dos usuários com os dados diferentemente ao que o

sistema disponibiliza, salvo por ferramentas comerciais como o ConnectWare (PARKWAY,

2005). Por fim, se é desejável a visualização de uma informação de modo diferente ao que o

sistema prevê, é necessário o desenvolvimento de uma rotina especial para atender a

solicitação do cliente.

Pensando em auxiliar as empresas desenvolvedoras de softwares comerciais e clientes

usuários de aplicações desenvolvidas por estas empresas, surge a idéia da concepção de uma

ferramenta em Java para consulta a estes dados de forma externa. A escolha de Java se dá por

ser uma linguagem orientada a objetos, o que proporciona um nível elevado de abstração,

auxiliando no desenvolvimento, modelagem e manutenção. Segundo Bezerra (2002, p. 6), a

orientação a objetos como técnica de desenvolvimento de sistemas diminui a diferença entre a

realidade e os modelos construídos.

1 Mainframe é um supercomputador capaz de armazenar e manipular grande massa de dados de forma rápida e segura. 2 Sistema e aplicações comerciais são utilizados como sinônimos neste trabalho.

15

A aplicação apresentada neste trabalho tem como entrada o cadastro do metadados3,

pois como citado anteriormente, os arquivos de dados COBOL não guardam informações

sobre as suas características. Após ter o metadados cadastrado, a ferramenta possibilita a

digitação de comandos de manipulação de dados em DML, parte da linguagem de acesso a

dados SQL, para leitura dos arquivos. As requisições são enviadas a um interpretador, que

analisa léxica, sintática e semanticamente os comandos, gerando um código fonte COBOL

com o uso de templates4. Por fim, este código de saída é compilado em tempo de execução,

gerando um programa. Este programa é executado, gravando o resultado do comando DML

em um arquivo temporário, que é lido pela ferramenta e apresentado ao usuário.

A ferramenta permite apenas a leitura aos dados, pois qualquer alteração, inserção ou

exclusão de informações indevidas podem comprometer o sistema que gerencia os arquivos,

causando inconsistências. Esta limitação ocorre porque em um banco de dados desta natureza,

o controle relacional está totalmente embutido dentro da camada de aplicação.

O código gerado é equivalente ao comando informado e a compilação do mesmo é

transparente ao usuário da ferramenta. Os analisadores léxico e sintático tem a

responsabilidade de consistir a requisição digitada, evitando erros de interpretação. O

analisador semântico possui a função de mapear a requisição do usuário, obtendo assim o

código de saída fiel à instrução solicitada. Estes fatores acarretam em certo grau de

complexidade, visto que não pode haver inconsistência entre o comando informado e o

resultado da execução do código gerado.

Além disso, para a geração do código de saída, o uso de templates faz-se necessário,

pois existem particularidades com a sintaxe da linguagem de programação entre os

compiladores existentes. Ainda, para flexibilizar a ferramenta apresentada, o compilador do

código gerado é parametrizável. Isto permite o uso do compilador do mesmo fabricante e com

a mesma versão do utilizado na construção do sistema de gerência da base de dados. É

importante ressaltar que a estruturação interna dos arquivos de dados também pode variar de

acordo com fabricante e versão.

Para finalizar, a liberdade de visualização das informações traz uma flexibilidade

maior na extração dos dados por parte dos clientes. Conseqüentemente, acarreta em menos

alterações de programas por parte dos desenvolvedores e maior eficiência na resolução de

3 Metadados são as propriedades referentes aos arquivos de dados, como a organização, as chaves e as informações relacionadas aos campos como tipo, tamanho e descrição. 4 Templates são “[...] arquivos que contém [sic] variáveis e blocos especiais que serão dinamicamente transformados a partir de dados enviados pelo Motor de Templates gerando as interfaces das aplicações [...]” (ROCHA, 2005).

16

problemas por parte do suporte aos usuários.

1.1 OBJETIVOS DO TRABALHO

Este trabalho tem como objetivo o desenvolvimento de uma ferramenta para extração

de dados em bases geradas por programas COBOL.

Os objetivos específicos do trabalho são:

a) permitir o cadastro do metadados, sendo este utilizado nas análises léxica, sintática

e semântica de comandos DML e na geração do código de saída;

b) possibilitar a digitação de comandos de consulta DML com operações de junção,

projeção e seleção;

c) efetuar as análises léxica, sintática e semântica para consistir o comando digitado;

d) gerar código COBOL a partir do comando informado utilizando templates;

e) permitir a configuração de uma ferramenta externa para compilação do código

fonte gerado.

1.2 ESTRUTURA DO TRABALHO

A estrutura deste trabalho está dividida em capítulos que serão explicados a seguir.

O primeiro capítulo apresenta a contextualização, objetivo e justificativa para o

desenvolvimento do trabalho.

O segundo capítulo apresenta a fundamentação teórica do trabalho, com conceitos

sobre SQL, forma de acesso e organização de arquivos de dados persistidos em COBOL,

análise léxica, sintática e semântica, motores de templates, geração de código e trabalhos

correlatos.

O terceiro capítulo apresenta os requisitos da ferramenta, bem como sua especificação,

implementação e resultados. São mostrados diagramas de classe, modelo de casos de uso e

diagrama de atividades, um exemplo de código COBOL necessário para atender a solicitação

SQL, a especificação do gerador de código e a especificação da BNF utilizada. Também são

apresentadas explicações sobre o desenvolvimento da aplicação apresentada.

17

O quarto capítulo apresenta conclusões, limitações e sugestões para futuros trabalhos.

18

2 FUNDAMENTAÇÃO TEÓRICA

Neste capítulo são apresentados conceitos sobre SQL, forma de acesso e organização

de arquivos de dados persistidos em COBOL, análise léxica sintática e semântica, motores de

templates, geração de código e trabalhos correlatos.

2.1 SQL

Segundo Silberschatz, Korth e Sudarshan (1999, p. 109), a linguagem SQL é a mais

utilizada no acesso a banco de dados, surgindo no início dos anos setenta com o nome de

Sequel. Após modificações na sintaxe e no natural desenvolvimento e aperfeiçoamento, foi

renomeada para SQL e nos anos noventa criou-se o padrão SQL-92, utilizado até hoje.

Esta linguagem é dividida em instruções DDL e DML. Para Silberschatz, Korth e

Sudarshan (1999, p. 110), as instruções DDL compreendem os comandos para definição das

estruturas e dos relacionamentos de um banco de dados. Citam também que os comandos

DML são as consultas às informações guardadas nas estruturas de armazenamento, baseadas

na álgebra e no cálculo relacional. Estas instruções também englobam inclusão, exclusão e

alteração de dados.

A estrutura básica em uma expressão SQL de consulta consiste nas cláusulas select,

from e where. A cláusula select corresponde à operação de projeção, sendo utilizada para

relacionar os atributos desejados no resultado de uma consulta. A cláusula from é a operação

de produto cartesiano, associando as relações da pesquisa de uma expressão. Por fim, a

cláusula where corresponde à seleção do predicado da álgebra relacional, consistindo os

atributos da relação, que ocorre na cláusula from (SILBERSCHATZ; KORTH;

SUDARSHAN, 1999, p. 111).

A SQL forma um produto cartesiano das relações indicadas na clausula from, executa uma seleção em álgebra relacional usando o predicado da clausula where e, então, projeta o resultado sobre os atributos da clausula select. Na prática, SQL pode converter a expressão de uma forma equivalente, que pode ser processada de forma mais eficiente (SILBERSCHATZ; KORTH; SUDARSHAN, 1999, p. 111).

19

2.2 FORMAS DE ACESSO E DE ORGANIZAÇÃO DE ARQUIVOS DE DADOS PERSISTIDOS EM COBOL

Segundo Newcomer (1985, p. 50), existem duas formas de se acessar arquivos de

dados na linguagem de programação COBOL: forma de acesso seqüencial e o acesso direto

ou randômico.

Almeida (2005) cita que o acesso seqüencial nada mais é do que a leitura seqüencial

dos registros. Neste caso o que determina a ordem de processamento dos registros é a sua

seqüência física no próprio arquivo. No acesso randômico, o mesmo explica que o

processamento de um registro é efetuado com o auxílio de uma chave fornecida. Nesta forma

de acesso, a leitura inicia do ponto onde a chave está localizada.

Newcomer (1985, p. 50) ainda completa que é possível organizar o armazenamento

dos registros de três formas. São elas: organização seqüencial, organização indexada e

organização relativa. Ele afirma que na organização seqüencial, também conhecida como

SAM, os registros são armazenados um após o outro e são lidos na mesma ordem em que se

encontram no arquivo. Para acessar arquivos organizados desta maneira, utiliza-se somente o

acesso seqüencial.

Para Almeida (2005), em uma organização seqüencial indexada, também conhecida

como ISAM, o registro é identificado por um índice, também conhecido como chave de

acesso. Desta forma, os arquivos são divididos em duas áreas. A área de dados, onde são

armazenadas as informações dos registros e a área de índices, onde estão localizadas as

chaves de acesso e os endereços dos registros na área de dados. Para os arquivos desta

natureza, a forma de acesso é seqüencial ou randômica.

Nos arquivos com organização relativa, o acesso aos registros é efetuado a partir de

uma chave numérica. Para a leitura destes arquivos pode-se utilizar o acesso seqüencial ou

acesso direto (NEWCOMER, 1985, p. 50).

Para Newcomer (1985, p. 50) o programador COBOL pode escolher entre a

organização e o modo de acesso dos arquivos processados pelo programa com a instrução

select. A sintaxe da instrução select pode ser observada no Quadro 1.

20

SELECT arquivo-logico ASSIGN TO {DISK, PRINTER} arquivo-fisico ORGANIZATION IS {LINE SEQUENTIAL, INDEXED, RELATIVE} ACCESS MODE IS (SEQUENTIAL, DYNAMIC, RANDO M} {RECORD KEY IS chave-primaria {ALTERNATE KEY IS chave-secundaria {WHIT DUPL ICATES}}} FILE STATUS IS variavel-de-file-status

Fonte: adaptado de Newcomer (1985, p. 42). Quadro 1 – Sintaxe da instrução select em COBOL

Newcomer (1985, p. 49) cita que arquivo-logico é um identificador utilizado pelo

programador que serve de referência ao arquivo nas demais instruções do programa, e que a

cláusula ASSIGN TO associa o arquivo a um dispositivo de entrada ou saída. Também

comenta que a cláusula ORGANIZATION descreve a organização do arquivo lógico e a cláusula

ACCESS MODE descreve a forma de acesso ao mesmo. RECORD KEY especifica a chave

primária, sendo esta um campo no leiaute do arquivo. Respectivamente, ALTERNATE KEY

representa uma chave secundária, sendo esta também um campo no leiaute do arquivo lógico.

Para finalizar Newcomer (1985, p. 52) afirma que a cláusula FILE STATUS IS variavel-

de-file-status representa o retorno sobre o sucesso ou falha de cada operação tentada

sobre um arquivo.

2.3 ANÁLISE LÉXICA, SINTÁTICA E SEMÂNTICA

Para Louden (2004, p. 31), o analisador léxico é a fase do compilador que lê os

comandos e os separa em marcas, também denominadas de tokens5. Segundo Souza et al

(2002), uma das funções do analisador léxico é separar estas marcas, enviando uma cadeia de

tokens ao analisador sintático.

Conforme Souza et al (2002), o analisador sintático recebe a cadeia de tokens do

analisador léxico, verificando a integridade dos comandos e apresentando os possíveis erros

ao usuário. Louden (2004, p. 95) afirma que a análise sintática determina a estrutura de um

comando ou programa. Tal estrutura é dada pela BNF da linguagem, que define as regras

gramaticais de uma gramática livre de contexto.

Por fim, tem-se o analisador semântico. Louden (2004, p. 259) explica que a principal

função desta fase do compilador é computar as informações que estão além da capacidade das

5 Tokens são para Souza et al (2002) palavras reservadas ou símbolos colhidos na análise léxica.

21

gramáticas livres de contexto. Desta forma, as informações computadas estão fortemente

relacionadas com o significado do código traduzido.

2.4 EXPRESSÕES REGULARES

Segundo Louden (2004, p. 34), as expressões regulares representam padrões definidos

por um conjunto de caracteres, sendo este conjunto denominado linguagem gerada pela

expressão regular. Esta linguagem depende do conjunto de caracteres disponíveis, sendo este

geralmente o conjunto de caracteres ASCII (ou algum subconjunto do mesmo).

Ocasionalmente, o conjunto de caracteres poderá ser mais geral do que o conjunto

ASCII, sendo estes identificados neste caso como símbolos. Por ventura, este conjunto de

símbolos legais é denominado alfabeto (LOUDEN, 2004, p. 34).

Louden (2004, p. 34) completa que uma expressão regular pode conter caracteres com

significados especiais. Estes caracteres são chamados de metacaracteres ou meta-símbolos e

de maneira geral não fazem parte do conjunto de caracteres legais do alfabeto. Para

diferenciar o uso de um meta-símbolo do seu uso como membro do alfabeto frequentemente é

utilizado um caractere de escape, que desativa o significado especial de um meta-símbolo

(LOUDEN, 2004, p. 35).

Por fim, Louden (2004, p. 35) explica que para definir uma expressão regular em

primeira instância deve-se descrever o conjunto de expressões regulares básicas, compostas

por símbolos individuais. Em seguida, é necessário descrever operações para gerar novas

expressões regulares a partir das já existentes.

Há três operações básicas em expressões regulares: (1) escolha entre alternativas, que é indicada pelo metacaractere | (barra vertical); (2) concatenação, que é indicada pela justaposição (sem metacaracteres); e (3) repetição ou “fecho”, que é indicada pelo metacaractere *. (LOUDEN, 2004, p. 35).

2.5 GRAMÁTICAS LIVRES DE CONTEXTO

Para Louden (2004, p. 95) a análise sintática é geralmente definida pelas regras

gramaticais de uma gramática livre de contexto. Estas regras gramaticais, além de lineares,

22

podem ser recursivas e as estruturas de dados utilizadas para representação da estrutura

sintática são basicamente do tipo árvore, sendo esta denominada de árvore de análise sintática

ou simplesmente árvore sintática.

Pode-se dizer que uma gramática livre de contexto é uma especificação para a estrutura

sintática de uma linguagem de programação, sendo muito similar a especificação da estrutura

léxica por expressões regulares. Basicamente a principal diferença entre uma gramática livre

de contexto e as expressões regulares é que a primeira é recursiva e a outra é linear

(LOUDEN, 2004, p. 97).

Como já citado anteriormente, as expressões regulares são definidas através de um

alfabeto ou conjunto de símbolos, formados principalmente por caracteres. Louden (2004, p.

98) explica que no caso das gramáticas livres de contexto os símbolos são definidos

normalmente por marcas, sendo estas representadas também por cadeias de caracteres.

2.6 MOTORES DE TEMPLATES

Segundo Rocha (2005), os motores de templates ou template engines são mecanismos

de software que possibilitam a separação entre código dinâmico6 e código estático7, de forma

que a construção destes possa ocorrer independentemente. Desta maneira, deve existir um

programa responsável por instanciar o motor, associar valores às variáveis e aos blocos

especiais e finalmente processar o template.

Rocha (2005) explica que cada motor de templates tem uma linguagem definida para

acesso às variáveis e aos blocos especiais. Diz ainda que estas linguagens podem variar

bastante em nível de complexidade, dependendo do motor. Variam desde estruturas básicas

para a substituição de valores de variáveis ou até estruturas mais complexas de controle como

iterações e expressões condicionais. A figura 1 ilustra o funcionamento de um motor desta

natureza.

6 Código dinâmico é o código simbólico definido no template. São as variáveis que serão substituídas no processo de geração da saída pelo motor de templates. 7 Código estático é o código fixo no template, que não será modificado pelo motor de templates.

23

Fonte: adaptado de Rocha (2005).

Figura 1 – Funcionamento de um motor de templates

Primeiro, um motor é instanciado por uma aplicação qualquer, através de uma

requisição a esta aplicação. Esta aplicação associa também os valores às variáveis e aos

blocos do template utilizado. O motor passa todas estas variáveis ao template, que em seguida

é apresentado como resposta a requisição (ROCHA, 2005).

2.6.1 Motor de templates Velocity

Velocity é um motor de templates desenvolvido com a linguagem de programação

Java, sendo um conjunto de classes pertencente à biblioteca org.apache.velocity . A sua

maior utilização está voltada ao desenvolvimento de aplicações web, onde o código Java fica

totalmente separado do código HTML, tendo-se assim uma aplicação modularizada e

consequentemente com maior facilidade para manutenção (STEIL, 2002a).

Segundo Steil (2002a), o Velocity foi projetado para ser de fácil utilização, servindo

como solução genérica para processamento de templates. Cita ainda, que é ideal para qualquer

tipo de programa Java que necessite de formatação de dados e apresentação dos mesmos.

Para Steil (2002a) algumas das razões para utilizar o Velocity são:

a) possui sintaxe clara e de fácil compreensão;

b) integra-se facilmente a qualquer tipo de aplicação baseada em Java;

c) pode ser utilizado em qualquer área, não restringindo-se somente a aplicações web;

24

d) tem alto desempenho, possuindo configurações de caching8 para acelerar o

processamento.

O Velocity faz uso da linguagem VTL para incorporação do código dinâmico ao

código estático. Conforme Steil (2002b), esta linguagem é separada em três partes

principais, sendo estas: referências, diretivas e comentários.

As referências condizem com as variáveis da VTL (código dinâmico) e iniciam sempre

com o caractere dollar sign ($), podendo ser simples variáveis ou propriedades. Estas

últimas são tratadas na linguagem como objetos Java, havendo a possibilidade de

chamadas de métodos públicos do objeto. Isso é possível devido ao Velocity aplicar

reflexão9 as propriedades, onde o mesmo procura métodos públicos e atributos públicos

que possam condizer com o que foi solicitado no template (STEIL, 2002b).

O Quadro 2 exemplifica a utilização das referências em VTL.

## utilização de variável simples O meu nome eh $meuNome!!! ## utilização de propriedades $usuario.setNome("Fulano de tal") O nome do usuário eh $usuario.getNome()!!! $meuLinkedList.getFirst().toString()

Fonte: adaptado de Steil (2002b). Quadro 2 – Exemplificação de referências em VTL

Para Steil (2002b), as diretivas são palavras reservadas da VTL, iniciando sempre com

o caractere number sign (#). As diretivas podem atribuir valores a referências, efetuar

comparações e efetuar iteração em listas. Também é possível a criação de métodos (macros) e

a inclusão de arquivos externos ao template, sendo estes também processados pelo Velocity.

O Quadro 3 exemplifica a utilização de diretivas e o Quadro 4 a utilização de macros

em VTL.

8 Caching refere-se à memória cache. Cache é uma seção de memória de alta velocidade, que armazena dados para busca rápida do processador. 9 Reflexão é uma propriedade da orientação objetos, onde a partir desta pode-se visualizar os métodos e atributos públicos de determinada classe.

25

## atribuição de valores #set ($idade = 21) #set ($objeto.nome = "sicrano") #set ($meuArray = ["valor 1", "valor 2", "valor 3", "valor n"]) ## comparações #if ($var1 == $var2) sao iguais #else nao sao iguais #end #if (!$numero > 100) numero NAO eh maior que 100 #else numero EH maior que 100 #end

#if ($nome) contem algum dado #end ## iterações #foreach ($nome in $nomesList) Olá $nome #end #foreach ($numero in [1..10]) $numero #end ## inclusão de arquivos externos ao template #include("arquivoQualquer.txt")

Fonte: adaptado de Steil (2002b). Quadro 3 – Exemplificação de diretivas em VTL

26

## criação de uma macro #macro( nomeMacro $arg1[, $arg2, $arg3, ... $argn ] ) [ codigo. ] #end ##onde: ## ## nomeMacro é o identificador utilizado para chama da da macro ## $arg1[, $arg2, $arg3, ... $argn ] são os parâmet ros da macro ## utilizacao de uma macro ## Criação de uma macro para criar linhas em uma ta bela HTML #macro (criaLinha $nome) <tr><td>$nome</td></tr> #end ## Chamada da macro #set ($nomes = ["Nome 1", "Nome 2", "Nome 3", "Nome 4"]) <table> #foreach ($nome in $nomes) #criaLinha($nome) #end </table>

Fonte: adaptado de Steil (2002b). Quadro 4 – Exemplificação de macros em VTL

Os comentários não são processados, podendo ser apresentados em uma única linha ou

em várias linhas. O Quadro 5 mostra a utilização de comentários.

## comentário em uma única linha #* Comentário em várias linhas *#

Fonte: adaptado de Steil (2002b). Quadro 5 – Exemplificação de comentários em VTL

Steil (2002b) conclui que a linguagem VTL é de simples utilização, e unida com o

Velocity fornece uma maneira simples e eficiente de apresentação de informações pré-

formatadas.

27

2.7 GERAÇÃO DE CÓDIGO

Para Moreira e Mrack (2003), um gerador de código é uma ferramenta que auxilia no

processo de desenvolvimento de sistemas, atuando na fase de implementação do projeto,

gerando o código fonte que seria desenvolvido pelo programador. Conforme Herrington

(2003, p. 15), o ato de gerar código traz benefícios, como a maior qualidade ao se gerar um

grande volume de fontes e a reutilização dos mesmos. Desta forma, é abstraída a preocupação

com trechos triviais do programa, dando-se mais atenção às regras de negócio da aplicação

desenvolvida.

Herrington (2003, p. 93) cita que para se desenvolver um gerador de código é

necessário seguir as seguintes etapas:

a) possuir o código de teste: o ponto de partida para se desenvolver um gerador de

código é possuir um código de teste em mãos. Ele irá ser comparado com o código

de saída gerado no final do processo de geração, visto que a saída deverá ser

equivalente ao código de teste;

b) projetar o gerador: para projetar o gerador é necessário especificar como será a

entrada das informações, como esta entrada será processada e como deverá ser

apresentada a saída. O mais importante nesta etapa é a elicitação e análise dos

requisitos sobre o código que será gerado;

c) implementar a análise dos dados de entrada: consiste em implementar o

processamento das informações de entrada, efetuando a extração e o

armazenamento dos dados necessários para se gerar a saída;

d) desenvolver os templates: nesta etapa é necessário criar os templates para a

construção da saída;

e) verificação da saída: após gerar o código a partir dos templates desenvolvidos, o

último passo é executar a saída obtida e comparar com a execução do código de

teste, verificando assim a equivalência.

Moreira e Mrack (2003) explicam que apesar do código produzido por um gerador

estar correto, vale ressaltar alguns pontos:

a) funcionamento em uma única via: uma vez que o modelo de dados é modificado,

deve-se executar a geração do código novamente. Isto pode causar problemas, pois

podem-se ter semânticas divergentes entre modelo e código;

b) padrão: o padrão do código gerado é dependente da ferramenta. Não se leva em

28

consideração o padrão em que a equipe de desenvolvimento está apta a trabalhar;

c) qualidade do código: um gerador de código não leva em consideração a integração

com outros sistemas. Podem-se ter problemas também quanto à estrutura e

desempenho do código gerado.

2.8 TRABALHOS CORRELATOS

Existem aplicações com características semelhantes à desenvolvida neste trabalho.

Com relação ao acesso aos dados oriundos de aplicações COBOL via SQL, tem-se o driver10

ODBC ConnectWare (PARKWAY, 2005). Em relação à geração de código COBOL tem-se o

pacote de ferramentas CASE Totem (CASEMAKER, 2005). Por fim, sobre analisadores

léxico, sintático, semântico e geração de código tem-se a ferramenta Delphi2Java-II

(SILVEIRA, 2006).

2.8.1 ConnectWare

Basicamente o ConnectWare é um driver para acesso de dados via SQL em arquivos

SAM e ISAM, com conexão via ODBC. Este é configurado a partir do gerenciador de drivers

ODBC do Microsoft Windows. É compatível com qualquer linguagem que comporte

interfaces desta natureza (MICRO COBOL SOFTWARE, 2005).

Com o ConnectWare permite-se queries SQL suportando funções de grupo, junção de

tabelas, filtros, inserção, alteração e exclusão de dados. As propriedades relacionadas aos

tipos de organização dos arquivos, aos tipos de dados, nomes de arquivos e nomes de colunas

são configuradas no próprio gerenciador ODBC.

O driver possui a vantagem de utilizar os mesmos tipos de dados COBOL. Desta

maneira, não é necessário converter estes dados e ter estes formatos controlados em paralelo,

pois os mesmos são convertidos em tempo de execução para o padrão ODBC. Assim, pode-se

ter uma aplicação em Delphi e outra em COBOL acessando os mesmos arquivos, cada um de

10 Drivers são programas ou rotinas usadas para gerenciar um dispositivo de entrada ou saída. No contexto deste capítulo, são softwares que permitem a comunicação entre uma aplicação e outra, sendo utilizados geralmente para conectar sistemas de informação e sistemas gerenciadores de dados.

29

sua maneira. Porém é importante ressaltar que existem drivers diferentes para cada fabricante

COBOL. Os fabricantes suportados são: Micro Focus, Informix, Byte Designs e Pervasive

(PARKWAY, 2005).

2.8.2 Totem

É um pacote de ferramentas CASE que auxilia desenvolvedores COBOL na geração de

código fonte (CASEMAKER, 2005). O pacote é formado pela ferramenta homônima Totem,

utilizada na geração de interfaces e a ferramenta DBMaker, utilizada na modelagem de bases

de dados.

Estas ferramentas são fabricadas pela empresa de sofware norte-americana Casemaker.

Segundo a mesma, com o pacote Totem é possível desenvolver aplicações COBOL por

completo, desde a modelagem dos arquivos de dados até a geração das interfaces ao usuário

(CASEMAKER, 2005).

A ferramenta DBMaker provê assistentes para o design das bases de dados, definindo

propriedades e criando arquivos persistidos COBOL. A ferramenta Totem disponibiliza

assistentes na criação de aplicações e na geração de interfaces, como telas de relatórios e telas

de cadastro de informações. Para isso utiliza a API do sistema operacional na construção dos

componentes, como botões e caixas de texto.

2.8.3 Extensão da ferramenta Delphi2Java-II para suportar componentes de banco de dados

O Delphi2Java-II é uma ferramenta que auxilia no processo de migração de aplicações

da linguagem de programação Delphi para a linguagem de programação Java (FONSECA,

2005). A mesma efetua a análise de formulários Delphi, contendo componentes de interface

com o usuário, gerando classes Java que preservam o layout do formulário original. Segundo

Fonseca (2005, p. 57), uma limitação da ferramenta está no grupo de componentes

selecionados para a conversão, que não abrange componentes visuais de banco de dados. Com

foco neste problema, surgiu a idéia de estender Delphi2Java-II para suportar componentes

visuais de banco de dados, utilizando a API JDBC (SILVEIRA, 2006, p. 13).

30

A ferramenta recebe como entrada um arquivo de formulário Delphi, que contém todas

as informações dos componentes da interface de uma aplicação desenvolvida nesta linguagem

(SILVEIRA, 2006, p. 20). Após o processamento deste arquivo, são geradas as classes Java

de saída. Para dividir e padronizar a saída em camadas é utilizado o padrão de

desenvolvimento MVC (SILVEIRA, 2006, p. 44). Para efetuar a leitura e recuperação das

informações contidas nos formulários Delphi são utilizados os analisadores léxico, sintático e

semântico. Para gerar as classes Java de saída é utilizado o motor de templates Velocity

(SILVEIRA, 2006, p. 37).

31

3 DESENVOLVIMENTO DO TRABALHO

Este capítulo apresenta os requisitos da ferramenta, bem como sua especificação,

implementação e resultados obtidos. São mostrados diagramas de classe, modelo de caso de

uso e diagrama de atividades, um exemplo de código COBOL necessário para atender a

solicitação SQL, a especificação do gerador de código e a especificação da BNF utilizada.

Também são apresentadas explicações sobre o desenvolvimento da aplicação apresentada.

3.1 REQUISITOS PRINCIPAIS DO PROBLEMA A SER TRABALHADO

Os requisitos funcionais e não-funcionais da ferramenta são:

a) disponibilizar uma interface para a digitação dos comandos e apresentar o resultado

das instruções solicitadas (RF);

b) disponibilizar uma área para cadastro do metadados (RF);

c) efetuar as análises léxica, sintática e semântica da instrução digitada, informando

ao usuário da ferramenta os possíveis erros (RF);

d) interpretar somente o comando DML select, implementando os conceitos de

projeção, junção e seleção. Os outros comandos DML insert, delete e update

deverão ser desconsiderados (RF);

e) acessar somente arquivos com a organização ISAM e SAM (RF);

f) gerar o código COBOL em tempo de execução, embasado no comando DML

solicitado (RF);

g) utilizar templates para a modelagem do código COBOL gerado (RF);

h) compilar o código gerado, construindo um programa executável. Utilizar este

programa para o acesso aos arquivos (RF);

i) gravar a saída da execução do programa gerado em um arquivo temporário,

efetuando a leitura do mesmo pela ferramenta (RF);

j) dar suporte a diferentes fabricantes de compiladores COBOL (RNF);

k) gravar o metadados em um arquivo do tipo XML (RNF);

l) ser compatível com os sistemas operacionais Windows 2000 e XP (RNF).

32

3.2 ESPECIFICAÇÃO

Para a especificação foram efetuados diagramas pertencentes à linguagem de

modelagem UML, sendo estes criados com a ferramenta Enterprise Architect. Tem-se nesta

sessão o modelo de casos de uso, o diagrama de atividades, o diagrama de pacotes, os

diagramas de classes dos pacotes pertencentes ao modelo da ferramenta, um exemplo de

código COBOL necessário para atender a solicitação SQL, a especificação do gerador de

código e a especificação da BNF.

É importante salientar que a ferramenta é dividida em três camadas distintas, sendo

elas a camada de modelo, a camada de visão e por fim a camada de controle. A camada de

modelo compreende a modelagem do negócio da aplicação. A camada de visão representa a

apresentação das informações ao usuário e a camada de controle, por sua vez, é responsável

pela atualização do modelo e também do controle de execução da aplicação.

3.2.1 Modelo de casos de uso

Para Bezerra (2002, p. 45) o modelo de casos de uso é de extrema importância, pois

força os desenvolvedores a modelar o sistema de acordo com o usuário, e não o usuário de

acordo com o sistema. É composto por casos de uso, atores e relacionamento entre estes

(BEZERRA, 2002, p. 46).

Os casos de uso da ferramenta desenvolvida são:

a) cadastrar banco de dados (UC01);

b) cadastrar layout (UC02);

c) cadastrar campo (UC03);

d) cadastrar chave (UC04);

e) parametrizar sistema (UC05);

f) executar consulta (UC06);

g) compilar código gerado (UC07).

A Figura 2 apresenta o diagrama de casos de uso.

33

ud Diagrama de casos de uso

Usuário

UC01 - Cadastrar banco de dados

UC02 - Cadastrar layout

UC03 - Cadastrar campo

UC04 - Cadastrar chave

UC05 - Parametrizar

sistema

UC06 - Executar consulta (Query)

UC07 - Compilar código gerado

«extend»

«extend»

«extend»

Figura 2 – Diagrama de casos de uso

O Quadro 6 apresenta a descrição do caso de uso cadastrar banco de dados.

UC01 – Cadastrar banco de dados Sumário: O usuário cadastra um banco de dados (arquivo XML representando o metadados). Ator primário: Usuário. Precondições: Nenhuma Fluxo principal: 1. O sistema carrega todos os bancos de dados cadastrados e apresenta ao usuário. 2. O usuário informa um novo identificador do novo banco de dados e salva. 3. O sistema grava em disco o banco informado. 4. O sistema carrega novamente todos os bancos de dados cadastrados e apresenta ao usuário, terminando o caso de uso. Fluxo alternativo (2): exclusão de um banco de dados a) O usuário escolhe um banco de dados existente e exclui. b) O sistema solicita confirmação para exclusão. c) Se o usuário confirmar, o sistema excluí o cadastro do banco de dados e o caso de uso prossegue a partir do passo 4. d) Se o usuário não confirmar, o caso de uso prossegue a partir do passo 4. Pós-condições: Banco de dados cadastrado.

Quadro 6 – Descrição do caso de uso UC01 – Cadastrar banco de dados

34

No Quadro 7 é mostrada a descrição do caso de uso cadastrar layout.

UC02 – Cadastrar layout Sumário: O usuário cadastra um layout (associa o layout a um banco de dados). Ator primário: Usuário. Precondições: Possuir pelo menos um banco de dados cadastrado. Fluxo principal: 1. O sistema carrega todos os bancos de dados cadastrados e apresenta ao usuário. 2. O usuário seleciona um banco de dados. 3. O sistema carrega todos os layout´s contidos no banco de dados selecionado e apresenta ao usuário. 4. O usuário preenche as informações pertinentes ao layout. 5. O usuário pode relacionar os campos (<<extend>> UC03 – Cadastrar campo). 6. O usuário pode relacionar as chaves (<<extend>> UC04 – Cadastrar chave). 7. O usuário salva. 8. O sistema relaciona o layout no banco de dados e salva as alterações do mesmo. 9. O sistema carrega novamente todos os bancos de dados cadastrados e apresenta ao usuário, terminando o caso de uso. Fluxo alternativo (4): exclusão de um layout a) O usuário escolhe um layout existente e exclui. b) O sistema solicita confirmação para exclusão. c) Se o usuário confirmar, o sistema exclui o layout do banco de dados selecionado, prosseguindo o caso de uso a partir do passo 9. d) Se o usuário não confirmar o caso de uso prossegue a partir do passo 9. Pós-condições: Layout criado e relacionado ao banco de dados. Nota: No contexto da ferramenta, um layout é uma referência lógica para um arquivo de dados COBOL.

Quadro 7 – Descrição do caso de uso UC02 – Cadastrar layout

O caso de uso parametrizar sistema é apresentado no Quadro 8.

35

UC05 – Parametrizar sistema Sumário: O usuário parametriza o sistema. Serão essas informações utilizadas para as análises léxica, sintática e semântica e para a geração do código COBOL. Ator primário: Usuário. Precondições: Possuir pelo menos um banco de dados cadastrado e possuir o arquivo de compilação configurado. É no arquivo de compilação onde parametriza-se o compilador da ferramenta. Fluxo principal: 1. O sistema carrega todos os bancos de dados cadastrados e apresenta ao usuário. 2. O usuário seleciona o banco de dados padrão. 3. O usuário informa o caminho do arquivo de compilação e o tempo para time out. 4. O usuário clica em salvar e o sistema grava as parametrizações, terminando o caso de uso. Pós-condições: Gravado identificador do banco de dados padrão e caminho do arquivo de compilação. Notas: O arquivo de compilação deve conter comandos para compilação do código COBOL, geração do arquivo binário e execução do mesmo. O tempo para time out é o tempo limite entre geração do código COBOL e finalização da execução do arquivo binário, simbolizada pela geração do arquivo de resultado. Este último é necessário para impedir que a ferramenta fique aguardando o arquivo de resultado desnecessariamente, caso ocorra algum problema na compilação do código ou execução do arquivo binário.

Quadro 8 – Descrição do caso de uso UC05 – Parametrizar sistema

No Quadro 9 é mostrada a descrição do caso de uso cadastrar campo.

36

UC03 – Cadastrar campo Sumário: O usuário cadastra um campo em um layout. Ator primário: Usuário. Precondição: Deve-se possuir pelo menos um layout cadastrado ou em processo de cadastramento. Fluxo principal: 1. No cadastro de layout o usuário opta por adicionar um campo e é apresentada a tela de cadastro de campos. 2. O usuário preenche as informações e salva. 3. O sistema relaciona o campo no layout. 4. O sistema atualiza os campos do layout e o caso de uso termina. Fluxo alternativo (1): alteração de um campo a) O usuário seleciona um campo existente optando por alterá-lo e é apresentada a tela de cadastro de campos com as informações pertinentes já preenchidas. b) O usuário altera as informações necessárias e salva, prosseguindo o caso de uso no passo 4. Fluxo alternativo (1): exclusão de um campo a) O usuário seleciona um campo existente optando por excluí-lo. b) O sistema solicita confirmação para exclusão. c) Caso haja confirmação, o campo é excluído do layout e o caso de uso prossegue no passo 4. d) Caso não haja confirmação, o caso de uso termina. Pós-condição: Campo criado e relacionado ao layout.

Quadro 9 – Descrição do caso de uso UC03 – Cadastrar campo

No Quadro 10 é apresentada a descrição do caso de uso cadastrar chave.

37

UC04 – Cadastrar chave Sumário: O usuário cadastra uma chave em um layout. Ator primário: Usuário. Precondição: Deve-se possuir pelo menos um layout cadastrado ou em processo de cadastramento. Também deve-se possuir pelo menos um campo cadastrado ou em processo de cadastramento. Fluxo principal: 1. No cadastro de layout o usuário opta por adicionar uma chave e é apresentada a tela de cadastro de chaves. 2. O usuário preenche o identificador da chave, seleciona os campos para composição da mesma e salva. 3. O sistema relaciona a chave no layout. 4. O sistema atualiza as chaves do layout e o caso de uso termina. Fluxo alternativo (1): alteração de uma chave a) O usuário seleciona uma chave existente optando por alterá-la e é apresentada a tela de cadastro de chaves com as informações pertinentes já preenchidas. b) O usuário altera as informações necessárias e salva, prosseguindo o caso de uso no passo 4. Fluxo alternativo (1): exclusão de uma chave a) O usuário seleciona uma chave existente optando por excluí-la. b) O sistema solicita confirmação para exclusão. c) Caso haja confirmação, a chave é excluída do layout e o caso de uso prossegue no passo 4. d) Caso não haja confirmação, o caso de uso termina. Pós-condição: Chave criada e relacionada ao layout.

Quadro 10 – Descrição do caso de uso UC04 – Cadastrar chave

No Quadro 11 é apresentado à descrição para o caso de uso executar consulta (query).

38

UC06 – Executar consulta (query) Sumário: O usuário executa uma consulta SQL. Ator primário: Usuário. Precondição: Deve-se possuir pelo menos um layout cadastrado e o sistema parametrizado. Fluxo principal: 1. O usuário informa o comando SQL e executa. 2. O sistema carrega as parametrizações para posterior utilização. 3. O sistema efetua a análise léxica, sintática e semântica do comando. 4. Se o comando for uma consulta, é gerado código COBOL e este é compilado (<<extend>> UC07 – Compilar código gerado). 5. O sistema lê o resultado da consulta e apresenta em tela, terminando o caso de uso. Fluxo alternativo (3): solicitação de descrição de layout a) Se o comando for uma solicitação de descrição de um layout é efetuada a leitura da descrição, sendo esta apresentada ao usuário e tendo-se o final do caso de uso. Fluxo de exceção (2): erro léxico, sintático ou semântico a) Se houverem erros nas análises léxica, sintática ou semântica, os mesmos são apresentados em tela e o caso de uso termina. Fluxo de exceção (4): tempo de espera esgotado a) Se o tempo de espera pelo arquivo de resultado for esgotado (time out), é apresentado erro em tela e o caso de uso termina. Pós-condições: O usuário visualiza o resultado da consulta em tela.

Quadro 11 – Descrição do caso de uso UC06 – Executar consulta

Por fim, é apresentada no Quadro 12 a descrição do caso de uso compilar código

gerado.

UC07 – Compilar código gerado Sumário: O compilador COBOL (parametrizado pelo arquivo de compilação, no caso de uso parametrizar sistema) trata o código gerado e o executa, gerando um arquivo de resultado. Ator primário: Compilador COBOL. Precondições: Possuir o arquivo de compilação. Neste deverão estar instruções para compilação e execução do código, sendo de preferência um arquivo .bat. Fluxo principal: 1. O compilador efetua o tratamento do código gerado. 2. O compilador gera um arquivo binário a partir do código gerado. 3. O arquivo binário é executado, gerando um arquivo de resultado. Pós-condições: Tem-se um arquivo de resultado gerado, que é carregado pela ferramenta para posterior visualização do usuário em tela.

Quadro 12 – Descrição do caso de uso UC07 – Compilar código gerado

39

3.2.2 Modelo de atividades

Para demonstrar o fluxo do processo efetuado pela ferramenta é utilizado o diagrama

de atividades. Para Bezerra (2002, p. 228) o diagrama de atividades é considerado um tipo

especial de diagrama de estados, sendo orientado pelo fluxo de controle.

Na figura 3 é apresentado o diagrama de atividades da aplicação.

Figura 3 – Diagrama de atividades

Inicialmente, o usuário tem a opção de atualizar o modelo (neste caso cadastrar ou

alterar o metadados ou parametrizar o sistema) ou efetuar uma consulta na ferramenta. Se a

opção for a atualização do modelo, o mesmo é alterado e gravado em disco para posterior uso

da aplicação, sendo encerrado o processo. Caso contrário é efetuado uma consulta à base de

dados.

Quando ocorre uma consulta, o gerenciador de execução, que pertence à camada de

40

controle, carrega o banco de dados parametrizado (carregando do arquivo de parâmetros) e

instancia os analisadores (léxico, sintático e semântico). É efetuada a análise léxica, sintática e

semântica do comando informado, sendo disparada uma exceção em caso de erro nas mesmas.

Esta exceção é capturada pela camada de visão e apresentada ao usuário.

Após as análises, contidas na camada de controle, o gerenciador de execução verifica

se o comando informado é uma seleção ou uma descrição de layout. Se for uma descrição de

layout é retornado a camada de visão a estrutura do layout solicitado. Caso contrário é

instanciado o gerador de código.

O gerador de código (pertencente também à camada de controle) invoca o Velocity,

contextualizando os objetos resultantes da geração ao template, compondo estes parte do

modelo. O template é processado e o código COBOL é gerado.

O controlador de execução invoca o arquivo de compilação (carregado do arquivo de

parâmetros) e aguarda a geração do arquivo de resultado. O arquivo de compilação, quando

executado, tem a função de compilar o código e gravar o arquivo de resultado. Se o tempo de

espera do controlador de execução for esgotado, é gerada uma exceção, sendo esta capturada

pela camada de visão e apresentada ao usuário. Se o arquivo de resultado for gerado, o

conteúdo do mesmo é carregado e retornado a camada de visão, encerrando assim o processo.

3.2.3 Modelo de pacotes e classes

Para Bezerra (2002, p. 95) a modelagem de classes e de pacotes representa o aspecto

estrutural estático, permitindo compreender como o sistema está estruturado internamente. A

figura 4 apresenta o diagrama de pacotes da aplicação.

41

pd Diagrama de Pacotes

view

model

metadata

cobolParts sqlParts

params

controller

analyzer codeGenerate

manager xml

Figura 4 – Diagrama de pacotes

Basicamente o sistema está dividido em três pacotes distintos: view , model e

controller . O pacote view agrega as classes responsáveis pela interface ao usuário. O

pacote model contém os pacotes metadata , params , cobolParts e sqlParts , sendo o

modelo da aplicação. Por sua vez, o pacote controller contém os pacotes analyzer ,

codeGenerate , manager e xml , sendo responsável pela implementação das funcionalidades e

controles do sistema. Por fim, esta divisão de pacotes é efetuada para aplicar o padrão MVC

no desenvolvimento da ferramenta.

O pacote view tem uma relação de dependência com o pacote controller , que por

sua vez depende do pacote model . No pacote controller , o subpacote manager depende dos

subpacotes analyzer , codeGenerate e xml .

As classes do pacote model.metadata tem a função de metadados da ferramenta

(guardam propriedades referentes a uma base de dados COBOL), sendo utilizadas para as

análises léxica, sintática e semântica. O diagrama de classes deste pacote é apresentado na

Figura 5.

42

cd Diagrama de Classes - model.metadata

DataBase

Layout Field

Key

0..*

1

1..*1

1..*

1

1..*

0..*

Figura 5 – Diagrama de classes do pacote model.metadata

O pacote model.sqlParts contém as classes responsáveis pelo mapeamento em

objetos do comando SQL informado (Figura 6).

cd Diagrama de Classes - model.sqlParts

«interface»Element

Constant Identificator

Expression

Where

Projection

Join Table

0..*

1

1..*1

1..*

1

2

0..*

Figura 6 – Diagrama de classes do pacote model.sqlParts

As classes do pacote model.cobolParts responsabilizam-se por mapear o código

COBOL em objetos, sendo utilizados estes para a geração do código. O seu diagrama de

classes é mostrado na Figura 7.

43

cd Diagrama de Classes - model.cobolParts

IdentificationDivision

EnvironmentDivision

DataDivision

MovePart

CobolFilter CobolFilterExpressionFileDescriptor

SelectFile RecordKey

Variable

2..* 0..1

0..*

2

1..*1

1..*

0..1

1..*

1

1..*

1

1 0..*

Figura 7 – Diagrama de classes do pacote model.cobolParts

Por sua vez, o pacote model.params contém a classe Options , responsável pelo

modelo das parametrizações da ferramenta.

Fazem parte do pacote view as classes relacionadas no Quadro 13.

44

Classes do pacote view

O pacote view contém as classes responsáveis pela apresentação dos dados ao usuário.

Classe / Interface Descrição

DataBaseShell Determina a janela para cadastro de banco de dados.

Properties

Classe que contém os diretórios utilizados pela aplicação, como diretório dos bancos de dados e diretório para geração de código. Também contém a descrição do template e as demais descrições de arquivos temporários utilizados para geração e execução do código.

FieldShell Determina a janela para cadastro de campos. É instanciada a partir da classe LayoutShell .

FileUtil Classe que contém métodos relativos a controle de arquivos (como abrir e salvar scripts) para a classe MainShell .

KeyShell Determina a janela para cadastro de chaves. É instanciada a partir da classe LayoutShell .

LayoutShell Classe que determina a janela de cadastro de chaves.

MainShell

Principal classe de interface com o usuário. Contém campos para requisição de consulta e apresentação de resultado. Também invoca as classes responsáveis pelos cadastros. Implementa a interface controller.manager. IOInterface.

OptionShell Determina a janela para parametrização do sistema.

ViewException Classe de exceção do pacote de visão.

ViewUtil Contém métodos comuns para todas as classes do pacote de visão.

Quadro 13 – Classes do pacote view .

No Quadro 14 estão apresentadas às classes do pacote controller.codeGenerate .

45

Classes do pacote controller.codeGenerate

O pacote controller.codeGenerate contém as classes responsáveis pela geração do código COBOL.

Classe / Interface Descrição

SqlToCobol

Classe que gera objetos do pacote model.cobolParts , com base em objetos model.sqlParts .

CobolGenerate

Responsável pela geração do código. Efetua a contextualização dos objetos dinâmicos (model.cobolParts ) aos objetos estáticos do template.

Quadro 14 – Classes do pacote controller.codeGenerate .

O Quadro 15 mostra as classes do pacote controller.manager .

Classes do pacote controller.manager

O pacote controller.manager contém as classes responsáveis pelo controle e gerenciamento da visão e modelo da ferramenta.

Classe / Interface Descrição

DataBaseManager Classe responsável pelo controle da visão e modelo no cadastro de bancos de dados.

IOInterface Interface responsável pela declaração dos métodos de entrada e saída de informações do núcleo da ferramenta.

LayoutManager Responsável pelo controle da visão e modelo no cadastro de layout’s, chaves e campos.

ManagerException Classe de exceção do pacote de controller.manager .

OptionsManager Classe responsável pelo controle da visão e modelo na parametrização do sistema.

RunManager

Controlador de execução do núcleo da ferramenta. Responsável por instanciar os analisadores, o gerador de código e executar o arquivo de compilação.

Quadro 15 – Classes do pacote controller.manager .

O pacote controller.xml contém a classe Xml, responsável pela leitura e gravação de

objetos em arquivos XML. Por fim, o pacote controller.analyzer contém as classes

responsáveis pelas análises léxica, sintática e semântica.

3.4.5 Especificação da BNF

A ferramenta interpreta instruções de consulta SQL simples, desta forma ignorando

46

comandos DDL, comandos DML de inserção, alteração e exclusão de registros.

A BNF empregada na confecção da ferramenta aqui apresentada é adaptada da

utilizada no trabalho final da disciplina Bancos de Dados II11, sendo excluídas as cláusulas

para agrupamento, ordenação e subconsultas.

O Quadro 16 apresenta as definições regulares da BNF.

Digit : [0-9] minuscula : [a-z] maiuscula : [A-Z] Letter : {maiuscula}|{minuscula} noQuote : [^"'"\n\r] COMMENT : "/*"[^"*"]*"*/" WS : [\s\t\n\r] ident : {Letter} ( {Letter} | {Digit} )* integer_ : {Digit} ( {Digit} )* float_ : {Digit} {Digit}* ("." {Digit} {Digit}* )? SQLString : "'" {noQuote}* "'"

Quadro 16 – Definições regulares da BNF

A expressão regular Digit refere-se aos dígitos de zero a nove. A expressão regular

minuscula representa os caracteres minúsculos do conjunto de caracteres do alfabeto. Por sua

vez maiuscula refere-se aos caracteres em maiúsculo do alfabeto e Letter um caractere

alfanumérico. A expressão regular noQuote representa os caracteres desconsiderados na

varredura léxica e COMMENT refere-se aos comentários. Tem-se também a expressão regular

ident , que simboliza um identificador, integer _, que representa um número inteiro, float _,

que refere-se a um número de ponto flutuante e SQLString , que representa uma cadeia de

caracteres.

A linguagem também possui palavras reservadas e caracteres especiais, mostrados no

Quadro 17.

11 Disciplina ministrada pelo professor Alexander Roberto Valdameri em 2005/1 e trabalho final desenvolvido juntamente com o aluno Maicon Klug, no curso de Ciências da Computação da Universidade Regional de Blumenau.

47

// Palavras reservadas ALL = ident : "ALL" FROM = ident : "FROM" SELECT = ident : "SELECT" DISTINCT = ident : "DISTINCT" WHERE = ident : "WHERE" HAVING = ident : "HAVING" ORDER = ident : "ORDER" GROUP = ident : "GROUP" BY = ident : "BY" COUNT = ident : "COUNT" SUM = ident : "SUM" MAX = ident : "MAX" MIN = ident : "MIN" AVG = ident : "AVG" NULL = ident : "NULL" DESC = ident : "DESC" ASC = ident : "ASC" NOT = ident : "NOT" AND = ident : "AND" OR = ident : "OR" LIKE = ident : "LIKE" ESCAPE = ident : "ESCAPE" IS = ident : "IS" BETWEEN = ident : "BETWEEN" IN = ident : "IN" DESCRIBE = ident : "DESCRIBE" //Caracteres especiais "(" ")" "*" "+" "," "-" "." "/" ":" ";" "<" "=" ">" "<>" "<=" ">=" "'"

Quadro 17 – Palavras reservadas e caracteres especiais

A gramática referente ao comando describe é apresentada no Quadro 18.

<Comando> ::= <SelectStmt> | <Describe> ; <Describe> ::= DESCRIBE ident #2 | DESC ident #2 ;

Quadro 18 – Gramática referente ao comando describe

É apresentada no Quadro 19 a gramática referente ao comando select.

48

<Comando> ::= <SelectStmt> | <Describe> ; <SelectStmt> ::= <SelectClause> <FromClause> <Where Opcional> #35 ; <SelectClause> ::= SELECT #1 <SelectFieldList> ; <SelectFieldList> ::= <SelectField> <SeparatorSelec tField> ; <SeparatorSelectField> ::= "," <SelectField> <Separ atorSelectField> | î ; <SelectField> ::= <Expression> | "*" ; <FromClause> ::= FROM <FromTableList> ; <FromTableList> ::= <QualifiedTable> <QualifiedRepe te> ; <QualifiedRepete> ::= <JoinSeparator> <QualifiedRep ete> | î ; <JoinSeparator> ::= <QualifiedSeparator> ; <QualifiedSeparator> ::= "," <QualifiedTable> ; <QualifiedTable> ::= ident #29 ; <WhereOpcional> ::= WHERE #46 <Expression> | î ; <Expression> ::= <SimpleExpression> <RelSimpleExp> ; <RelSimpleExp> ::= <Relation> #34 <SimpleExpression > <RelSimpleExp> | î ; <SimpleExpression> ::= <RepeteOperator> ; <RepeteOperator> ::= <WordOperator> <Field> <Repete Operator> | î ; <WordOperator> ::= AND | OR ; <Relation> ::= "=" | "<>" | "<" | "<=" | ">" | ">=" ; Nota: O símbolo î representa o conjunto vazio.

Quadro 19 – Gramática referente ao comando select

O comando informado pode ser uma descrição ou uma seleção de layout (identificador

lógico para um arquivo de dados COBOL), sendo a descrição representada pelo símbolo não

terminal <Describe> e a seleção representada pelo símbolo não terminal <SelectStmt> .

O símbolo não terminal <SelectStmt> é seguido dos não terminais <SelectClause> ,

<FromClause> e <WhereOpcional> , sendo este seguido pela palavra reservada WHERE e pelo

não terminal <Expression> , que refere-se a uma expressão de restrição.

49

3.2.4 Estrutura básica do código COBOL

O código COBOL deve obedecer um padrão semântico para atender a solicitação do

comando SQL informado pelo usuário. Desta maneira o mesmo deve efetuar a leitura correta

dos arquivos, executar o produto cartesiano e efetuar a gravação do arquivo de resultado,

sendo este de acordo com a projeção informada no comando SQL. Esta sessão representa o

primeiro passo na geração de código, referindo-se ao código de testes.

No Quadro 20 é apresentada uma fragmentação de código COBOL para declaração da

estrutura dos arquivos.

*> Program identification identification division. program-id. Programa-exemplo. *> Enviroment division environment division. special-names. decimal-point is comma. select fd-arquivo assign to disk "c:\arquivo .dat" . . . file status is ws-result-access. select al-resultado assign to disk "c:\resul tado.csv" . . . file status is ws-result-access. *> Data division data division. fd $fd-arquivo. . . . fd al-resultado. . . . *> Working storage section working-storage section. . . .

Quadro 20 – Exemplo de código COBOL para declaração da estrutura dos arquivos

O código de saída deve conter os select file para os arquivos (layout’s) informados

no comando SQL e também para o arquivo de resultado (que possui os campos da projeção).

50

Da mesma forma deve conter os file descriptor para os layout’s informados no comando

e para o arquivo de resultado.

O Quadro 21 mostra uma fragmentação de código para efetuar o produto cartesiano e a

gravação do arquivo de resultado.

*> Procedure division procedure division. . . . 2000-process section. 2000-begin. . . . perform 2060-filterresult . . . 2000-exit. exit. 2060-filterresult section. 2060-begin. . . . perform 2050-writeresultfile . . . 2060-exit. exit. 2050-writeresultfile section. 2050-begin. move al-cliente-codigo to al-resultado -codigo . . . write al-resultado. 2050-exit. 2050.

Quadro 21 – Exemplo de código COBOL para o produto cartesiano e gravação do arquivo de resultado

Neste exemplo, a section 2000-process efetua o produto cartesiano dos arquivos

utilizados no comando SQL. A section 2060-filterresult efetua a restrição dos registros e

a section 2050-writeresultfile move o conteúdo dos arquivos selecionados para a

projeção, gravando o arquivo de resultado.

51

3.4.5 Especificação do gerador de código

O segundo passo para a geração de código é a especificação do gerador, onde tem-se a

especificação da entrada, de processamento desta e apresentação da saída. Para ilustrar esta

especificação é apresentado o fluxograma do processo de geração de código na Figura 8.

ad Fluxograma da geração de código

Início

Gera objetosmodel.cobolParts.*

Invoca o motor detemplates

Contextualiza objetos aotemplate / processa

template

Grava o código de saídaem arquivo

Final

Figura 8 – Fluxograma do processo de geração de código

Inicialmente parte-se do princípio de que o comando de consulta SQL já tenha sido

digitado pelo usuário e que este já tenha sido mapeado em objetos model.sqlParts

(consequentemente também enviados ao gerador de código). A partir desses, o gerador de

código constrói objetos do pacote model.cobolParts e invoca o motor de templates. Em

seguida estes objetos são contextualizados ao template, que é processado pelo motor. Por fim,

o código de saída gerado por este processo é gravado em arquivo para posterior compilação.

3.3 IMPLEMENTAÇÃO

A seguir são mostradas as técnicas e ferramentas utilizadas, a implementação da

ferramenta e a operacionalidade da mesma.

52

3.3.1 Técnicas e ferramentas utilizadas

A ferramenta foi desenvolvida utilizando o padrão de projetos MVC, sendo

implementada na linguagem de programação Java. Foi utilizado o ambiente de

desenvolvimento Eclipse, juntamente com a biblioteca gráfica SWT e o JDK versão 1.5.0. Foi

utilizado o motor de templates Velocity através da biblioteca velocity-1.4.jar e para a

geração das classes responsáveis pelas análises léxica e sintática a ferramenta GALS. Para a

compilação do código de saída foi utilizado o compilador COBOL Micro Focus NetExpress

3.1.

3.3.2 Implementação da ferramenta

Esta sessão apresenta a implementação das classes que compõem a ferramenta,

mostrando trechos de código fonte e explicação sobre os mesmos. Está dividida em

armazenamento do metadados, implementação da camada de visão, implementação da

camada de modelo, implementação das classes controladoras, implementação dos

analisadores, implementação da geração de código e definição do template.

3.3.2.1 Armazenamento do metadados

O metadados é formado por arquivos XML, sendo cada banco de dados

(model.metadata.DataBase) um arquivo com as propriedades do mesmo. Este arquivo

contém os layout’s (objetos da classe model.metadata.Layout ) do banco, que por sua vez

contém os campos (classe model.metadata.Field ) e as chaves (objetos da classe

model.metadata.Key ). O Quadro 22 apresenta parte do conteúdo do arquivo XML de banco

de dados.

53

<?xml version="1.0" encoding="UTF-8"?> <java version="1.5.0_07" class="java.beans.XMLDecod er"> <object class="model.metadata.DataBase"> <void property="layoutMap"> <void method="put"> <string>PORTIFOLIO</string> <object class="model.metadata.Layout"> <void property="accessType"> <int>1</int> </void> <void property="fieldMap"> <void method="put"> <string>PRCDPRODUTO</string> <object id="Field0" class="model.metadata.Fi eld"> <void property="id"> . . .

Quadro 22 – Parte do conteúdo de um arquivo XML de banco de dados

Para o cadastro de um novo banco de dados é gerado um novo arquivo XML com o

identificador do banco como nome do arquivo. Para o cadastro de um layout, é instanciado

um banco de dados (este carregado de um arquivo XML), inserido o layout no mesmo, e

consequentemente, gravando novamente em disco o arquivo de banco. Da mesma forma, uma

chave ou um campo é inserido em um layout, sendo este por sua vez relacionado a um objeto

de banco para posterior gravação.

A gravação dos parâmetros (objeto da classe model.param.Options ) ocorre da

mesma forma, onde é instanciado um objeto e este é gravado em arquivo XML.

Os arquivos XML utilizados pela ferramenta são basicamente objetos serializados,

sendo utilizados métodos das classes java.beans.XMLDecoder e java.beans.XMLEncoder .

Referente ao metadados são serializados objetos da classe model.metadata.DataBase e nos

parâmetros é serializado um objeto da classe model.params.Options .

3.3.2.2 Implementação da camada de modelo

As classes da camada de modelo estão agrupadas nos pacotes model.cobolParts ,

model.metadata , model.sqlParts e model.params .

Como já citado no capítulo de especificação, as classes do pacote model.cobolParts

representam o mapeamento em objetos de um código fonte COBOL. Possui em seu conjunto

uma classe representando uma variável (classe Variable ), uma classe representando uma

chave (classe RecordKey ), classes representando testes lógicos (classes CobolFilter e

CobolFilterExpression ), classes representando a environment division (classes

54

SelectFile e EnvironmentDivision ) e classes representando a data division

(DataDivision e FileDescriptor ).

Por sua vez, como também comentado no capítulo de especificação, as classes do

pacote model.sqlParts referem-se ao mapeamento em objetos do comando de consulta SQL

informado pelo usuário. O pacote possui a interface Element e as classes Constant ,

Identificator e ElementType (representando estas os identificadores e constantes), as

classes Where, Expression , LogicalOperator e RelationOperator (representando a

cláusula where), e por fim as classes Projection (representando a projeção), Join e Table

(representando a lista de tabelas do comando).

As classes do pacote model.metadata são as utilizadas como metadados para as

análises léxica, sintática e semântica. Dentro do conjunto do pacote estão as classes Layout ,

Field , Key e DataBase , sendo este último serializado em arquivo XML.

Também há a classe model.params.Options , que guarda a parametrização do sistema

(banco de dados padrão, caminho do arquivo de compilação e tempo para time out) e é

também serializada em um arquivo do tipo XML.

A construção das classes da camada de modelo baseou-se simplesmente no

mapeamento de suas características reais em objetos, implementando classes com simples

atributos e seus respectivos métodos getters e setters.

3.3.2.3 Implementação das classes controladoras

As classes controladoras estão divididas em dois grupos distintos: os controladores de

atualização do modelo e o controlador de execução.

Os controladores de atualização de modelo possuem a responsabilidade de

instanciarem um objeto do modelo (carregado de um arquivo XML), encapsular suas

propriedades (atributos) e enviar as mesmas para a camada de visão. Da mesma forma,

encapsulam as propriedades (valores dos componentes) contidas na camada de visão,

instanciam um objeto do modelo e serializam o mesmo em arquivo XML. Estas propriedades

são encapsuladas em um objeto da classe java.util.HashMap , formando um conjunto de

tuplas (identificador de propriedade e valor da propriedade).

No Quadro 23 é apresentada a classe controladora de layout (classe

controller.manager.LayoutManager ) e seus principais métodos.

55

public class LayoutManager { . . . /* * Método que salva um Layout */ public void saveLayout(HashMap <String, Object> va lues) throws MetadataException, IOException { String id = (String)values.get(LayoutManager.L AY_ID); String path = (String)values.get(LayoutManager.L AY_PATH); . . . if (this.defaultLayout == null) this.defaultLayout = new Layout(); this.defaultLayout.setId(id); this.defaultLayout.setPath(this.defaultLayout.va lidPath(path)); . . . Xml.writeObject(this.defaultDataBase, dbDirectory + this.defaultDataBa se.getName()); } /* * Método que determina o database default */ public void setDefaultDataBase(String dbName) throws FileNotFoundException { if (!dbName.equals("")) this.defaultDataBase = (DataBase)Xml.readObje ct( this.dbDirectory + dbName); else this.defaultDataBase = null; } /* * Método que determina o layout default */ public void setDefaultLayout(String layoutId) { this.defaultLayout = this.defaultDataBase.getLay out(layoutId); } /* * Método que carrega um Layout */ public HashMap <String, Object> loadLayout() { HashMap <String, Object> values = new HashMap <St ring, Object> (); if (this.defaultLayout != null) { values.put(LayoutManager.LAY_ID, this.defaultL ayout.getId()); values.put(LayoutManager.LAY_PATH, this.defaul tLayout.getPath()); . . . } return values; } . . .

Quadro 23 – Classe controller.manager.LayoutManager

O método saveLayout(HashMap<String, Object> values) recebe como parâmetro

56

as propriedades de um layout encapsuladas em um objeto da classe java.util.HashMap .

Estas propriedades são desempacotadas e atribuídas a um novo objeto de layout, que por sua

vez é inserido no banco de dados padrão, sendo o mesmo serializado em arquivo XML. No

método loadLayout() , um layout (passando seu identificador como parâmetro através do

método setDefaultLayout(String layoutId) ) é retornado do banco de dados padrão, que

é lido de um arquivo XML. Este layout, por sua vez, tem suas propriedades encapsuladas e

retornadas a camada de visão.

Os demais controladores de atualização do modelo são objetos das classes

controller.manager.DataBaseManager e controller.manager.OptionsManager ,

funcionando da mesma maneira que objetos da classe

controller.manager.LayoutManager . Estes também relacionam-se com a camada de visão

através de atributos empacotados.

O controlador de execução é um objeto da classe controller.manager.RunManager

e possui métodos para invocação dos analisadores léxico, sintático e semântico, para a

geração do código e para a execução do arquivo de compilação.

Dentre seus parâmetros de construção está a interface

controller.manager. IOInterface (mostrada no Quadro 24). A implementação desta

interface é necessária para troca de informações (como as mensagens de erro e a apresentação

do resultado de uma consulta) entre o controlador de execução

controller.manager.RunManager e a classe de visão view.MainShell .

57

package controler.manager; /* * Interface com os métodos necessários para entrad a e saída de informações */ public interface IOInterface { /* * Método que retorna o texto da query */ public String getQueryText(); /* * Método que determina o texto na área de erros */ public void setErrorsArea(String content); /* * Método que limpa a área de resultado */ public void clearResultArea(); /* * Método que determina o cabeçalho área de result ado */ public void setHeaderResultArea(String content); /* * Método que determina o texto da área de mensage m */ public void setMessageText(String content); /* * Método que adiciona um texto na área de resulta do */ public void appendResult(String content); /* * Método que finaliza a leitura do arquivo de res ultado */ public void finalizeRead(); }

Quadro 24 – Interface controller.manager. IOInterface

A principal função da classe controladora de execução é o método process() ,

apresentado no Quadro 25.

58

public class RunManager { . . . public void process() throws ResourceNotFoundException, ParseErrorException, IOException, InterruptedException, ManagerException { boolean isDesc = true; try { this.analyser(); } catch (AnalysisError e) { . . . } for (int i = 0; i < this.args.length; i++) if (this.args[i] != null) isDesc = false; if (!isDesc) { this.codeGenerate(); this.execCmd(this.compCmd); this.readResultFile(); this.deleteFiles(); this.ioInterface.finalizeRead(); } } . . .

Quadro 25 – Método process() da classe controller.manager.RunManager

Inicialmente o método process() invoca os analisadores (léxico, sintático e

semântico) através do método privado analyzer() . Em seguida é verificado se o comando

informado é um descritor de layout. Em caso positivo, o método é finalizado. Caso contrário é

invocada a geração de código, através do método privado codeGenerate() e executado o

arquivo de compilação com o método privado execCmd(String compCmd) . Após executado o

arquivo de compilação é aguardado o arquivo de resultado, através do método

readResultFile() , sendo ao final excluídos os arquivos de controle12 e de resultado com o

método deleteFiles() .

No Quadro 26 são apresentados os principais métodos privados chamados pelo método

process() .

12 O arquivo de controle é gerado pelo executável COBOL para sinalizar o fim da consulta. Após o arquivo de controle gerado é possível iniciar a leitura do arquivo de resultado.

59

public class RunManager { . . . private void analyser() throws AnalysisError, SqlPa rtsException { ioInterface.clearResultArea(); LexiAnalyser lexi = new LexiAnalyser(ioInter face.getQueryText()); SyntAnalyser synt = new SyntAnalyser(); SemantAnalyser sem = new SemantAnalyser(); this.args = synt.parse(lexi, sem, this.dataBase, ioInterface); } private void codeGenerate() throws ResourceNotFoundException, ParseErrorExce ption { CobolGenerate cobolGenerate; try { cobolGenerate = new CobolGenerate(this.args, this.programId, this.resultFullPath, this.resultFdId, this.ctrlFullPath, this.ctrlFdId, this.dataBase, this.codeFullPath, this.templateName); cobolGenerate.generate(); this.ioInterface.setHeaderResultArea(cobolGenerate .getHeaderResult()); . . . private void execCmd(String cmd) throws IOException { Runtime.getRuntime().exec("rundll32 SHELL32.DLL, ShellExec_RunDLL " + cmd); }

Quadro 26 – Principais métodos privados chamados pelo método process() da classe controller.manager.RunManager

O método analyser() instancia um analisador léxico (classe

controller.analyser.LexiAnalyser ) passando como parâmetro o conteúdo do comando

de consulta SQL (através do método getQueryText() implementado pela classe de visão

view.MainShell ). Também instancia um analisador sintático (classe

controller.analyser.SyntAnalyser ) e um analisador semântico (classe

controller.analyser.SemantAnalyser ). Em seguida é invocado o método parse() do

analisador sintático, que retorna um vetor com objetos pertencentes às classes do pacote

model.sqlParts .

Para geração do código de saída COBOL é utilizado o método codeGenerate() . Este

instancia um objeto da classe controller.codeGenerate.CobolGenerate , passando entre

seus parâmetros o vetor de objetos model.sqlParts (adquirido através do método

analyser() ).

Por fim, o método execCmd(String cmd) executa o arquivo de compilação após a

geração do código de saída recebendo como parâmetro o caminho do arquivo.

60

3.3.2.4 Implementação da camada de visão

A camada de visão é responsável pela interação entre o núcleo da ferramenta e seus

usuários, sendo composta por classes de cadastro e a classe main da aplicação. Para cada

classe de cadastro existe um controlador, sendo este instanciado e tendo seus métodos

invocados para gravação e leitura dos arquivos XML pertinentes.

Tem-se como exemplo o cadastro de um layout. Ao salvar um layout as informações

(atributos do mesmo) contidas em tela são empacotadas em um objeto da classe

java.util.HashMap e passadas ao controlador para gravação. Da mesma forma, quando

requer-se a visualização de um layout, é efetuada uma solicitação ao controlador, que por sua

vez carrega o arquivo XML de banco de dados. Deste arquivo é capturado o layout pertinente,

sendo empacotados os seus atributos e retornados a camada de visão. O Quadro 27 mostra

estes métodos aplicados na classe de cadastro de layout (view.LayoutShell ).

61

public class LayoutShell { . . . /* * Método para salvar o layout */ private void saveLayout() throws ManagerException, IOException, MetadataException, ViewException { if (this.dbChoiseCombo.getText().equals("")) throw new ViewException("Selecione um banco de dad os"); HashMap <String, Object> values = new HashMap <S tring, Object> (); values.put(LayoutManager.LAY_ID, this.layIdText. getText()); values.put(LayoutManager.LAY_PATH, this.layPathT ext.getText()); . . . this.layoutManager.saveLayout(values); this.cleanDisplay(); } . . . /* * Método que carrega os valores do layout para tel a */ private void showLayout() throws ManagerException, ViewException { this.fieldTable.clearAll(); this.keyTable.clearAll(); this.layoutManager.setDefaultLayout(this.layChoi seCombo.getText()); HashMap <String, Object> values = this.layoutMan ager.loadLayout(); this.layIdText.setText((String)values.get(Layout Manager.LAY_ID)); this.layPathText.setText((String)values.get(Layo utManager.LAY_PATH)); . . .

Quadro 27 – Invocando métodos do controlador controller.manager.LayoutManager (leitura e gravação)

O método saveLayout() , pertencente a classe view.LayoutShell , instancia um

objeto da classe java.util.HashMap e adiciona neste os atributos do layout (contidos em

tela), formando a tupla identificador do atributo e valor do atributo. Em seguida invoca o

método saveLayout(HashMap<String, Object> values) do gerenciador de layout’s

(classe controller.manager.LayoutManager ), passando como parâmetro as propriedades

(atributos) encapsuladas no HashMap anterior. Da mesma forma o método showLayout()

apresenta as informações de um layout em tela, invocando o método loadLayout() (da

classe controller.manager.LayoutManager ) que retorna os atributos do layout em um

HashMap. Após os atributos carregados, os mesmos são movidos aos componentes da classe

62

de visão (no caso a classe view.LayoutShell ) e apresentadas em tela.

As demais classes de cadastro funcionam de maneira semelhante à citada, invocando

métodos de seus respectivos controladores para leitura e gravação.

Outro componente da camada de visão é a classe view.MainShell , que contém o

método main da aplicação. Esta proporciona a digitação dos comandos de consulta SQL e a

apresentação dos resultados destas consultas.

A classe view.MainShell também instancia um controlador, sendo este um objeto da

classe controller.manager.RunManager (controlador de execução da ferramenta). Para

utilizar este controlador é necessário implementar a interface

controller.manager. IOInterface. Esta implementação é mostrada no Quadro 28.

63

public class MainShell implements IOInterface { . . . public void appendResult(String content) { this.resultTable.setLinesVisible(true); TableItem item = new TableItem(this.resultTable, SWT.NONE); StringTokenizer tokens = new StringTokenizer(con tent, ";"); int counter = 0; while (tokens.hasMoreTokens()) { item.setText(counter, tokens.nextToken()); counter++; } } public void clearResultArea() { this.tabFolder.setSelection(0); this.resultTable.removeAll(); this.resultTable.setLinesVisible(false); int x = this.resultTable.getColumnCount(); for (int i = 0; i < x; i++) this.resultTable.getColumn(0).dispose(); this.setMessageText(""); } public String getQueryText() { return this.queryTextArea.getText(); } public void setErrorsArea(String content) { this.tabFolder.setSelection(1); this.messageTextArea.setText(content); } public void setHeaderResultArea(String content) { this.tabFolder.setSelection(0); StringTokenizer tokens = new StringTokenizer(con tent, ";"); while (tokens.hasMoreTokens()) { TableColumn column = new TableColumn(this.res ultTable, SWT.NONE); column.setText(tokens.nextToken()); } } public void setMessageText(String content) { this.tabFolder.setSelection(1); this.messageTextArea.setText(content); } public void finalizeRead() { for (int i = 0; i < this.resultTable.getColumnCo unt(); i++) this.resultTable.getColumn(i).pack(); } . . .

Quadro 28 – Implementação da interface controller.manager. IOInterface pela classe view.MainShell

O método appendResult(String content) adiciona uma linha na grid de resultado

separando os campos por ponto-e-vírgula. O método setHeaderResultArea(String

content) determina o cabeçalho (nome das colunas) da área de resultado e o método

clearResultArea() apaga todo o mesmo. O método getQueryText() retorna o conteúdo da

área de digitação de consultas, o método setErrorsArea() determina o conteúdo da área de

64

erros e o método setMessageText() determina o conteúdo da área de mensagens. Ainda, o

método finalizeRead() serve como indicador de final de leitura (no caso leitura do arquivo

de resultados).

Por fim, quando solicitada uma consulta é invocado o método process() do

controlador de execução.

3.3.2.5 Implementação dos analisadores (léxico, sintático e semântico)

Como já comentado na sessão de técnicas e ferramentas utilizadas, usou-se a aplicação

GALS para geração dos analisadores léxico e sintático (com base na BNF citada no capítulo

de especificação) e implementou-se as ações semânticas.

Apesar do GALS gerar com precisão as classes para análise léxica e sintática, foram

efetuadas alterações nas classes controller.analyser.SyntAnalyser (analisador sintático)

e controller.analyser.SemantAnalyser (analisador semântico) para encaixarem-se no

contexto da ferramenta aqui apresentada.

As alterações no código fonte dos analisadores estão apresentadas no Quadro 29.

65

.

.

. public class SyntAnalyser implements Constants public Object[] parse(LexiAnalyser scanner, SemantAnalyser semanticAna lyser, DataBase db, IOInterface ioInterface) throws AnalysisError, SqlPartsException { this.semanticAnalyser = semanticAnalyser; this.semanticAnalyser.setDb(db); this.semanticAnalyser.setIOInterface(ioInterf ace); this.semanticAnalyser.init(); . . . return this.semanticAnalyser.getArgs(); } } public class SemantAnalyser implements Constants { private DataBase db; private IOInterface ioInterface; private SemanticActions semanticActions; public void setDb(DataBase db) { this.db = db; } public void setIOInterface(IOInterface ioInterfa ce) { this.ioInterface = ioInterface; } public void init() { this.semanticActions = new SemanticActions(th is.db, this.ioInterface); } . . . public Object[] getArgs() { return this.semanticActions.mountReturn(); } }

Quadro 29 – Alterações no código gerado pela ferramenta GALS

A classe controller.analyser.SyntAnalyser foi alterada para receber, além do

analisador léxico e semântico, o banco de dados padrão e a interface

controller.manager. IOInterface (implementada pela classe view.MainShell ). Isto para

possibilitar a análise sob o banco de dados parametrizado e poder retornar o conteúdo de uma

descrição de layout (no caso da interface passada como parâmetro), visto que o retorno da

função parse() é um vetor de objetos do pacote model.sqlParts . A classe citada invoca os

analisadores léxico (controller.analyser.LexiAnalyser ) e semântico

(controller.analyser.SemantAnalyser ).

Na classe controller.analyser.SemantAnalyser foram inseridos os atributos de

banco de dados, a interface controller.manager. IOInterface (determinados estes pelos

66

métodos setDb(DataBase db) e setIOInterface(IOInterface ioInterface) sendo

chamados pelo analisador sintático) e o objeto da classe

controller.analyser.SemanticActions , instanciado pelo método init() e também

invocado pelo analisador sintático.

Foi criada a classe controller.analyser.SemanticActions para tratar as ações

semânticas recebidas pelo método executeAction(int action, Token token) da classe

controller.manager.SemantAnalyser , podendo este ser observado no Quadro 30.

public class SemantAnalyser implements Constants { . . . public void executeAction(int action, Token toke n) throws AnalysisError, SqlPartsException { switch (action) { case 1: this.semanticActions.action01(); break; case 2: this.semanticActions.action02(token); break; . . . case 96: this.semanticActions.action96(token); break; default: break; } } . . .

Quadro 30 – Método executeAction(int action, Token token) pertencente a classe controller.analyser.SemantAnalyser

O método executeAction(int action, Token token) recebe o código da ação

semântica a ser executada e invoca o método correspondente no objeto da classe

controller.analyser.SemanticActions , que efetua a análise (embasado no objeto de

banco de dados recebido no construtor) correspondente aquela ação.

Este método correspondente pode receber ou não um token conforme visualizado no

Quadro 31, que mostra a ação semântica responsável pela verificação da existência de um

layout informado no comando de consulta SQL.

67

public class SemanticActions { . . . /* * Ação que verifica a existência de determinado La yout */ public void action29(Token token) throws AnalysisEr ror, SqlPartsException { String str = token.getLexeme(); Layout layout = this.dataBase.getLayout(str); if (layout == null) throw new AnalysisError(str + " inexistente n o DataBase"); Table table = new Table(str); this.join.add(table); } . . . /* * Método que monta o retorno das ações semânticas */ public Object[] mountReturn() { Object[] args = {this.projection, this.join, this.where, this.having, this.groupBy, this.orderBy}; return args; } . . .

Quadro 31 – Método correspondente à ação semântica responsável pela verificação da existência de um layout

Neste caso, a ação carrega do seu objeto de banco de dados o layout correspondente

(através do token passado como parâmetro) e se o mesmo for nulo é disparada exceção. Se o

mesmo existir é instanciado um objeto da classe model.sqlParts.Table e inserido no

atributo join (model.sqlParts.Join ).

Após a execução de todas as ações semânticas do comando informado é invocado o

método mounReturn() , que retorna um vetor com objetos model.sqlParts , resultantes da

análise semântica. Este vetor por sua vez é retornado ao método parse() do analisador

sintático, que retorna também ao controlador de execução para posterior geração do código de

saída.

3.3.2.6 Implementação da geração de código

A geração de código está basicamente implementada em duas classes: classe

controller.codegenerate.SqlToCobol e classe

controller.codegenerate.CobolGenerate . Esta sessão trata do terceiro passo na geração

68

de código, que é a implementação do processamento da entrada.

A classe controller.codegenerate.SqlToCobol é responsável por efetuar o parser

entre objetos pertencentes as classes do pacote model.sqlParts e objetos pertencentes as

classes do pacote model.cobolParts . Parte da classe citada é apresentada no Quadro 32, que

mostra o método getDataDivision() .

public class SqlToCobol { . . . /* * Método que retorna o Data Division */ public DataDivision getDataDivision() { DataDivision dataDivision = new DataDivision(); LinkedList <FileDescriptor> fdList = new LinkedL ist <FileDescriptor> (); for (int i = 0; i < this.join.getSize(); i++) { Layout layout = this.dataBase.getLayout(this. join.get(i).getValue()); FileDescriptor fileDescriptor = new FileDescr iptor(); fileDescriptor.setType(FileDescriptor.LAYOUT_ FD); fileDescriptor.setFdId(layout.getId()); fileDescriptor.setVariableList(this.getVariab leFieldList("", layout.toField Array(), true)); fdList.add(fileDescriptor); } FileDescriptor resultFileDescriptor = new FileDe scriptor(); resultFileDescriptor.setFdId(this.resultFdId); resultFileDescriptor.setType(FileDescriptor.RESU LT_FD); resultFileDescriptor.setVariableList(this.getVar iableProjectionList("wrs-")); fdList.add(resultFileDescriptor); FileDescriptor ctrlFileDescriptor = new FileDesc riptor(); ctrlFileDescriptor.setType(FileDescriptor.CTRL_F D); ctrlFileDescriptor.setFdId(this.ctrlFdId); ctrlFileDescriptor.setVariableList(this.getVaria bleCtrlList("ctrl-")); fdList.add(ctrlFileDescriptor); dataDivision.setFdList(fdList); return dataDivision; } . . .

Quadro 32 – Parte da classe controller.codegenerate.SqlToCobol

O método apresentado retorna um objeto da classe model.cobolParts.DataDivision

a partir de objetos da classe model.sqlParts.Join (passado como parâmetro no construtor)

e da classe model.sqlParts.projection (passado também como parâmetro no construtor).

Inicialmente é efetuada uma iteração no objeto de Join , sendo percorridas todas as

suas tabelas (objetos da classe model.sqlParts.Table ). A partir de cada tabela é criado um

objeto da classe model.coboParts.FileDescriptor , adicionando suas propriedades a partir

do objeto de layout correspondente (carregado este do banco de dados). Em seguida, a partir

69

do objeto de Projection é criado um outro objeto de FileDescriptor , representando o

resultado da consulta. Também é criado um FileDescriptor de controle, para identificar o

final da geração do arquivo de resultado. Por fim todos os objetos de FileDescriptor são

adicionados ao objeto de DataDivision , que é o retorno do método.

Os demais métodos da classe SqlToCobol funcionam de maneira semelhante,

efetuando a conversão de objetos model.sqlParts (resultantes da análise semântica) para

objetos model.cobolParts .

A classe controller.codegenerate.CobolGenerate é a responsável pela geração

do código COBOL, sendo apresentada no Quadro 33.

public class CobolGenerate { . . . public void generate() throws ResourceNotFoundException, ParseErrorE xception, Exception { this.assocContext(); this.mainTemplate = this.vEngine.getTemplate( this.templateName); StringWriter writer = new StringWriter(); this.mainTemplate.merge(this.vContext, writer ); this.writeInFile(writer); } private void assocContext() { this.vContext.put("identificationDivision", this.sqlToCobol.getIdentifi cationDivision()); this.vContext.put("dataDivision", this.sqlToCobol.getDataDivi sion()); this.vContext.put("environmentDivision", sqlToCobol.getEnvironmentDi vision()); this.vContext.put("cobolFilter", this.sqlToCo bol.getCobolFilter()); this.vContext.put("movePart", this.sqlToCobol .getMovePart()); } private void writeInFile(StringWriter content) t hrows IOException { File outputFile = new File(this.codeFull Path); FileOutputStream out = new FileOutputStream(o utputFile); String result = content.toString(); out.write(result.getBytes()); out.close(); }

Quadro 33 – Classe controller.codegenerate.CobolGenerate

Para explicação desta classe, parte-se da premissa de que a mesma já esteja instanciada

pelo controlador de execução, possuindo um vetor com objetos model.sqlParts e o caminho

do arquivo para geração de código. Também possui-se instanciado um objeto da classe

controller.codegenerate.SqlToCobol (passando como parâmetro os objetos

model.sqlParts ). Após, é invocado pelo controlador de execução o método público

generate() , que associa as variáveis dinâmicas (no caso, o resultado da invocação dos

métodos da classe SqlToCobol ) as variáveis estáticas. Em seguida, é instanciado o motor de

templates (passando como parâmetro o template definido, sendo este um dos parâmetros de

70

construção da classe) e logo após efetuado a contextualização das variáveis dinâmicas as

variáveis estáticas, sendo gerado código COBOL. Por fim, o mesmo é gravado em arquivo.

3.3.2.7 Definição do template

O template utilizado para geração do código COBOL de saída é embasado no

compilador Micro Focus NetExpress 3.1. É importante lembrar que para a utilização de outro

compilador o template deverá ser revisado. Esta sessão refere-se ao quarto passo na geração

de código, que é a definição dos templates (HERRINGTON 2003, p. 93).

O Quadro 34 mostra parte do conteúdo do template (arquivo mainTemplate.vm)

referente a identification division e environment division .

*> Cobol Auto-Generated Program *> Program identification identification division. program-id. $identificationDivision.getProgr amId(). *> Enviroment division environment division. special-names. decimal-point is comma. #foreach($selectFile in $environmentDivision .getSelectFileList()) select $selectFile.getFdId() assign to disk wid-$selectFile.getFdId() organization is $selectFile.getOrgan ization() access mode is $selectFile.getAcces sMode() #foreach($recordKey in $selectFile.ge tKeyList()) #if ($recordKey.getType().equalsIgnor eCase("primary key")) record key is #else alternate key is #end $recordKey.getK eyId() = #foreach($fieldsId in $recordKey.ge tFieldsId()) $fieldsId.toString() #end #end lock mode is manual file status is ws-result-access. #end

Quadro 34 – Identification division e environment division do arquivo mainTemplate.vm

Na identification division o program-id é retornado a partir do método

getProgramId() da diretiva $identificationDivision .

Para montagem do environment division , é efetuada um iteração na diretiva

$environmentDivision , percorrendo a sua lista de objetos SelectFile , sendo invocados

métodos dos mesmos para o preenchimento das propriedades.

No Quadro 35 é apresentada parte do conteúdo do template referente à data

division e working-storage section .

71

*> Data division data division. #set($counter = 0) #foreach($fileDescriptor in $dataDivision.ge tFdList()) fd $fileDescriptor.getFdId(). #if ($fileDescriptor.getType().equals("RE SULT_FD")) #foreach($variable in $fileDescriptor.getVa riableList()) #set($counter = $counter + 1) #if ($counter == 1) 01 wrs-$fileDescriptor.getFdId(). #end $variable.toString(). #if ($counter != $fileDescriptor.g etVariableList().size()) 03 filler value ";". #end #end #else #foreach($variable in $fileDescriptor.g etVariableList()) $variable.toString(). #end #end #end *> Working storage section working-storage section. 01 ws-working-fields. 03 ws-result-access pic X(2). 88 ws-operation-ok value "00" "02 ". #foreach($selectFile in $envi ronmentDivision.getSelectFileList()) 03 wid-$selectFile.getFdId() pic X(100 ). #end

Quadro 35 – Data division e working-storage section do arquivo mainTemplate.vm

Para geração do data division é efetuada iteração na diretiva $dataDivision , sendo

esta a lista de file descriptors do objeto model.cobolParts.DataDivision . Assim,

para cada objeto desta iteração é invocado o método toString() de suas variáveis. Por sua

vez, na construção da working-storage section é utilizado a lista de objetos selectFile

da diretiva $environmentDivision .

O controle principal do programa gerado é definido pela sessão 0000-control no

arquivo de template, sendo apresentada esta no Quadro 36.

0000-control section. 0000-begin. perform 1000-init perform 2000-process perform 3000-finish. 0000-exit. exit program. stop run.

Quadro 36 – Sessão 0000-control do arquivo mainTemplate.vm

A sessão 0000-control (no código gerado) tem a responsabilidade de invocar as

sessões 1000-init (que inicializa os arquivos), 2000-process (que efetua o processamento)

e 3000-finish (que fecha os arquivos e grava o arquivo de controle, sinalizando o final do

processamento).

72

A construção das sessões 1000-init , 2000-process e 3000-finish são apresentadas

no Quadro 37.

1000-init section. 1000-begin. #foreach($selectFile in $environmentDivisio n.getSelectFileList()) #if (!$selectFile.getType().equalsIgnoreCas e("CTRL_SF")) move "$selectFile.getFilePath()" to wid- $selectFile.getFdId(). open $selectFile.getOpenType() $selectFi le.getFdId(). #end #end 1000-exit. exit. 2000-process section. 2000-begin. #foreach($selectFile in $environmentDivisio n.getSelectFileList()) #if ($selectFile.getOpenType().equalsIgno reCase("i- o")) initialize $dataDivision.getFDVariable($ selectFile.getFdId()).getId() #if (!($selectFile.getOrganization().equalsIg nore Case("line sequential"))) $selectFile.getCobolStart() #else open $selectFile.getOpenType() $selectFi le.getFdId() #end read $selectFile.getFdId() next perform until not ws-operation-ok #end #end perform 2060-filterresult #set($index = $dataDivision.getLayoutFDLis t().size()) #foreach($fileDescriptor in $dataDivision. getLayoutFDList()) #set($index = $index - 1) read $dataDivision.getLayoutFDList().get ($index).getFdId() next #if ($index == 0) end-perform. #else end - perform #end #end 2000-exit. exit. 3000-finish section. 3000-begin. #foreach($selectFile in $environmentDivisi on.getSelectFileList()) #if ($selectFile.getType().equalsIgnore Case("CTRL_SF")) move "$selectFile.getFilePath()" to w id-$selectFile.getFdId(). open $selectFile.getOpenType() $selec tFile.getFdId(). #end #end write ctrl-ctrlOne. #foreach($selectFile in $environmentDivis ion.getSelectFileList()) close $selectFile.getFdId(). #end 3000-exit. exit.

Quadro 37 – Sessões 1000-init , 2000-process e 3000-finish do arquivo mainTemplate.vm

A sessão 1000-init , como já citado efetua a inicialização (ou abertura) dos arquivos

de dados e do arquivo de resultado. O arquivo de controle não é aberto nesta sessão, como

observado no teste #if (!$selectFile.getType().equalsIgnoreCase("CTRL_ SF")) . A

sessão 2000-process (embasada na diretiva $environmentDivision ) efetua o produto

cartesiano dos arquivos de dados, invocando a sessão 2060-filterresult . Por sua vez, a

sessão 3000-finish fecha todos os arquivos utilizados. Contudo, o arquivo de controle é

73

aberto e gravado nesta sessão.

No Quadro 38 são apresentadas as demais sessões COBOL presentes no arquivo de

templates.

2060-filterresult section. 2060-begin. #if ($cobolFilter.toString().equals("")) perform 2050-writeresultfile. #else if $cobolFilter.toString() perform 2050-writeresultfile end-if. #end 2060-exit. exit. 2050-writeresultfile section. 2050-begin. #set($index = 0) #foreach($moveDestiny in $movePart.getDes tinyVariableList()) move $movePart.getSourceVariableList() .get($index).getId() to $moveDestiny.getId(). #set($index = $index + 1) #end #foreach($fileDescriptor in $dataDivision .getFdList()) #if ($fileDescriptor.getType().equals("RE SULT_FD")) write wrs-$fileDescriptor.getFdId(). #end #end 2050-exit. 2050.

Quadro 38 – Demais sessões COBOL do arquivo mainTemplate.vm

A sessão 2060-filterresult é responsável por efetuar o filtro dos registros lidos.

Caso não haja filtro (se não houver where no comando de consulta SQL informado) é

invocada diretamente a sessão 2050-writeresultfile . Caso contrário é chamado, a partir da

diretiva $cobolFilter , o comando if referente a restrição SQL, sendo chamada dentro do

escopo do mesmo a sessão 2050-writeresultfile . Esta move o conteúdo da projeção do

comando informado para as variáveis do file descriptor de resultado, que por sua vez é

gravado.

3.3.3 Operacionalidade da implementação

Nesta sessão é apresentada a operacionalidade da ferramenta, sendo criada uma base

de dados de testes para a demonstração da mesma. Também foi configurado o arquivo de

compilação utilizando a aplicação Micro Focus NetExpress 3.1, responsável por compilar o

código de saída, gerar o arquivo binário e executá-lo.

74

Partindo da premissa que o template para geração do código de saída já está definido, o

usuário deverá em seguida configurar o arquivo de compilação. É apresentado no Quadro 39 o

conteúdo do arquivo de compilação utilizado para os testes da ferramenta.

@echo off @c: @cd\Arquiv~1\MF\ @C:\Arquiv~1\MF\COBOL.EXE c:\temp\CobolQuery\Code\a cCode.cbl, c:\temp\CobolQuery\Code\acCode.obj, c:\temp\CobolQuery\Code\acCode.lst, c:\temp\CobolQuery\Code\acCode.gpr @C:\Arquiv~1\MF\CBLLINK.EXE c:\temp\CobolQuery\Code \acCode.obj @C:\Arquiv~1\MF\acCode.exe . . .

Quadro 39 – Conteúdo do arquivo de compilação

O aplicativo COBOL.EXE é responsável por compilar o código de saída acCode.cbl ,

gerando o código objeto acCode.obj . Na seqüência o aplicativo CBLLINK.EXE gera o arquivo

binário (a partir do arquivo acCode.obj ) acCode.exe que em seguida é executado. Este

processo é transparente para a ferramenta, pois a mesma gera o arquivo acCode.cbl (com

base no template) e aguarda o arquivo de resultado.

Após o arquivo de compilação configurado o usuário pode iniciar o processo de

configuração da ferramenta (cadastro do metadados e parametrização do sistema). Na Figura

9 é mostrada a ferramenta Cobol Query 1.0.

75

Figura 9 – Cobol Query 1.0

O usuário primeiramente deverá cadastrar um banco de dados, gerando assim um

arquivo XML referente ao metadados. Na figura 10 é apresentado o cadastro de banco de

dados.

Figura 10 – Cadastro de banco de dados

Após o banco de dados cadastrado é possível o cadastro de um layout (Figura 11).

76

Figura 11 – Cadastro de layout

No cadastro de layout é possível o cadastramento de campos (Figura 12). Também é

possível o cadastro de chaves (Figura 13).

Figura 12 – Cadastro de campo

77

Figura 13 – Cadastro de chave

Após o cadastro de um campo ou uma chave é atualizada a tabela de campos (ou a de

chaves) no cadastro de layout (Figura 14).

78

Figura 14 – Atualização das tabelas de campos e de chaves

Com o metadados cadastrado é possível a parametrização do sistema, onde é

informado o banco de dados padrão, o caminho do arquivo de compilação e o tempo para time

out.

A parametrização do sistema é apresentada na Figura 15.

Figura 15 – Parametrização do sistema

Após o metadados cadastrado e o sistema parametrizado pode-se utilizar a ferramenta,

79

efetuando comandos de consulta SQL. Quando efetua-se uma consulta o resultado é

apresentado em forma de grid (Figura 16).

Figura 16 – Consulta na ferramenta

Há também a possibilidade do usuário cometer erros no comando informado. Quando

estes erros ocorrem os mesmos são apresentados na guia mensagens (Figura 17).

80

Figura 17 – Mensagens de erro durante uma consulta

Por fim, a descrição de layout’s também é apresentada ao usuário na guia mensagens

(Figura 18).

81

Figura 18 – Exemplo de descrição de layout

3.4 RESULTADOS E DISCUSSÃO

Inicialmente é importante relatar que a ferramenta gera código COBOL com

funcionalidade equivalente ao comando de consulta SQL de entrada e também com o código

de testes, descrevendo assim o quinto e último passo na geração de código.

Entre os trabalhos correlatos, verificou-se que existem ferramentas com as mesmas

características propostas neste trabalho, em especial o driver ODBC ConnectWare. Porém, o

mesmo não gera código e funciona apenas com um grupo de compiladores restritos,

diferentemente da aplicação proposta que será flexível neste quesito. O pacote de ferramentas

Totem efetua a geração de código como a aplicação proposta, mas o foco é o

desenvolvimento de aplicações e não a extração de informações de base de dados. A extensão

82

do aplicativo Delphi2Java assemelha-se com a ferramenta proposta nas análises léxica,

sintática, semântica e na geração de código fonte.

No Quadro 40 são apresentadas as principais características entre o driver ODBC

ConnectWare e a ferramenta desenvolvida.

Comparação entre ConnectWare e CobolQuery 1.0 ConnectWare Cobol Query 1.0

Efetua análises (léxica, sintática e semântica)

X X

Disponibiliza ambiente para cadastro do metadados

X X

Permite exclusão, inclusão e alteração de registros

X

Permite digitação de comandos DDL

X

Quadro 40 – Comparação entre ConnectWare e CobolQuery 1.0.

É importante ressaltar que o ConnectWare funciona como driver ODBC. Desta

maneira necessita de uma aplicação que o utilize, do contrário da aplicação apresentada neste

trabalho que é um ambiente pronto para iteração em bases de dados COBOL.

Quanto ao desempenho da aplicação, com um processador de 2,4 GHz, têm-se:

a) tempo médio das análises (léxica, sintática e semântica): na casa de 0,4 segundos;

b) tempo médio da geração de código: na casa de 0,6 segundos;

c) tempo médio da compilação do código de saída e geração do arquivo binário: na

casa de 1 segundo, sendo este resultado dependente do compilador utilizado;

d) tempo médio da execução do arquivo binário e leitura do arquivo de resultado: para

leitura de aproximadamente 500 registros o tempo médio é de 1 segundo. Para a

leitura de aproximadamente 2.500 registros o tempo médio é de 7 segundos.

Consequentemente para leitura de aproximadamente 375.000 registros o tempo

médio é de aproximadamente 2 minutos.

O baixo desempenho em grande quantidade de registros é explicado devido ao código

gerado executar o produto cartesiano dos arquivos, e também da demora para apresentar o

arquivo de resultado ao usuário, visto que o mesmo é lido caractere a caractere.

Por fim, durante a implementação tentou-se a utilização dos compiladores gratuitos

TinyCobol e PowerCobol (COBOL da Fujitsu), mas sem sucesso. O compilador TinyCobol

83

apresentou-se deficiente quanto a geração do arquivo binário para execução. Por sua vez o

compilador PowerCobol não interpretava o código COBOL e deduziu-se que somente a

versão paga o faria. Desta maneira foi utilizado o compilador NetExpress 3.1 da Micro Focus.

84

4 CONCLUSÕES

Após a análise do problema envolvendo a leitura alternativa dos arquivos de

persistência de aplicações COBOL, surge a idéia deste trabalho, sendo este o

desenvolvimento de uma ferramenta de consulta a estas informações.

O cadastro das propriedades dos arquivos de dados COBOL torna-se necessário devido

aos mesmos não guardarem informações sobre as suas características e campos. Desta forma

possibilitou-se a imputação de layout’s e associação dos mesmos com campos e chaves,

compreendendo assim o primeiro objetivo específico.

Para a extração das informações foi escolhida a forma de consulta via comandos DML,

devido ao SQL ser a linguagem de acesso a banco de dados mais utilizada e conhecida,

contextualizando desta maneira o segundo objetivo específico. Além disso, aproveita-se o

conhecimento dos usuários em outras aplicações que utilizam esta linguagem para acesso aos

dados.

As análises léxica, sintática e semântica são vitais para o correto funcionamento da

ferramenta e compreendem ao terceiro objetivo específico. Caso as mesmas não forem

consistentes erros poderão ocorrer na geração do código de saída. Desta forma preocupou-se

em analisar e adaptar com precisão a BNF antes da geração dos analisadores léxico e sintático

pelo GALS.

O desenvolvimento resultou em uma ferramenta de fácil configuração, que é adaptável

na consulta de arquivos de dados de sistemas COBOL já em uso. A flexibilidade dá-se pelo

fato da mesma gerar código a partir de templates e de não depender do compilador, pois o

mesmo é abstraído da ferramenta, referindo-se assim ao quarto e quinto objetivos específicos.

A adaptação para um sistema já em funcionamento implica somente na alteração do cadastro

do metadados, e se necessário na modificação do compilador e na alteração dos templates.

O acesso aos arquivos seqüenciais, seqüenciais indexados, e também a forma de leitura

seqüencial e randômica são implementadas implicitamente no COBOL, salvo apenas por

modificações de identificadores no código fonte. Todo o tratamento em uma pesquisa por

índices, por exemplo, é nativo da linguagem. Desta forma, a geração de código torna-se

necessária, pois se deseja ter eficiência quanto à extração das informações contidas nos

arquivos de dados.

Finalizando, a ferramenta foi desenvolvida no padrão MVC, o que resultou em um

sistema organizado e modular, com classes e métodos bem definidos. Por este motivo pode-

85

se, por exemplo, modificar a camada de visão para web e continuar utilizando o núcleo da

ferramenta (controle e modelo) sem modificações.

4.1 LIMITAÇÕES

Há restrição de somente efetuar leitura dos arquivos, pois não foram implementados

comandos para alteração, exclusão e inclusão, visto que os arquivos de dados COBOL não

dão suporte ao relacionamento. Este tratamento deverá ser efetuado dentro do sistema de

informação que gerencia os arquivos e qualquer alteração na estrutura, poderá eventualmente

acarretar em um problema de sincronismo entre a ferramenta e a aplicação que faz uso da

base de dados.

Também existe a limitação de não poder cadastrar campos (e layout’s) com underline

ou hífen. Isto ocorre devido a existência de compiladores COBOL que não aceitam estes

caracteres como parte de identificadores.

Ainda, devido a linguagem COBOL não permitir identificadores com tamanho maior

do que trinta caracteres, a ferramenta inibe o cadastro de campos com mesma descrição,

mesmo que em layout’s diferentes. Se a ferramenta efetuasse, por exemplo, a concatenação do

nome do layout com o nome do campo no código de saída (diferenciando assim os campos

para compilação), haveria grandes chances de se ultrapassar os trinta caracteres e o código

não seria compilado. Também utiliza-se na geração de código variáveis auxiliares embasadas

nos campos cadastrados, o que proporcionaria também chances de não compilação do código

de saída.

Por fim, a ferramenta não efetua distinção entre campos numéricos com e sem sinal.

4.2 EXTENSÕES

Como extensões da ferramenta sugerem-se: a implementação dos comandos order by,

group by, having e join; implementação de operações agregadas (AVG, MIN, MAX,...);

implementação da função like; e implementação de operadores matemáticos. Estas

implementações acarretariam na alteração da BNF e alteração das classes dos pacotes

86

controller.analyzer e controller.sqlParts devido a inclusão de novos elementos para

as análises léxica, sintática e semântica. Também acarretaria em alterações nas classes dos

pacotes controller.cobolParts e controller.codegenerate e na definição do template.

Também sugere-se a geração do arquivo de resultado em arquivos XML (hoje a

ferramenta gera o arquivo de resultado em formato .csv), o que acarretaria na alteração da

classe controller.manager.RunManager e na definição do template.

Por fim, o núcleo da ferramenta pode ser também utilizado em aplicações IDE, para

geração de sistemas COBOL, adaptando-a para efetuar inclusão, alteração e exclusão de

registros.

87

REFERÊNCIAS BIBLIOGRÁFICAS

ALMEIDA, M. Gerenciadores de arquivos (GA) e sistemas gerenciadores de bancos de dados (SGBD). [S.l.], 2005. Disponível em: <http://www.sqlmagazine.com.br/colunistas/mansueto/02_GAxSGBD.asp>. Acesso em: 4 set. 2006. ARCHBELL, I. et al. Em defesa do COBOL. Tradução Paulo Roberto Rodrigues. [S.l.], 2003. Disponível em: <http://www.clubecobol.com.br/cc_em_defesa_do_cobol_01.asp>. Acesso em: 22 ago. 2006. BEZERRA, E. Princípios de análise e projeto de sistemas com UML. Rio de Janeiro: Campus, 2002. CASEMAKER. Totem overview. [S.l.], 2005. Disponível em: <http://www.casemaker.com/totem>. Acesso em: 10 set. 2006. FONSECA, F. Ferramenta conversora de interfaces gráficas: Delphi2Java-II. 2005. 59 f. Trabalho de Conclusão de Curso (Bacharelado em Ciências da Computação) – Centro de Ciências Exatas e Naturais, Universidade Regional de Blumenau, Blumenau. HERRINGTON, J. Code generation in action. Greenwich: Manning Puplications, 2003. LOUDEN, K. Compiladores: princípios e práticas. Tradução Flavio Soares Correia da Silva. São Paulo: Pioneira Thomson Learning, 2004. MICRO COBOL SOFTWARE. Micro COBOL software: ConnectWare. [S.l.], 2005. Disponível em: <http://www.microcobol.com.br/CONNECTware.html>. Acesso em: 10 set. 2006. MOREIRA, D.; MRACK, M. Sistemas dinâmicos baseados em metamodelos. In: WORKSHOP DE COMPUTAÇÃO E GESTÃO DA INFORMAÇÃO, 2., 2003, Lajeado. Anais eletrônicos... [Lajeado]: UNIVATES, 2003. Não paginado. Disponível em: <http://inf.univates.br/sicompi/wcompi2003/09-moreira-mrack.pdf#search=%22Gerador%20de%20C%C3%B3digo%22>. Acesso em: 10 set. 2006. NEWCOMER, L. Cobol estruturado. Tradução Lars Gustav Erik Unonius. São Paulo: McGraw-Hill do Brasil, 1985. PARKWAY. Parkway: ConnectWare. [S.l.], 2005. Disponível em: <http://www.parkway-software.com/index.php?id=14&L=1>. Acesso em: 10 set. 2006. ROCHA, L. APE: plataforma para o desenvolvimento de aplicações web com PHP. [Salvador], 2005. Disponível em: <http://twiki.im.ufba.br/bin/view/Aside/ProjetoConclusaoDeCursoAPEMonografia#4_2_Mot ores_de_templates>. Acesso em: 29 ago. 2006.

88

SILBERSCHATZ, A.; KORTH, H.; SUDARSHAN, S. Sistema de banco de dados. 3. ed. Tradução Marília Guimarães Pinheiro e Cláudio César Canhete. São Paulo: Pearson Education do Brasil, 1999. SILVEIRA, J. Extensão da ferramenta Delphi2Java-II para suportar componentes de banco de dados. 2006. 80 f. Trabalho de Conclusão de Curso (Bacharelado em Sistemas de Informação) – Centro de Ciências Exatas e Naturais, Universidade Regional de Blumenau, Blumenau. SOUZA, A. et al. RAFF: um compilador para facilitar o aprendizado de algoritmos. In: ENCONTRO DE ESTUDANTES DE INFORMÁTICA DO TOCANTINS, 1., 2002, Palmas. Anais... Palmas: [s.n.], 2002. Não paginado. Disponível em <http://www.ulbra-to.br/ensino/43020/artigos/anais2002/Encoinfo2002/RAFF.pdf>. Acesso em: 5 set. 2006. STEIL, R. Introdução ao Velocity. [S.l.], 2002a. Disponível em: <http://www.guj.com.br/Java.tutorial.artigo.18.1.guj>. Acesso em: 6 maio 2007. _____. Velocity template language. [S.l.], 2002b. Disponível em: <http://www.guj.com.br/Java.tutorial.artigo.26.1.guj>. Acesso em: 6 maio 2007.