DAVI AZEVEDO DE QUEIROZ SANTOS
TRANSFORMAÇÃO DE MODELOS INDEPENDENTE DE
METAMODELOS USANDO REFLEXÃO
Dissertação apresentada como requisito parcial à obtenção do grau de Mestre. Programa de Pós-Graduação em Informática,
Setor de Ciências Exatas, Universidade Federal do Paraná.
Orientador: Prof. Dr. Marcos Didonet del
Fabro
CURITIBA
2014
S237t
Santos, Davi Azevedo de Queiroz
Transformação de modelos independente de metamodelos usando
reflexão / Davi Azevedo de Queiroz Santos. – Curitiba, 2014.
74f. : il. color. ; 30 cm.
Dissertação (mestrado) - Universidade Federal do Paraná, Setor de
Ciências Exatas, Programa de Pós-graduação em Informática, 2014.
Orientador: Marcos Didonet del Fabro.
Bibliografia: p. 60-65.
1. Engenharia de software. 2. Projeto de sistemas. 3. Simulação
(Computadores). I. Universidade Federal do Paraná. II. Fabro, Marcos
Didonet del. III. Título.
CDD: 005.12
DAVI AZEVEDO DE QUEIROZ SANTOS
TRANSFORMAÇÃO DE MODELOS INDEPENDENTE DE
METAMODELOS USANDO REFLEXÃO
Dissertação aprovada como requisito parcial à obtenção do grau de
Mestre no Programa de Pós-Graduação em Informática da Universidade
Federal do Paraná, pela Comisso formada pelos professores:
Orientador: Prof. Dr. Marcos Didonet del Fabro
DINF/UFPR
Prof. Dr. Marco Aurélio Wehrmeister
UTFPR - membro externo
Prof. Dr. Fabiano Silva
DINF/UFPR - membro interno
Curitiba, 03 de abril de 2014
i
AGRADECIMENTOS
Ao professor e orientador Marcos Didonet del Fabro, pela orientação e suporte.
Aos meus professores de graduação, Gustavo Augusto Lima de Campos e Jerffeson
Texeira de Souza.
À CAPES (Coordenação de Aperfeiçoamento de Pessoal de Nı́vel Superior) pela concessão da bolsa.
Finalmente agradeço à minha famı́lia por tudo.
ii
SUMÁRIO
LISTA DE FIGURAS
v
LISTA DE TABELAS
vi
RESUMO
vii
ABSTRACT
viii
1 INTRODUÇÃO
1
1.1 Motivação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
1.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.3 Organização do texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2 REVISÃO BIBLIOGRÁFICA
7
2.1 Engenharia Dirigida Por Modelos . . . . . . . . . . . . . . . . . . . . . . .
7
2.1.1
Transformação de Modelos . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.2
Classificação para Problemas de Transformação de Modelos . . . . . 14
2.1.3
Classificação para Linguagens de Transformação de Modelos . . . . 16
2.2 Linguagens e Ferramentas para a Transformação de Modelos . . . . . . . . 18
2.3 Eclipse Modeling Framework . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.4 Programação por Restrições . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.5 Framework Alloy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3 MODELAGEM COMO BUSCA
27
3.1 Modelagem como Busca . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2 Transformação como Busca
. . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3 Trabalhos Relacionados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
iii
4 TRANSFORMAÇÃO DE MODELOS INDEPENDENTE DE METAMODELOS USANDO REFLEXÃO
39
4.1 Abordagem Independente de Resolvedor . . . . . . . . . . . . . . . . . . . 39
4.2 Instanciação com o Framework Alloy . . . . . . . . . . . . . . . . . . . . . 41
4.3 Transformação de Modelos Independente de Metamodelos usando Reflexão
5 EXPERIMENTOS
47
52
5.1 Linhas de Produto de Software . . . . . . . . . . . . . . . . . . . . . . . . 52
5.2 Transformação Classe para Relacional . . . . . . . . . . . . . . . . . . . . . 54
6 CONCLUSÕES E TRABALHOS FUTUROS
57
BIBLIOGRAFIA
60
A CÓDIGO DA TRANSFORMAÇÃO 4
66
iv
LISTA DE FIGURAS
2.1 Hierarquia das siglas MBE, MDE, MDA e MDD [12] . . . . . . . . . . . .
7
2.2 Arquitetura de três nı́veis [19] . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.3 Exemplos da arquitetura de três nı́veis [19] . . . . . . . . . . . . . . . . . . 10
2.4 Esquema base da transformação de modelos . . . . . . . . . . . . . . . . . 11
2.5 Exemplos de transformações de modelos [22] . . . . . . . . . . . . . . . . . 12
2.6 Metamodelos de entrada e saı́da do exemplo Livro para Publicações [21] . . 13
2.7 Exemplo de modelo de entrada da transformação e sua respectiva saı́da . . 13
2.8 Diagrama das principais classes do Ecore [56]
. . . . . . . . . . . . . . . . 22
2.9 Exemplos de instâncias Alloy . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1 Modelagem como Busca [37] . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2 Exemplo do metamodelo Livro . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3 Exemplo de instância de Livro . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.4 Integração da modelagem como busca no espaço tecnológico MDE [37]
. . 30
3.5 Transformação como busca . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.6 Metamodelo de transformacão para a transformacão como busca [38] . . . 34
3.7 Resultado da transformação do diagrama de classe para relacional . . . . . 35
3.8 Diagrama com as classes do SAPos . . . . . . . . . . . . . . . . . . . . . . 36
4.1 Abordagem Independente de Resolvedor . . . . . . . . . . . . . . . . . . . 40
4.2 Transformação da Solução . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.3 Metamodelo Alloy [37] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.4 Metamodelo XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.5 Metamodelo de Instâncias Alloy . . . . . . . . . . . . . . . . . . . . . . . . 45
4.6 Metamodelo ECore produzido pela transformação 3. . . . . . . . . . . . . . 47
4.7 Saı́da da Transformação 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.1 Metamodelo de Classe do estudo de caso SPL . . . . . . . . . . . . . . . . 53
v
5.2 Modelo produzido pela TIMeR para o estudo de caso SPL . . . . . . . . . 53
5.3 Metamodelo de Classe usado como entrada . . . . . . . . . . . . . . . . . . 54
5.4 Saı́da do estudo de caso Class2Relational . . . . . . . . . . . . . . . . . . . 55
5.5 Metamodelo relacional [22] . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.6 Saı́da do estudo de caso Class2Relational com a operação cut . . . . . . . . 56
vi
LISTA DE TABELAS
2.1 Comparativo
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2 Comparativo
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1 Mapeamentos entre os elementos . . . . . . . . . . . . . . . . . . . . . . . 33
3.2 Tempos de Execução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.1 Mapeamento entre o metamodelo Alloy e ECore . . . . . . . . . . . . . . . 47
4.2 Principais classes e métodos do ECore usados na implementação . . . . . . 47
5.1 Tempo médio em segundos de cada etapa do estudo de caso SPL . . . . . . 53
5.2 Tamanho da entrada de cada etapa do estudo de caso SPL . . . . . . . . . 54
5.3 Tempo médio em segundos de cada etapa da cadeia para o estudo de caso
Class2Relational
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.4 Tamanho da entrada de cada etapa do estudo de caso Class2Relational . . 56
vii
RESUMO
A integração de técnicas de programação por restrições em plataformas de engenharia dirigida por modelos (MDE) tem como objetivo principal usar resolvedores de programação por restrições para execução de operações sobre modelos. As operações são
chamadas operações de busca, pois buscam instâncias válidas de modelos baseada em um
conjunto de restrições.
Entretanto, as plataformas MDE existentes possuem formatos incompatı́veis com os
formatos das soluções dos resolvedores atuais. Por isso é necessário desenvolver mecanismos de interoperabilidade. Existem diferentes abordagens para automatizar esta integração, normalmente baseada na execução de uma cadeia de transformações, sendo uma
das mais conhecidas chamada “modelagem como busca”. Esta abordagem especifica quais
operações são necessárias para, a partir de um modelo e metamodelo de entrada, produzir
uma especificação no formato do resolvedor, e como transformar o resultado produzido
por um resolvedor em um modelo e metamodelo.
Entretanto, esta e as demais abordagens são baseadas em transformações de modelo
que são implementadas sobre os elementos de metamodelos. Com isso, para cada metamodelo de saı́da, é necessário implementar uma transformação do formato do resolvedor
para um modelo conforme a este metamodelo, tornando a abordagem inviável.
Este trabalho propõe um conjunto de transformações para automatizar a cadeia de
operações da abordagem de modelagem como busca. Dentre as diferentes transformações,
damos destaque a transformação do modelo do formato do resolvedor para o metamodelo
de saı́da. Esta transformação será desenvolvida sem conhecimento prévio dos elementos
do metamodelo, estes serão interpretados durante a execução, sendo assim chamada de
”transformação independente de metamodelos”. Apresentaremos a formalização da cadeia
de operações, e esta será implementada em dois casos de uso, mostrando sua factibilidade.
Palavras-chave: engenharia dirigida por modelos, transformação de modelos
viii
ABSTRACT
The integration of constraint programming techniques with model-driven engineering
(MDE) platforms has as main objective to use constraint programming solvers to perform
operations on models. These operations are called search operations, because they search
valid model instances based on a set of constraints.
However, the existing MDE platforms have incompatible formats with the formats of
the solutions produced by the current solvers. Therefore it is necessary to develop mechanisms for interoperability. There are different approaches to automate that integration,
usually based on the execution of a chain of transformations, one of the most known
approach is called “model search”. This approach specifies what operations are needed
to produce, from an input model and metamodel, an specification in the solver’s format,
and how to turn the result produced by a solver into a model and metamodel.
Yet, this and the other approaches are based on model transformations that are implemented over the elements of metamodels. Thus, for each output metamodel, it is
necessary to implement a transformation of the solver’s format to a model conforming to
this metamodel, making the approach difficult to implement.
This work proposes a set of transformations to automate the chain of operations of
the model search approach, focusing on the interoperability part. Among the different
transformations, we highlight the model transformation from the solver’s format to the
output metamodel. This transformation will be developed without prior knowledge of
the metamodel elements, these are interpreted at runtime, thus being called ”metamodel
independent transformation.”We will present the formalization of the chain of operations,
and this chain will be implemented in two use cases, showing its feasibility.
Keywords: model-driven engineering, model transformation
1
CAPÍTULO 1
INTRODUÇÃO
A Engenharia Dirigida por Modelos (Model-Driven Engineering, MDE) [12] é uma
abordagem de desenvolvimento de software onde modelos são artefatos de primeira ordem
[37], e não são usados apenas como entrada para atividades de geração de código ou
documentação. Isto diferencia esta abordagem de métodos como o RUP, onde modelos
são usados essencialmente para documentação [40].
Um modelo é uma representação de um sistema, utilizado para um determinado objetivo, que tenta extrair algumas de suas caracterı́sticas de forma simplificada [12]. Temos
como exemplo um modelo representando um sistema de gestão de controle acadêmico,
onde um aluno é um elemento deste modelo que possui atributos como nome, idade, e
relaciona-se com outros elementos como disciplina e histórico. Estes relacionamentos podem indicar que um aluno está matriculado em uma disciplina e possui um histórico com
as notas das disciplinas cursadas.
Os tipos dos elementos pertencentes a um modelo e seus relacionamentos são definidos
por um modelo chamado metamodelo [19]. A relação de tipagem entre um modelo e seu
metamodelo é chamada de conformidade [19]. Entretanto, metamodelos não possuem
sempre capacidade de expressão adequada, pois definem informações essencialmente estruturais e é necessário incluir restrições mais especı́ficas [37]. Por exemplo, a idade de
um aluno não pode ser negativa.
Searchbased MDE (SBMDE) é uma área recente que estuda a integração de técnicas
de MDE com programação por restrições [32]. As aplicações mais comuns de SBMDE
são a verificação automática e manual de modelos UML [13, 27], Linhas de Produto de
Software [15], e mais recentemente abordagens como JTL [14], Modelagem como Busca
[37] e Transformação como Busca [38]. As abordagens de programação por restrições
possuem resolvedores que, a partir de um conjunto de variáveis, restrições e valores de
2
entrada, tentam encontrar uma solução (conjunto de valores atribuı́dos às variáveis) que
satisfaça todas as restrições especificadas [37].
As soluções de programação por restrições atuais não possuem integração completa
com o MDE [14, 27], pois as soluções de cada resolvedor possuem formatos de representação e ferramentas especı́ficos e incompatı́veis. Isto dificulta a integração de ambas
abordagens. Dizemos que a abordagem MDE e programação por restrições são definidas
em espaços tecnológicos diferentes. Espaços tecnológicos representam o contexto para a
especificação e representação dos modelos [12], como por exemplo: XML [58], Ecore [56],
SQL [26], MOF [49] e soluções de programação por restrições. Cada espaço tecnológico
possui sua própria terminologia, formalismo, capacidades e conjunto de ferramentas de
suporte [42]. Por exemplo, o que é chamado de metamodelo no espaço tecnológico MDE
corresponde a um esquema no espaço tecnológico do XML. É importante possuir técnicas
para converter modelos de um espaço tecnológico para outro, para ser possı́vel aproveitar
as capacidades de diferentes espaços tecnológicos. Nesta dissertação, usaremos o MDE
como espaço tecnológico base.
Para realizar operações de conversão entre modelos, usamos transformações de modelos
[12]. Transformações de modelos recebem um ou mais modelos de entrada e produzem
um ou mais modelos de saı́da [11]. Quando transformações de modelo são desenvolvidas,
é necessário conhecer o metamodelo de entrada e o metamodelo de saı́da. Por exemplo,
para transformar diagramas de classes em tabelas [22], devemos conhecer os elementos
do metamodelo de classes e os elementos do metamodelo de tabelas. Transformações que
convertem modelos entre diferentes espaços tecnológicos são chamadas de injetores ou
extratores.
Se considerarmos o MDE como espaço tecnológico de referência, um injetor é uma
transformação que converte uma representação de um espaço tecnológico X para o espaço
tecnológico MDE. Um extrator é a transformação inversa, do espaço tecnológico MDE
para o espaço tecnológico X [12].
3
1.1
Motivação
Existem diferentes abordagens que permitem fazer a conexão entre o espaço tecnológico
MDE e o espaço tecnológico de programação por restrições de forma automatizada, como
por exemplo, a Modelagem como Busca [37].
A Modelagem como Busca (Model Search) é uma abordagem que usa programação por
restrições para aplicar operações de busca de modelos válidos, isto é, dado um conjunto
de elementos de um modelo, não conectados, como entrada, um resolvedor é utilizado
para encontrar um ou vários modelos de saı́da válidos. Uma aplicação de exemplo são as
linhas de produto de software. Uma extensão da modelagem como busca chamada Transformação como Busca (Transformation as Search, TAS) [38] é aplicada especificamente
para a operação de transformação de modelos.
O funcionamento da modelagem como busca consiste em encontrar um modelo de
saı́da a partir do metamodelo alvo, suas restrições e um modelo parcial. Este modelo parcial é composto por atribuições iniciais de elementos e relacionamentos do modelo, que
não precisam, necessariamente, satisfazer todas as restrições do metamodelo. Em outras
palavras, um conjunto de elementos não conectados e não conforme ao metamodelo. O
resolvedor, quando executado, pode produzir uma ou várias soluções, dependendo do modelo parcial e das restrições do metamodelo. Essa capacidade de produzir várias soluções
para um mesmo conjunto de entrada é útil em diversos cenários, como em aplicações de
linha de produto de software.
A abordagem da modelagem como busca é formada por uma cadeia com cinco etapas
[37]:
1. Transformação do metamodelo do problema em um modelo de programa de busca.
2. Transformação do modelo parcial em dados do programa de busca. Ao término
destas duas etapas, temos o modelo do programa de busca, que contém os elementos
do metamodelo, suas restrições e o modelo com as atribuições iniciais.
3. Extração do modelo do programa de busca do espaço tecnológico MDE para o espaço
tecnológico do resolvedor. Por exemplo, um arquivo texto com o programa a ser
4
executado.
4. Execução do programa pelo resolvedor com a obtenção da sua solução. Esta fase é
a execução da operação de busca.
5. Injeção desta solução no espaço tecnológico MDE, de forma a gerar um modelo
em conformidade com o metamodelo de saı́da. Este metamodelo não precisa ser
conhecido durante a especificação desta cadeia.
Entretanto, não há abordagens atualmente que implementem toda esta cadeia de
forma genérica, em especial a última etapa. Isto porque as ferramentas existentes de
injeção e extração precisam conhecer o metamodelo de saı́da para que a transformação
seja codificada. Isto é, é preciso escrever uma transformação do formato de saı́da do
resolvedor para cada metamodelo de saı́da diferente. Porém, na modelagem como busca e
na transformação como busca, isto deveria ser evitado, escrevendo apenas uma operação de
extração de um espaço tecnológico para outro, sem ser dependente do metamodelo de saı́da
para a sua especificação. Para evitar essa limitação, nesta dissertação apresentaremos
uma solução de transformação de modelos independente de metamodelo para injeção da
solução de um resolvedor no espaço tecnológico MDE.
1.2
Objetivos
O objetivo deste trabalho é propor e implementar uma abordagem de injeção do espaço
tecnológico do resolvedor para o espaço tecnológico MDE sem conhecer o metamodelo de
saı́da durante sua implementação.
O metamodelo de saı́da será um parâmetro de entrada que será interpretado durante a
execução usando técnicas de reflexão. Esta transformação será escrita usando os elementos
do metametamodelo. Por isso, sua implementação será independente do metamodelo de
saı́da. A transformação será chamada de transformação independente de metamodelo.
Implementaremos também transformações de suporte, no total de 4, para levar em
conta a diferença de formatos entre o espaço tecnológico dos resolvedores e o espaço
tecnológico MDE.
5
Para cumprir tal objetivo, foi proposta uma cadeia composta com as quatro transformações de modelos descritas abaixo:
1. Injeção do programa do resolvedor para um modelo de programa do resolvedor no
espaço tecnológico MDE. O modelo do programa do resolvedor contém informações
do metamodelo de saı́da e suas restrições;
2. Injeção da solução do programa do resolvedor no espaço tecnológico MDE. Esta
solução contém os elementos do modelo de saı́da;
3. Transformação do modelo produzido pela primeira transformação no metamodelo
de saı́da. Vale salientar que o metamodelo e o modelo do resolvedor são sempre os
mesmos em uma execução. Os elementos variáveis são os metamodelos e modelos
da solução (saı́da);
4. Transformação do modelo da solução do resolvedor em um modelo em conformidade
com o metamodelo de saı́da. A implementação desta transformação será independente do metamodelo, isto é, não será necessário conhecer o metamodelo de saı́da
(produzido por 3) durante sua implementação. Este será apenas interpretado durante a execução.
Assim, quando a cadeia de modelagem como busca for executada, as soluções do
resolvedor poderão ser injetadas no espaço tecnológico MDE de forma automática e com
a especificação de uma única transformação na etapa 4, para qualquer metamodelo ou
modelo de saı́da.
Após esta implementação, o processo de validação e análise dos resultados foi realizado
utilizando dois estudos de caso: linhas de produto de software [15] para a modelagem
como busca e a transformação Class2Relational [22] para a transformação como busca. A
validação foi feita comparando os elementos gerados com os esperados e com verificação
do formato correto do modelo através da ferramenta do Eclipse. O resolvedor utilizado foi
o Alloy Analyser [30]. Algumas ferramentas já existentes foram utilizadas como o injetor
do programa Alloy de [37]. Para as outras transformações utilizou-se o ATL [2] e Java
com o framework EMF [56] para suas implementações.
6
1.3
Organização do texto
Este trabalho está organizado da seguinte forma:
No próximo capı́tulo é realizada uma sı́ntese dos principais conceitos utilizados neste
trabalho, como a engenharia dirigida por modelos, as ferramentas de transformação de
modelos e programação por restrições.
No capı́tulo três é apresentado a modelagem como busca e a transformação como
busca, abordagens às quais este trabalho visa contribuir.
No capı́tulo quatro é apresentado a solução proposta através de uma cadeia de transformações, onde a última é denominada transformação independente de metamodelos
usado reflexão.
No capı́tulo cinco são apresentados os resultados obtidos. Finalmente, no capı́tulo seis
temos as conclusões e sugestões de trabalhos futuros.
7
CAPÍTULO 2
REVISÃO BIBLIOGRÁFICA
Neste capı́tulo será realizada uma revisão bibliográfica dos conceitos usados nesta
dissertação. Esta dissertação abrange conceitos de duas áreas, engenharia dirigida por
modelos e programação por restrições, além da integração de ambas. Estes são os conceitos
e ferramentas em que este trabalho se baseia.
2.1
Engenharia Dirigida Por Modelos
A Engenharia Dirigida por Modelos (Model-Driven Engineering, MDE) [35] é uma
abordagem que usa modelos como artefatos de primeira classe em todas as fases do ciclo de vida do processo de desenvolvimento de software. Recentemente em [12], tem-se
utilizado o termo engenharia de software dirigida por modelos (Model-Driven Software
Engineering - MDSE) para os usos do MDE dentro da Engenharia de Software. Há diferentes abordagens baseadas no MDE como Model-Driven Development (MDD) [12];
Model-Driven Architecture (MDA) [48], que é uma visão particular da MDD proposta
pela Object Management Group (OMG); e Model-Based Engineering (MBE) [12]. A
figura 2.1 ilustra a hierarquia dessas siglas. Como exemplos de MDE temos o Eclipse
Modeling Framework [56], o Meta-Object Facility [49].
Um modelo pode ser definido como a representação de um sistema que possui duas
Figura 2.1: Hierarquia das siglas MBE, MDE, MDA e MDD [12]
8
utilidades [12]: refletir uma parte das propriedades e entidades relevantes do sistema e
representar o sistema de forma abstrata e generalizada.
Um sistema é um grupo de elementos que interagem, relacionam-se, ou são independentes e que formam um todo [19]. Podemos usar um modelo para representar um sistema
para um determinado objetivo. Os modelos podem ter diferentes propósitos [12]: podem
ser descritivos (descrevem a realidade de um contexto ou sistema, como um esquema de
dados), prescritivos (determinam o escopo e detalhes, como os diagramas UML) ou definem como um sistema será implementado. Os modelos podem ser classificados como
estruturais (ou estáticos), que focam no aspecto da representação da estrutura e dados
do sistema com o diagrama de classe da UML [53], ou comportamentais (ou dinâmicos),
que enfatizam a sequência de ações e algoritmos, além de mostrar a colaboração entre
componentes e mudanças de seus estados internos [12], como por exemplo os diagramas
de estados e sequência da UML [53].
Um passo natural para a definição de modelos é especificar estes modelos como instâncias
de outros modelos mais abstratos [12]. Estes modelos, chamados de metamodelos, definem as informações de tipagem e os relacionamentos possı́veis entre os elementos de um
modelo [19], ou de acordo com [42], um metamodelo é um modelo de uma linguagem de
modelagem. A relação entre o modelo e seu metamodelo é chamada de conformidade, isto
é, um modelo está em conformidade com seu metamodelo. Esta relação é frequentemente
indicada pela sigla c2 (conformsTo). Tomando como exemplo um documento XML [58]
(modelo) e seu respectivo esquema XSD [59] (metamodelo), o esquema XSD especifica
quais elementos e atributos o documento XML deve possuir. Da mesma forma que existe
a relação entre um modelo e seu metamodelo, podemos ter a relação entre o metamodelo
e outro modelo que especifica quais são os tipos e relacionamentos do metamodelo. Este
modelo é chamado de metametamodelo. Um metametamodelo é um modelo que especifica a representação base para todos os modelos e metamodelos de um dado contexto.
Um metamodelo está em conformidade consigo mesmo [19].
A seguir temos as definições destes termos de acordo com [19] e [38]:
Definição 2.1 Um sistema é um grupo de elementos que se interagem, relacionam-se ou
9
conforme
M3
Metametamodelo
conforme
M2
Metamodelo
conforme
Modelo
M1
representa
Sistema
M0
Figura 2.2: Arquitetura de três nı́veis [19]
são independentes, e que formam um todo.
Definição 2.2 Um modelo é um artefato que representa um sistema. Um modelo M é
uma tripla < G, ω, µ > onde G é um multigrafo rotulado acı́clico; ω (modelo de referência
de M) é um outro modelo ou o mesmo modelo (uma auto-referência); µ é uma função
que associa vértices e arestas do grafo G para os nós do grafo Gω (o grafo associado a seu
modelo de referência ω).
Definição 2.3 Um metamodelo é um modelo que define o tipo dos elementos e relacionamentos dos elementos de um modelo.
Definição 2.4 Um metametamodelo é um modelo que especifica a representação base
para todos os modelos e metamodelos de um dado contexto. Um metamodelo está em
conformidade consigo mesmo.
Definição 2.5 A relação entre um modelo e seu metamodelo é chamada de conformidade
e é notada como conformsTo (ou abreviado como c2).
A figura 2.2 mostra as relações entre sistema, modelo, metamodelo e metametamodelo.
M3 é o metametamodelo. M2 é o metamodelo. M1 é o modelo que representa o sistema
M0. Como o sistema está fora da fronteira dos modelos, temos apenas três nı́veis.
Esta arquitetura de três nı́veis é suficiente para ser aplicada em diferentes contextos.
Na figura 2.3 temos a ilustração de três exemplos onde esta arquitetura pode ser aplicada.
10
conforme
M3
MOF
conforme
M2
Metamodelo
UML
conforme
M1 Modelo UML
conforme
Definição
XML
conforme
Esquema
XSD
conforme
Documento
XML
conforme
EBNF
conforme
Gramática
Java
conforme
Código
Java
Figura 2.3: Exemplos da arquitetura de três nı́veis [19]
O MOF (Meta-Object Facility) da OMG [49] é o metametamodelo que fornece uma base
independente de plataforma para a MDA. Podemos definir um metamodelo de classe que
está em conformidade com o MOF. Este metamodelo define os tipos e relacionamentos
dos elementos de um diagrama de classe, como associações e herança. Em seguida temos
o exemplo do XML [58], que também pode ser especificado em três nı́veis. O documento
XML (modelo) está em conformidade com um esquema XSD [59] (metamodelo). Este esquema define a validade da forma de um documento XML. Por sua vez, o esquema XSD
está em conformidade com a definição de um arquivo XML (metametamodelo). Também
podemos representar um código de uma linguagem de programação qualquer. O código
de um programa (modelo) está em conformidade com a gramática de uma linguagem de
programação (metamodelo), e esta linguagem é definida pela notação EBNF [55] (metametamodelo). Todos os modelos e metamodelos do MDE são projetados seguindo essa
arquitetura de três nı́veis [19].
Como temos diferentes formatos de representação, dizemos que cada forma de representação delimita um espaço tecnológico [12]. Um espaço tecnológico representa o
contexto para a especificação e implementação de aplicações [12]. Eles possuem uma linguagem para especificar os metamodelos e formatos para armazenar estes modelos, além
de um conjunto de ferramentas de suporte. Por exemplo, o espaço tecnológico do EMF
[56] possui como metametamodelo o Ecore e usa XMI [50] como formato para armazenar
os modelos. O MOF [49] possui um metametamodelo diferente, apesar de usar também
11
transforma
Figura 2.4: Esquema base da transformação de modelos
XMI como formato de armazenamento de seus modelos. Ligar estes diferentes espaços
tecnológicos de forma uniforme é necessário [42], porque os espaços tecnológicos podem
possuir capacidades e ferramentas diferentes. É preciso de uma operação que realize a
integração e manipule estes modelos em espaços tecnológicos diferentes ou até mesmo
dentro do mesmo espaço tecnológico. Estas operações são chamadas de transformações
de modelos.
2.1.1
Transformação de Modelos
Transformação de modelos é a principal operação do MDE e é definida usando modelos
de transformação. Isto é, a própria transformação é definida por um modelo. Estes
modelos definem o mapeamento entre os metamodelos de entrada e saı́da. Elas possuem
diversas aplicações [18]: gerar modelos de baixo nı́vel (código), mapear, sincronizar e
evoluir modelos, engenharia reversa, entre outras.
A figura 2.4 mostra o esquema básico de uma operação de transformação de modelos.
Neste exemplo, Ma é o modelo de entrada que é transformado para o modelo de saı́da Mb .
Ma está em conformidade com MMa (metamodelo de Ma ) e Mb com MMb (metamodelo de
Mb ), isso é indicado pelas setas c2. O modelo da transformação Mt está em conformidade
com MMt (metamodelo de Mt ) e define as regras de transformação entre os metamodelos
de entrada e saı́da. MMt é o modelo da linguagem de transformação. Mt contém as
12
operações que são executadas para transformar Ma em Mb . Todos os metamodelos estão
em conformidade com o mesmo metametamodelo. A seguir temos uma definição para
transformação de modelos conforme [19]:
Definição 2.6 Transformação de modelo é uma operação que recebe um conjunto de modelos como entrada, visita os elementos destes modelos e produz um conjunto de modelos
de saı́da.
transforma
Figura 2.5: Exemplos de transformações de modelos [22]
Na figura 2.5, temos dois exemplos de transformações. A primeira consiste em transformar um diagrama de classe em um modelo relacional [22]. A segunda consiste na
transformação de um modelo de livros para um modelo de publicações [21]. Temos na
figura 2.6(a) o metamodelo de livros e na figura 2.6(b) o de publicações. O metamodelo de
livros determina que a classe Livro possui os atributos tı́tulo e um conjunto de capı́tulos,
e a classe Capı́tulo possui os atributos tı́tulo e número de páginas deste capı́tulo. O
metamodelo de publicações contém uma única classe Publicação, que possui os atributos
tı́tulo da publicação e número de páginas totais. A transformação consiste em transformar cada instância da classe Livro em uma instância da classe Publicação, sendo que o
tı́tulo da publicação é o tı́tulo do livro e o número de páginas da publicação é a soma do
número de páginas de todos os capı́tulos deste livro. Na figura 2.7 temos um exemplo de
13
(a) Metamodelo de
Livros
(b) Metamodelo de
Publicações
Figura 2.6: Metamodelos de entrada e saı́da do exemplo Livro para Publicações [21]
(a) Modelo de Livros (entrada)
(b) Modelo
(saı́da)
de
Publicações
Figura 2.7: Exemplo de modelo de entrada da transformação e sua respectiva saı́da
modelo a ser transformado (figura 2.7(a)) e o resultado da transformação em um modelo
de Publicações (figura 2.7(b)).
Quando os modelos de entrada e saı́da estão em espaços tecnológicos diferentes, é
possı́vel transformar estes modelos de um espaço tecnológico para outro [12].
Esta
operação é denominada injeção ou extração [37].
• A injeção é uma transformação de um espaço tecnológico para o espaço tecnológico
base (MDE).
• A extração é uma transformação do espaço tecnológico base (MDE) para outro
espaço tecnológico.
Injetores e extratores podem ser implementados de várias formas, código nativo [2],
Textual Concrete Syntax [34], ou usando ferramentas de transformação que realizem transformação modelo-para-texto [12].
14
A seguir, temos um resumo da classificação dos problemas que envolvem as transformações e das ferramentas utilizadas para realizá-las feito por [11]. Czarnecki el al. [18],
Mens et al. [43] e Huber [28] realizaram a classificação das principais linguagens e ferramentas utilizadas para a transformação de modelos. Biehl [11] sintetiza estas abordagens
em dois tipos: classificação para problemas de transformação de modelos e classificação
para Linguagens de Transformação de Modelos.
2.1.2
Classificação para Problemas de Transformação de Modelos
Um problema de transformação de modelos é definido como um problema que deve
ser resolvido usando transformação de modelos [11]. Logo, é preciso uma classificação da
relação entre os modelos de entrada e saı́da. Esta relação possui as seguintes propriedades
segundo [11]:
• Mudança de Abstração:
– O nı́vel de abstração é a medida da quantidade de detalhes de um modelo[11].
A transformação de modelos pode mudar o nı́vel de abstração inserindo ou
removendo detalhes, ou mesmo não realizar nenhuma alteração. Esta propriedade é independente da mudança do metamodelo, isto é, os metamodelos de
entrada e saı́da podem ser o mesmo ou diferentes. Há dois tipos: transformação
vertical e transformação horizontal.
– Uma transformação vertical muda o nı́vel de abstração. Se houver a inserção
de detalhes no modelo, a transformação é chamada de transformação de refinamento [11].
– Uma transformação horizontal muda a representação do modelo, mas não muda
seu nı́vel de abstração. Este tipo de transformação produz o modelo de saı́da
em um metamodelo diferente e mantendo o mesmo nı́vel de abstração [43].
• Mudança de Metamodelos:
15
– Se os metamodelos de entrada e saı́da são os mesmos, temos uma transformação
endógena. Se são diferentes, a transformação é chamada exógena [18].
• Espaços Técnológicos Suportados:
– Como foi visto, modelos podem estar em espaços tecnológicos diferentes. Os
espaços tecnológicos limitam quais ferramentas de transformação podem ser
usadas.
• Número de Modelos Suportados:
– O número de modelos de entrada e saı́da também é uma caracterı́stica importante de uma transformação. A maioria das transformações envolve dois
modelos diferentes, um de entrada e outro de saı́da. Também é possı́vel ter
vários modelos de entrada e saı́da.
– Quando o modelo de entrada e saı́da é o mesmo, a transformação é chamada
transformação in-place. Neste caso, o modelo de saı́da é criado modificando
algumas partes do modelo de entrada.
• Tipo do Modelo de Saı́da Suportado:
– Podemos diferenciar a transformação de modelos de acordo com o tipo do
modelo de saı́da. Uma transformação modelo-para-modelo (model-to-model,
M2M) cria um novo modelo a partir do modelo de entrada. Elementos do
modelo de entrada são mapeados em elementos do modelo de saı́da. Uma
transformação modelo-para-texto (model-to-text, M2T) cria texto ou código.
Logo, os elementos do modelo de entrada são mapeados em fragmentos de
texto ou código.
• Preservação de Propriedades:
– A transformação pode ou não preservar algumas propriedades. Há três tipos:
∗ Preservação Semântica: os modelos de entrada e saı́da são os idênticos,
mesmo estando em espaços tecnológicos diferentes. As computações podem
16
ser diferentes, mas os resultados produzidos devem ser iguais [11]. Por
exemplo, a refatoração de um modelo.
∗ Preservação Comportamental: As restrições (implı́citas e explı́citas) do
modelo de entrada são mantidas no modelo de saı́da [11].
∗ Preservação de Sintaxe: Os modelos de entrada e saı́da possuem a mesma
sintaxe [11]. Este tipo é comum em uma transformação endógena horizontal.
2.1.3
Classificação para Linguagens de Transformação de Modelos
Biehl [11], baseado nos trabalhos [18] e [28], propôs as seguintes caracterı́sticas para
as linguagens de transformação de modelos:
• Paradigma:
– Há diferentes paradigmas para as linguagens de transformação de modelos [11]
e [18]:
∗ Imperativo/Operacional: Especificam o fluxo sequencial e descrevem como
a transformação deve ser executada, isto é, a transformação é descrita como
uma sequência de ações em uma linguagem imperativa [18], como Java ou
C#.
∗ Declarativo/Relacional: Elas não explicitam o controle de fluxo. Apenas
indicam como a transformação deve ser executada, focando em o quê deve
ser mapeado pela transformação. Como descrevem o relacionamento entre
os metamodelos de entrada e saı́da, este relacionamento pode ser bidirecional [11]. Como exemplo, temos a ATL [33].
∗ Hı́brido: Oferece as abordagens imperativa e declarativa, deixando a escolha para o usuário [11].
∗ Transformação de Grafos: Triple Graph Grammars (TGG) [54] são uma
forma de descrever transformações de grafos. É um subconjunto do tipo
17
declarativo, onde modelos de entrada e saı́da são interpretados como grafos
e há um terceiro grafo que descreve o mapeamento entre os elementos da
entrada e saı́da.
∗ Baseado em Templates: É usada em transformações modelo-para-texto.
Para cada elemento do metamodelo de saı́da, há um fragmento de texto
correspondente [18].
∗ Manipulação Direta: É a aplicação de linguagem de programação de propósito
geral para implementar a transformação [18]. Por exemplo, usar Java para
produzir um documento XML.
• Agendamento das Regras:
– O agendamento das regras determina a ordem em que cada regra é a aplicada [18]. Uma linguagem de transformação pode fornecer mecanismos para
determinar de forma explı́cita quando e onde uma determinada regra deve ser
aplicada [11].
• Organização das Regras:
– Em uma transformação com muitas regras, pode ser interessante a sua organização, isto é, agrupar estas regras de forma que possam ser compostas e/ou
reutilizáveis (modularizadas). Assim, com o reuso é possı́vel combinar regras
simples para construir regras mais complexas [11].
• Rastreabilidade:
– A execução de uma transformação pode gerar um registro do mapeamento
realizado entre os elementos. Esta funcionalidade pode estar embutida na
ferramenta ou implementada como parte da descrição da transformação [11].
• Direção:
– O mapeamento entre os modelos de entrada e saı́da por ser unidirecional, isto
é, as regras de transformação só podem ser aplicadas no modelo de entrada;
18
ou multidirecional, quando as regras podem ser aplicadas tanto do modelo de
entrada para o modelo de saı́da, como também do modelo de saı́da para o
modelo de entrada. Neste caso, se há apenas um modelo de entrada e outro de
saı́da, a transformação é bidirecional [18].
• Transformação Incremental:
– Uma transformação é incremental quando as mudanças no modelo de entrada
se propagam para o modelo de saı́da. Por outro lado, uma transformação
não-incremental recria o modelo de saı́da [11].
• Representação da Transformação:
– As transformações podem ser representadas como texto ou como um modelo.
Se são modelos, elas podem ser manipuladas por transformações de modelos
[11].
2.2
Linguagens e Ferramentas para a Transformação de Modelos
A seguir apresentamos a listagem das principais ferramentas e linguagens usadas para
a transformação de modelos.
EMF Henshin [9] é uma linguagem que suporta transformações modelo-para-modelo
endógenas e exógenas. É baseada no Eclipse Modeling Framework (EMF) [56] e a transformação é representada por Triple Graph Grammars (TGG). Contudo, não há suporte
para rastreabilidade, multidirecionalidade ou transformação incremental.
Atlas Transformation Language (ATL) [33] é uma linguagem hı́brida (imperativa e
declarativa, esta última a preferı́vel) para a transformações modelo-para-modelo. Suporta
apenas transformações unidirecionais e não incrementais. É integrada com a IDE Eclipse,
oferece suporte dedicado a rastreamento, a ordem de execução das regras é determinada
automaticamente na maioria dos casos.
OpenArchitectureWare (OAW) [24] é um conjunto de boas práticas e processos de
MDE integrados no Eclipse. Possui uma linguagem imperativa e baseada em templates
19
chamada Xpand [20] para transformações modelo-para-texto.
Query/View/Transform (QVT) [51, 41] é uma especificação da OMG (Object Managment Group) para uma linguagem capaz de expressar consultas, visões e transformações
sobre modelos. É divida em três sub-linguagens que são imperativas e declarativas para
transformações modelo-para-modelo:
• QVT Relational é uma linguagem declarativa de alto nı́vel. Suporta a especificação
de transformações bidirecionais; modelos de rastreabilidade são criados implicitamente.
• QVT Core é uma linguagem declarativa de baixo nı́vel e serve como base para a
QVT Relational.
• QVT Operational é uma linguagem imperativa que estende a QVT Relational. As
transformações são unidirecionais e usam modelos de rastreamento implı́citos.
SmartQVT [5] é uma implementação de um motor de transformação para a linguagem
QVT Operational. É uma linguagem imperativa para transformações modelo-para-modelo
para modelos do EMF. Não suporta transformações incrementais nem multidirecionalidade.
Kermeta [45, 52] é uma linguagem de modelagem imperativa e propósito geral capaz de
realizar transformações modelo-para-modelo. Não há suporte para multidirecionalidade,
rastreabilidade, nem para transformações incrementais.
Epsilon Transformation Language (ETL) [39] é uma linguagem hı́brida de transformação modelo-para-modelo, e pode tratar vários modelos de entrada e saı́da. Oferece a
funcionalidade do agendamento da aplicação das regras e as regras podem ser reutilizadas
e herdadas.
VIATRA2 [17] é um framework com uma linguagem hı́brida baseada em transformação
de grafos que suporta transformações modelo-para-modelo e modelo-para-texto. Também
suporta transformações incrementais.
Janus Transformation Language (JTL) [14] é uma linguagem de transformação declarativa modelo-para-modelo que realiza transformações bidirecionais. Possui suporte a
20
transformações incrementais e rastreabilidade.
A Transformação como Busca (Transformation as Search, TAS) [38] é uma extensão da
Busca de modelos [37] que realiza transformações exógenas modelo-para-modelo usando
uma linguagem declarativa. Possui suporte a rastreabilidade, incrementabilidade e transformações bidirecionais.
Nas tabelas 2.1 e 2.2 temos o resumo das caracterı́sticas mais importantes de cada
linguagem.
Ferramenta
EMF Henshin
OpenArchitectureWare
ATL
QVT
SmartQVT
Kermeta
ETL
VIATRA2
JTL
TAS
Tipo do Modelo de Saı́da
Modelo-para-modelo
Modelo-para-texto
Modelo-para-modelo
Modelo-para-modelo
Modelo-para-modelo
Modelo-para-modelo
Modelo-para-modelo
Modelo-para-modelo Modelo-para-texto
Modelo-para-modelo
Modelo-para-modelo
Paradigma
Transformação de Grafo
Imperativa e Baseada em
Templates
Hı́brida
Hı́brida
Imperativa
Imperativa
Hı́brida
Hı́brida
Declarativa
Declarativa
Tabela 2.1: Comparativo
Ferramenta
Direcionalidade
EMF Henshin
Unidirecional
OpenArchitectureWare
Unidirecional
ATL
Unidirecional
QVT
Unidirecional e Bidirecional
SmartQVT
Unidirecional
Kermeta
Unidirecional
ETL
Multidirecional
VIATRA2
Unidirecional
JTL
Bidirecional
TAS
Bidirecional
Rastreabilidade
Não
Sim
Sim
Sim
Sim
Não
Sim
Sim
Sim
Sim
Incremental
Não
Não
Não
Sim
Não
Não
Não
Sim
Sim
Sim
Tabela 2.2: Comparativo
Podemos ver que a maioria das abordagens são modelo-para-modelo, usam linguagens
imperativas e são unidirecionais. Poucas possuem suporte a incrementabilidade. Ainda
é preciso evoluir bastante nessa área, já que há a necessidade de transformações bidirecionais e incrementais, porque durante o desenvolvimento os modelos de entrada e saı́da
21
são modificados continuadamente [14]. Logo, nenhumas das abordagens atuais sozinhas
podem ser utilizadas para todos os tipos de problemas, elas sempre são combinadas entre
si para obter o resultado desejado.
Neste trabalho, onde é proposto uma cadeia de transformações para realizar última
etapa da cadeia da busca de modelos (e consequentemente da transformação como busca),
a ATL foi escolhida como ferramenta auxiliar a definição e execução de transformações
entre modelos, devido a sua fácil integração com a IDE do Eclipse e com framework de
modelagem do Eclipse (Eclipse Modeling Framework, EMF), além de ser possı́vel executála diretamente dentro de um código java.
2.3
Eclipse Modeling Framework
O Eclipse Modeling Framework (EMF) [56] é um framework de modelagem e geração
de código para construir ferramentas e outros aplicativos baseados em modelo. Este
framework permite manipular o metametamodelo Ecore usado nesta dissertação. O EMF
consiste de dois frameworks básicos: Core e EMF.Edit. O Core fornece uma API para
a geração e manipulação de modelos, além de fornecer ferramentas para produzir código
Java a partir de um modelo. O EMF.Edit estende o Core, adicionando suporte para gerar
classes adaptadoras, visualizadores e editores de modelos.
O EMF foi inicialmente uma implementação do Meta-Object Facility (MOF) [49], que
é o padrão da Object Management Group (OMG) para o MDE, mas acabou ganhando
importância própria, e pode ser visto uma implementação Java de um subconjunto da
API MOF [56].
O EMF é fornecido como um plugin para a IDE Eclipse e usa XMI (XML Metadata
Interchange) para armazenar (serializar) os modelos.
Ecore é o metametamodelo fornecido pelo EMF. Ele tem quatro tipos de classes como
principais elementos [56] (figura 2.8):
• EClass: é usado para modelar as classes. São identificadas por nome e possuem
atributos, referências. Também há suporte para herança.
22
Figura 2.8: Diagrama das principais classes do Ecore [56]
• EAttribute: modela atributos. São identificados por nome e possuem um tipo (um
EDataType).
• EDataType: é usado para representar tipos simples, cujos detalhes não são modelados em classes. Também identificados por um nome e são associados a tipos
primitivos das linguagens de programação.
• EReference: é usado para modelar associações entre classes. Também são identificadas por um nome e também possuem um tipo (uma EClass). Uma referência
também possui multiplicidade.
Estes tipos são usados para modelar as caracterı́sticas estruturais dos modelos. Para
modelar as caracterı́sticas comportamentais, a classe EOperation é usada. No entanto,
o Ecore apenas modela a interface destas operações comportamentais, porém é possı́vel
especificar implementações em outras linguagens usando anotações [56].
Além de fornecer ferramentas para criar e manipular os modelos Ecore dentro da IDE
do Eclipse, é possı́vel fazer a manipulação direta destes modelos utilizando a linguagem
Java. Entre as vantagens de realizar esta manipulação em nı́vel de metametamodelo estão:
maior flexibilidade, capacidade de manipulação dos modelos e metamodelos em tempo
execução e utilização da API reflexiva [56]. Esta API reflexiva permite que programas
examinem as informações sobre a estrutura dos modelos e metamodelos que estão sendo
manipulados em tempo de execução, com é isso possı́vel criar modelos dinamicamente e
criar novas ferramentas.
23
2.4
Programação por Restrições
Nesta seção apresentaremos os conceitos de programação por restrições usados nesta
dissertação.
Programação por restrições (Constraint Programming , CP) [32] é um paradigma
de programação declarativo usado para resolver problemas combinatórios [37]. A programação por restrições consiste na especificação de um conjunto de restrições sobre um
conjunto de variáveis com um tipo de dado. Em seguida, um programa chamado de
resolvedor analisa esta especificação e tenta encontrar uma atribuição de valores válida
(valoração) para estas variáveis, satisfazendo as restrições de entrada. O resolvedor pode
encontrar zero ou mais valorações (soluções de um problema de programação por restrições).
Cada variável possui um tipo e um domı́nio, isto é, um conjunto de valores possı́veis
para uma variável [37]. As restrições sobre um conjunto de variáveis são um subconjunto
do produto cartesiano dos domı́nios destas variáveis [7]. O conjunto de valores de todas
as variáveis formam a solução, e este conjunto de valores é encontrado por resolvedores.
Um exemplo de problema resolvido por programação por restrições é determinar se
uma fórmula booleana é satisfeita ou não, também conhecido como problema SAT [16].
Uma fórmula booleana é a ligação de um conjunto variáveis com domı́nio binário
(verdadeiro ou falso) por operadores lógicos (conjunção, disjunção e negação) [8]. Por
exemplo, tendo as variáveis A e B, uma fórmula para a conjunção da negação destas
variáveis pode ser escrita como ¬A ∧ ¬B.
A programação por restrições não apenas verifica a satisfabilidade, como também
encontra os valores possı́veis que tornam a fórmula verdadeira.
O paradigma SAT possui algumas limitações: o domı́nio das variáveis possui apenas
dois valores e fornece uma linguagem de baixo nı́vel para predicados (apenas negação,
conjunção e disjunção). Há uma grande variedade de resolvedores SAT eficientes: MiniSat [23], SAT4J [10], Chaff [46] e outros. Estendendo o problema SAT para variáveis
com domı́nios não apenas binários, chegamos aos problemas de satisfação de restrições
(Constraint Satisfaction Problems, CSP) [37].
24
Há diversos resolvedores para CSP, a maioria são baseados em Prolog [57], uma linguagem de programação lógica ou realizam redução ao SAT. A seguir temos uma lista de
alguns resolvedores utilizados no contexto do MDE:
• ECLiPSe [8] é uma ferramenta de código aberto baseada em Prolog, logo as restrições
são expressas como predicados lógicos. Possui uma API para ser integrada em
aplicações java.
R
R
é uma ferramenta proprietária para proCPLEX CP Optimizer [1]
• IBM ILOG
gramação por restrições. Possui uma linguagem de modelagem e resolvedores bastante robustos.
• Alloy [30] foi desenvolvido pelo MIT e, apesar de usar resolvedores SAT, possui
uma linguagem relacional bastante expressiva. Esta linguagem permite a expressão
de predicados usando conjuntos, relações e quantificadores. O Alloy pode utilizar
diferentes resolvedores SAT, além de poder ser facilmente integrada em aplicações
Java.
Entre estes resolvedores, o ILOG CPLEX CP Optimizer possui a desvantagem de ser
uma ferramenta proprietária e paga. O ECLiPSe e o Alloy já foram utilizados no contexto
do MDE em [13], [38]. Neste trabalho o Alloy foi escolhido, pois uma implementação atual
da modelagem como busca já o utiliza, está disponı́vel em código aberto, tem ferramentas e documentação de suporte, e sua especificação pode ser traduzida para diferentes
resolvedores.
2.5
Framework Alloy
O framework Alloy [30] é uma ferramenta de código aberto desenvolvida pelo MIT, e
seu propósito é analisar programas escritos pela linguagem de modelagem Alloy utilizando
o Alloy Analyzer.
A linguagem Alloy é baseada na lógica de predicados, e pode ser usada para representar
modelos e suas restrições [44]. Os programas escritos na linguagem Alloy são modelos for-
25
mados por estruturas chamadas assinaturas (signatures), que são declarações de conjunto
de átomos (atoms), e fatos (facts).
Átomos são entidades primitivas, indivisı́veis, imutáveis e não possuem propriedades
[31]. A linguagem permite a especificar propriedades através da definição de relações entre
átomos [31]. Estas relações são especificadas na linguagem por meio de campos (fields)
dentro das assinaturas. Fatos são declarações de restrições sobre átomos ou assinaturas. Esta restrições podem ser predicados, limite de cardinalidade, ou operações sobre
conjuntos [37].
Código 2.1: Exemplo de código Alloy
1
2
3
4
5
6
7
8
9
sig E s t o q u e {
itens : set Item
}
sig Item {
c o d i g o P r o d u t o : one Int ,
n o m e P r o d u t o : one String ,
q u a n t i d a d e : one Int
}
fact { all y : Item | y . q u a n t i d a d e >= 0 }
Estes conceitos são exemplificados na listagem de código 2.1 com um sistema de controle de estoque. Um estoque é formado por um conjunto de itens. As entidades são
descritas por assinaturas. Cada item é descrito por uma assinatura que contém a relação
de três átomos. O primeiro átomo é o código do produto, o segundo é nome do produto
e o terceiro é quantidade deste produto no estoque. Na linha 9 é definida uma restrição
que exclui os valores negativos do domı́nio do campo quantidade.
O Alloy Analyzer funciona como um resolvedor de programação por restrições [44].
Ele recebe como entrada um programa Alloy, e produz uma instância. Esta instância é
uma valoração das variáveis do programa que satisfazem as restrições, ou seja, é a solução
encontrada pelo resolvedor SAT [29]. Se o programa permite mais de uma solução, o
Alloy Analyzer é capaz de encontrá-la.
A figura 2.9 ilustra duas instâncias para o exemplo do sistema de controle de estoque.
Na figura 2.9(a), temos o átomo ’Estoque’ relacionado com dois átomos do tipo Item
(’Item1’ e ’Item2’) através do campo itens. Cada uma destas relações forma uma tupla.
26
(a) Instância com dois itens
(b) Instância com três itens
Figura 2.9: Exemplos de instâncias Alloy
Cada átomo do tipo Item possui três campos: código, nome do produto e quantidade. Na
figura 2.9(b), temos uma instância similar com três átomos do tipo Item.
Internamente, o Alloy Analyzer traduz o programa Alloy em uma fórmula booleana, e
um resolvedor SAT é utilizado para encontrar uma ou mais valorações desta fórmula. Cada
valoração é uma solução, que é traduzida automaticamente para a linguagem do programa
Alloy. Uma caracterı́stica do Alloy Analyazer é restringir o espaço da busca através de
um escopo, isto é, uma restrição no espaço de busca. Como esse escopo é limitado, o
resolvedor nem sempre encontra uma instância, mas isso significa apenas que não foi
possı́vel encontrar a solução dentro daquele escopo. Porém, as instâncias encontradas
são seguramente válidas [44]. Também é oferecido um suporte a rastreamento, assim é
possı́vel realizar análises e simulações podem ser aplicadas as instâncias encontradas [31].
Finalmente, as instâncias encontradas pelo Alloy Analyzer são armazenadas como
documentos XML [29]. Para as instâncias serem utilizada no espaço tecnológico MDE, é
preciso injetar este documento XML num modelo.
27
CAPÍTULO 3
MODELAGEM COMO BUSCA
Neste capı́tulo apresentaremos primeiramente a abordagem chamada “modelagem
como busca”, que integra técnicas de programação por restrições com execução de operações
MDE. Em seguida, apresentaremos uma extensão do MAS (Model as Seach), especı́fica
para execução de transformação de modelos. Finalmente, apresentaremos uma implementação que realizamos para avaliar a cadeia de TAS.
3.1
Modelagem como Busca
A Modelagem como Busca (Model Search) [37] é uma abordagem que usa programação
por restrições para aplicar operações sobre modelos. A natureza dos resolvedores de programação por restrições permite, dado um conjunto de elementos do modelo não conectados como entrada, encontrar um ou mais modelos de saı́da que satisfazem a estrutura
do metamodelo e um conjunto de restrições. Esta possibilidade de encontrar múltiplas
soluções é um diferencial em relação as abordagens de transformação apresentadas na
seção anterior.
Os metamodelos podem conter restrições embutidas (metamodelos com restrições).
Um metamodelo com restrições é definido por um metamodelo e um conjunto de restrições
que um determinado modelo deve satisfazer. Quando este modelo satisfaz a todas as
restrições dizemos que está em conformidade com as restrições.
A figura 3.1 ilustra uma operação de modelagem como busca. Esta operação consiste
em encontrar um modelo (M) a partir de outro modelo entrada Mr que está parcialmente em conformidade com um metamodelo (CMM). Este modelo Mr é chamado de
modelo parcial, e está em conformidade com o relaxamento das restrições do metamodelo CMM. Este relaxamento consiste em remover restrições e elementos (cardinalidade,
opcionais, etc) do metamodelo original, criando assim o chamado metamodelo relaxado
28
CMMr . Quando este modelo parcial Mr está em conformidade com o metamodelo relaxado CMMr , dizemos que o modelo parcial está em conformidade parcial (p-conformsTo)
com o metamodelo com restrições CMM. Finalmente, tendo o modelo parcial, o metamodelo relaxado e o metamodelo com restrições, a modelagem como busca é a operação que
procura encontrar um modelo (finito) a partir do modelo parcial que esteja em conformidade com o metamodelo com restrições.
O conceito de metamodelo parcial foi introduzido nesta abordagem para poder definir
o conjunto de elementos não conectados que uma operação de modelagem como busca
recebe como entrada. Isto se deve ao fato de que esta abordagem precisa de um “pool”
de elementos de entrada, isto é, não é uma abordagem generativa.
Figura 3.1: Modelagem como Busca [37]
A modelagem como busca é considerada uma transformação de modelos onde o modelo
de entrada (modelo parcial Mr e o metamodelo com restrições CMM) é uma instância
de um problema combinatório, e o modelo de saı́da M é uma solução deste problema (se
existir). Do ponto de vista da programação por restrições, o metamodelo CMM age como
uma fórmula, enquanto que o modelo parcial é uma atribuição parcial que precisa ser
completada para a fórmula ser verdadeira [37].
Para exemplificar a modelagem como busca, utilizaremos novamente o metamodelo
de Livros [21] (figura 3.2(b)). Um modelo está em conformidade com este metamodelo
com restrições quando um Livro possui zero ou mais capı́tulos. Ao relaxar este meta-
29
(a) Metamodelo de
Livros relaxado
(b)
Metamodelo
de
Livros
com
restrições
Figura 3.2: Exemplo do metamodelo Livro
(a) Modelo parcial
(b) Modelo encontrado
Figura 3.3: Exemplo de instância de Livro
modelo, podemos excluir a referência entre Livro e Capı́tulo, de forma que os elementos
do modelo parcial sejam desconexos. Com isso, temos o metamodelo relaxado na figura
3.2(a). O modelo parcial pode ser qualquer modelo que esteja em conformidade com este
metamodelo relaxado. Pode ser um modelo vazio ou um modelo que possui apenas uma
instância da classe Livro e duas instâncias da classe Capı́tulo que não estão associadas a
nenhuma instância da classe Livro (figura 3.3(a)). Quando um desses modelos parciais
é usado como entrada pela modelagem como busca, o resolvedor realiza atribuições que
tornem esse modelo parcial em conformidade com as restrições e com o metamodelo nãorelaxado [37]. No segundo exemplo de modelo parcial, o resolvedor adiciona as instâncias
das classes Capı́tulo à instância da classe Livro 3.3(b).
Em [37] é apresentado um cadeia para a automatização e integração da modelagem
como busca ao espaço tecnológico MDE. A figura 3.4 ilustra essa cadeia e a divide em cinco
tarefas. Os metamodelos CMM, CMMr , Search Engine, SE Solution e XML estão no
30
ECore
Figura 3.4: Integração da modelagem como busca no espaço tecnológico MDE [37]
espaço tecnológico MDE. Os metamodelos Search Engine e SE Solution são os metamodelo usados para representar o programa e a solução do resolvedor no espaço tecnológico
MDE. O metamodelo XML é o metamodelo para documentos XML dentro do espaço
tecnológico MDE. Os outros metamodelos estão fora do espaço tecnológico MDE. SE.g
representa a gramática do programa do resolvedor e XML Format é o esquema do documento XML onde está a solução do resolvedor. A seguir temos uma descrição de cada
etapa da cadeia:
1. Geração do Problema de Busca (CMM2SP): esta tarefa gera o modelo do problema
de programação por restrições a partir do metamodelo de entrada e suas restrições
(CMM).
2. Geração dos Dados de Busca (M2SP): gera os dados de entrada do programa de
programação por restrições a partir do modelo parcial Mr . Esta transformação é
especı́fica para cada metamodelo de entrada.
3. Extração do Programa: converte o modelo do problema de programação por restrições para um formato executável pelo resolvedor usado.
4. Busca da Programação por Restrições: o programa gerado nos passos anteriores é
executado, e uma ou mais soluções são encontradas no formato da saı́da do resolvedor.
31
5. Injeção da Solução (XML2SS, SS2M): Injeta a solução encontrada pelo resolvedor
em um modelo em conformidade com o metamodelo CMM. Esta etapa consiste em
escrever uma transformação para injetar a solução encontrada no formato da saı́da
do resolvedor em um modelo do espaço tecnológico base.
A modelagem como busca também pode utilizar um metamodelo de saı́da diferente
do de entrada, neste caso é usada para transformações exógenas, e esta abordagem recebe
o nome de transformação como busca, que será apresentada a seguir.
3.2
Transformação como Busca
A Transformação como Busca (Transformation As Search, TAS) [38] é uma abordagem, baseada na modelagem como busca, para definir e executar transformações de modelo
bidirecionais. A diferença principal em relação a modelagem como busca é a execução de
transformações exógenas. Isto impacta na especificação das restrições sobre o metamodelo
da solução, pois teremos um metamodelo fonte e um metamodelo destino, e as restrições
deverão ser escritas entre os dois metamodelos. Estas restrições podem ser consideradas correspondências entre metamodelos. Como se baseia na modelagem como busca
(é independente de resolvedores), não é preciso definir uma linguagem especı́fica, assim
qualquer ferramenta de programação por restrições pode ser usada. A abordagem fornece suporte para transformações modelo-para-modelo, verticais e horizontais, endógenas
e exógenas, bidirecionais, incrementais, rastreáveis, mas sem suporte a agendamento e
controle de aplicação das regras. Estas caracterı́sticas são possı́veis devido às expressividade das linguagens declarativas usadas pelos resolvedores. Porém algumas delas, como
a bidirecionalidade, dependem de como é realizada a implementação da transformação.
A figura 3.5 ilustra o funcionamento da cadeia de transformação como busca, numa
transformação exógena unidirecional. M A é o modelo de entrada que está em conformidade com o metamodelo de entrada CMM A , M B é o modelo de saı́da em conformidade
com o metamodelo CMM B . MrT é o modelo parcial para a modelagem como busca e
consiste numa cópia do modelo de entrada. M T é a solução encontrada pela modelagem
32
ECore
c2
Figura 3.5: Transformação como busca
como busca, CMM T é metamodelo de transformação (unificação dos metamodelos de
origem e saı́da e seus elos) e CMMrT é o metamodelo relaxado de CMM T . Depois de
encontrada a solução pela modelagem como busca, há um último passo chamado ’cut’
que extrai o modelo desejado. Este passo é necessário porque o resultado da modelagem
como busca possui tanto o modelo de entrada como o de saı́da.
A seguir, apresentaremos um caso de uso de transformação como busca para aplicação
e teste da cadeia completa 1 . Foi implementada a transformação de modelos ClassToRelational [22], que consiste em transformar um modelo de classes em um relacional. Esta
transformação e usada em diversos trabalhos como ilustração de problemas de transformações. A figura 3.6 ilustra o metamodelo da transformação usado em [38]. Este
metamodelo ilustra a correspondência (weaving links) entre os metamodelos de entrada e
saı́da. Nesta implementação foi utilizado como resolvedor o framework Alloy/SAT.
A tabela 3.1 ilustra o mapeamento entre os elementos dos metamodelos. Não há um
mapeamento 1:1 entre o elemento Table do metamodelo relacional e um elemento do metamodelo de classe e sim um mapeamento disjunto entre tabelas, atributos multivalorados
e classes. Isto é, há uma tabela para uma classe ou um atributo multivalorado. Isso é
realizado pela associação wnamed entre AttributeClassAndTable e NamedElt. Porém,
existe uma restrição que especifica que os elementos dessa associação só podem ser classes
1
Publicado em [38]
33
ou atributos multivalorados. Há uma equivalência entre atributos e colunas, eles possuem estruturas muito semelhantes, mas possuem algumas propriedades diferentes (como
a indicação de chave de uma tabela para o modelo relacional). Um caso diferente são
os atributos multivalorados de uma classe, pois eles estão associados a uma tabela e a
uma coluna. Já os tipos de dados do metamodelo relacional e de classe possuem a mesma
estrutura, então seu mapeamento é direto. Há também casos onde um elemento de um metamodelo não possui correspondência com algum elemento do outro metamodelo. Neste
caso, o metamodelo relacional possui chaves, porém o metamodelo de classes não possui esta informação, e não há correspondência e essa informação fica contida apenas no
modelo relacional.
Uma implementação da transformação como busca pode ser dividida em dois passos:
1. Criação do metamodelo de transformação: identificar as correspondências, com suas
ligações e elementos;
2. Adição de restrições: adicionar restrições que tornem os modelos corretos.
No primeiro passo nem sempre este mapeamento é bijetor (1:1). É preciso identificar
os casos onde há uma relação 1:N, N:1 e M:N entre os elementos dos metamodelos. No
segundo passo é preciso adicionar as restrições que tornem corretos o mapeamento e os
modelos de entrada e saı́da que serão produzidos. Estes dois passos correspondem a unificação dos metamodelos da transformação como busca. No exemplo ClassToRelational,
os nomes de atributos, classes, tabelas, colunas, tipos devem se corresponder de forma
adequada.
Elementos do Metamodelo
de Classe
Class
Attribute (monovalorado)
Attribute (multivalorado)
DataType
Elementos do Metamodelo
Relacional
Table
Column
Column e Table
Type
Tabela 3.1: Mapeamentos entre os elementos
A seguir temos a listagem de algumas restrições da transformação usando a OCL+ [3]
34
Figura 3.6: Metamodelo de transformacão para a transformacão como busca [38]
(uma extensão da linguagem OCL [47]). Estas restrições estabelecem a correspondência
entre os nomes de tipos, classes, atributos multivalorados e tabelas.
A injeção destes metamodelos e suas restrições num programa de busca representam
o final da tarefa Extração do Programa. Nesse ponto, o resolvedor é executado (isto é, é
executada a busca da programação por restrições), e uma solução é encontrada.
A figura 3.7 apresenta a entrada e o resultado da transformação de um modelo de
classe para o modelo relacional. O modelo utilizado consiste em duas classes (Family
e Person) com atributos monovalorados e mutivalorados. Os atributos multivalorados e
as classes foram mapeados corretamente para tabelas. Da mesma forma, os atributos
monovalorados foram mapeados corretamente.
Como podemos ver na tabela 3.2, o um ponto negativo da implementação foi o tempo
de execução. Os modelos utilizados possuem poucos elementos (apenas duas classes e
cinco atributos). Foi realizado um experimento com uma entrada maior e extraı́da de um
sistema real (Sistema de Apoio da Pós-graduacão - SAPos) [4] (figura 3.8). Esta entrada
possui 18 classes. Os experimentos mostraram que para essa entrada o framework Alloy
traduziu o problema para um problema booleano com uma explosão de variáveis. O
35
Restrições OCL+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1 - c o n t e x t dtt : D a t a T y p e A n d T y p e inv :
dtt . w d a t a t y p e . name = dtt . wtype . name
2 - c o n t e x t act : A t t r i b u t e C l a s s A n d T a b l e inv :
act . wnamed . name = act . w t a b l e N T. name
3 - c o n t e x t act : A t t r i b u t e C l a s s A n d T a b l e inv :
act . wnamed . i n c l u d e s( named : N a m e d E l t |
named . o c l I s T y p e O f ( Class ) or
( named . o c l I s T y p e O f ( A t t r i b u t e) and named . m u l t i V a l u e d ) ) )
4 - c o n t e x t mvac : M o n o V a l u e d A t t r i b u t e s A n d C o l u m n inv :
mvac . m o n o V a l A t t r . forAll ( attr : A t t r i b u t e |
not attr . m u l t i V a l u e d iff
mvac . m o n o V a l A t t r. i n c l u d i n g( attr ) and
mvac . m o n o V a l C o l. one ( col | col . name = attr . name and
col . keyOf . o c l I s U n d e f i n e d () and
col . towner . name = attr . cowner . name and
if D a t a T y p e. one ( dt | attr . ctype . name = dt . name ) then
col . ttype . name = attr . ctype . name
else
col . ttype . name = ’ Integer ’)
Figura 3.7: Resultado da transformação do diagrama de classe para relacional
36
Cenário-versão
Classe para Relacional
Relacional para Classe
Incremental
Número de Variáveis Booleanas
7179
5725
5448
Tempo de Execução (ms)
2483
1655
666
Tabela 3.2: Tempos de Execução
resolvedor minisat foi utilizado nestes experimentos.
Figura 3.8: Diagrama com as classes do SAPos
Após esta etapa, a solução encontrada deve ser injetada no espaço tecnológico MDE.
Numa abordagem clássica é preciso escrever uma transformação de modelos T1 que injete
a solução encontrada pelo resolvedor em um modelo em conformidade com o metamodelo
relacional. Porém esta transformação T1 não serve para injetar a solução num modelo
em conformidade com o metamodelo de Classe ou com o metamodelo de Livros, por
exemplo. Seria preciso escrever transformação T2 para o metamodelo de Classe e uma
transformação T3 para o metamodelo de livros. Neste caso, não é desejável escrever uma
injeção diferente para cada metamodelo de saı́da diferente. Automatizar esta injeção para
37
metamodelos de saı́da diferentes traria benefı́cios para o uso da modelagem como busca
e transformação como busca.
É preciso de uma implementação genérica para a injeção da solução da cadeia da modelagem como busca. As soluções encontradas pelo resolvedor estão em formato XML. A
injeção da solução é crucial para a praticidade da modelagem como busca, e consequentemente da transformação como busca.
3.3
Trabalhos Relacionados
Em [27] os autores apresentam uma ferramenta para verificação de modelos UML
com restrições especificadas com a linguagem OCL [47]. Há suporte para os diagramas
de classe, objeto e sequência da UML, mas é preciso escrever um código para realizar
a validação. Este código consiste em consultas que são executadas por um resolvedor
OCL. Este resolvedor é usado como um biblioteca que retorna o resultado da consulta
em formato de texto, que é exibido na interface do programa. A injeção da solução do
resolvedor desta abordagem é sempre para um formato já conhecido.
A abordagem [13] tem o mesmo objetivo, mas com um escopo mais reduzido (apenas
diagramas de classe). Fornece uma verificação automática. Neste caso o ECLIPSe é
utilizado como resolvedor. Esta abordagem transforma o modelo UML de entrada e suas
restrições em um programa de busca, e o resolvedor tenta encontrar uma atribuição (ou
mais de uma) que satisfaça todas as restrições. Se todas as restrições são satisfeitas, um
modelo que representa uma instância válida daquele diagrama de classe é encontrado.
Se este modelo não é encontrado, significa que a especificação do modelo de entrada e
restrições está errada. A solução encontrada pelo resolvedor está em um grafo armazenado
em formato textual. A ferramenta GraphViz [25] é utilizada para gerar apenas uma
visualização desta solução.
Em nenhuma dessas duas abordagens, o objetivo é produzir um modelo usável a partir
da solução do resolvedor. Os modelos encontrados estão em formato próprio, e não há
uma transformação deles em modelo Ecore, por exemplo.
Em [14] é apresentado uma abordagem chamada Janus Transformation Languagem
38
(JTL), que possui funcionamento similar à transformação como busca. É uma linguagem
de transformação de modelos baseado em resolvedores de programação por restrições.
Porém, o modelo e metamodelos de entrada precisam ser codificados usando uma linguagem própria da ferramenta, porque não há uma extração automática dos metamodelos
ECore para a linguagem usada pelo motor de transformação. Nesta abordagem a injeção
da solução é realizada por uma transformação que recebe o metamodelo de saı́da e gera
uma outra transformação que transforma a saı́da do resolvedor em um modelo em conformidade com o metamodelo de saı́da.
A modelagem como busca tem como objetivo realizar estas extrações e injeções de
forma automática e transparente. Por exemplo no caso de linhas de produto de software,
o metamodelo, restrições e modelo parcial estão no espaço tecnológico base. Estes modelos
e restrições são extraı́dos para o espaço tecnológico do resolvedor de forma automática e a
solução do resolvedor é injetada no espaço tecnológico base também de forma automática
em conformidade com o metamodelo de entrada.
No próximo capı́tulo é apresentada a abordagem utilizada para extrair a solução encontrada pelo resolvedor e injetá-la como um modelo usável no espaço tecnológico MDE
escrevendo apenas uma única transformação.
39
CAPÍTULO 4
TRANSFORMAÇÃO DE MODELOS INDEPENDENTE DE
METAMODELOS USANDO REFLEXÃO
Neste capı́tulo, apresentaremos uma abordagem para a injeção da solução produzida
pela operação de modelagemo como busca em um modelo no espaço tecnológico MDE,
usando apenas uma transformação para todos os metamodelos de saı́da. Esta abordagem é composta por quatro transformações. As três primeiras operações são relativas
a interoperabilidade entre espaços tecnológicos. A quarta transformação da abordagem
é o ponto chave, denominada Transformação de Modelos Independente de Metamodelos
usando Reflexão (TIMeR). Seu objetivo é implementar uma transformação que seja independente do metamodelo de saı́da, isto é, um modelo de entrada é transformado em
um modelo de saı́da em conformidade com um metamodelo que é desconhecido na fase
de implementação.
Primeiramente será apresentada uma abordagem independente de resolvedor em seguida sua instanciação com o framework Alloy.
4.1
Abordagem Independente de Resolvedor
Como foi apresentado, a primeira etapa da cadeia da modelagem como busca (CMM2SP)
é transformar o metamodelo e suas restrições em um programa de busca, e a última etapa
(SS2M) é transformar o modelo da solução encontrada pelo resolvedor em um modelo
em conformidade com o metamodelo CMM. Portanto, para realizar a transformação do
modelo da solução, precisamos de duas etapas (figura 4.1):
1. Consiste no passo reverso da CMM2SP, isto é, o metamodelo CMM é extraı́do do
programa de busca em um metamodelo no espaço tecnológico MDE (transformação
SP2MM).
40
2. Consiste na execução da TIMeR, que recebe como entrada o metamodelo CMM
produzido em (1) e o modelo com a solução do resolvedor.
c2
ECore
Figura 4.1: Abordagem Independente de Resolvedor
A transformação SP2MM pode ser implementada com qualquer linguagem de transformação. Na transformação SP2MM as restrições não precisam ser transformadas, basta
os elementos do metamodelo, em seguida podemos apenas importar as restrições do problema original. As soluções encontradas pelo resolvedor já satisfazem as restrições originais.
O programa de busca, que contém o modelo parcial, restrições e metamodelo de saı́da,
está em outro espaço tecnológico, geralmente em formato de texto da linguagem do resolvedor. Por isso, dependendo do resolvedor utilizado é preciso realizar uma injeção
prévia.
A TIMeR possui duas entradas: a solução do resolvedor e o metamodelo de saı́da.
Cada elemento da solução do resolvedor é processado, e então é criado um elemento no
modelo de saı́da, se houver uma correspondência entre o elemento do metamodelo de saı́da
e o elemento do programa de busca.
A seguir temos a definição da Transformação de Modelos Independente de Metamodelos usando Reflexão:
41
Definição 4.1 Definição da Transformação de Modelos Independente de Metamodelos
usando Reflexão:
Seja, MI =< GI , MMI , µI >, MMI =< Ga , MMM, µa > e MMO =< Gb , MMM, µb >,
onde MI é o modelo de entrada a ser transformado. MI está conforme MMI , e MMO
é o metamodelo de saı́da. A Transformação de Modelos Independente de Metamodelos
usando Reflexão cria um modelo MO =< GO , MMO , µO >, tal que MO está conforme
MMO e ∃x∃y|((x ∈ GI ∧ y ∈ Gb ∧ y := µI (x)) ↔ (∃z|z ∈ MO ∧ µO (z) := µI (x)))
Onde := é a operação reflexiva que retorna verdadeiro se os termos a direita e esquerda
são correspondentes (na maioria dos casos, se possuem o mesmo nome).
Analisando o último termo da definição, podemos ver que um elemento do modelo de
saı́da (z) corresponde a um elemento do modelo de entrada (x), se e somente se, o elemento
do metamodelo de entrada (que está atrelado a x) possui alguma correspondência com o
metamodelo de saı́da.
Um fator importante é a definição da operação “:=”. Nos exemplos testados considerouse que se os elementos possuem o mesmo nome (label), então eles são similares. Outras
definições podem aumentar a expressividade desta operação, mas ao custo de aumentar
sua complexidade de projeto e implementação.
A seguir veremos mais detalhes de como isso é feito na implementação da Injeção da
Solução usando o framework Alloy.
4.2
Instanciação com o Framework Alloy
Como o programa Alloy gerado e suas respectivas soluções estão em outro espaço tecnológico, é preciso injetá-los no espaço tecnológico MDE, para que sejam compatı́veis com
o ECore. Para realizar isso, temos duas transformações (injeções) adicionais às apresentadas na seção anterior. Para evitar a reimplementação de soluções já existentes explicitamos
quais passos desta cadeia de transformações são reutilizados ou então implementados por
este trabalho.
Como podemos ver na figura 4.2 ao todo temos quatro transformações:
42
Solução
Solução
Alloy
Alloy (XML)
(XML)
Figura 4.2: Transformação da Solução
1. Injeção do Programa Alloy em um Modelo Alloy, implementado em [37];
2. Injeção da Instância Alloy em um Modelo de Instâncias Alloy;
3. Transformação do Modelo de Programa Alloy em um metamodelo ECore;
4. Transformação de Modelos Independente de Metamodelos usando Reflexão.
Também se pode notar pelos retângulos triplos que podemos ter diferentes modelos e
metamodelos de entrada mantendo as mesmas transformações.
A primeira transformação é injeção do programa Alloy em um modelo de programa
Alloy. Nesta etapa foi utilizado o metamodelo de programa Alloy (figura 4.3) e o TCS
Parser Generator criados em [37], que permite a injeção/extração entre a versão textual e
o modelo de programa Alloy. Este TCS foi disponibilizado publicamente como um plugin
do eclipse em [36].
Para ilustrar o funcionamento de cada etapa, foi escolhido o estudo de caso de linhas de
produto de software para a modelagem como busca utilizado em [37]. Este estudo de caso
43
Figura 4.3: Metamodelo Alloy [37]
ilustra os possı́veis métodos que uma classe que simula o funcionamento de um relógio
deve possuir. Esta classe pode possuir os métodos: Start, Stop, DisplayTime, StartAlarm, StartVisualAlarm, StopAlarm, StartSoundAlarm. As restrições limitam quais
combinações de métodos são possı́veis. Por exemplo, um relógio deve possuir os métodos
Start e DisplayTime e se existir o método StartAlarm, o método StopAlarm também deve
estar presente.
Abaixo, temos um programa Alloy produzindo pela terceira etapa da cadeia da modelagem como busca. Este programa Alloy contém o metamodelo de saı́da, restrições e o
modelo parcial, e é usado como entrada na Transformação 1. Esta transformação injeta
esse código num modelo de programa Alloy em conformidade com o metamodelo da figura
4.3.
Código 4.1: Programa Alloy - Entrada para a Transformação 1
1
2
3
4
5
6
7
module watch
// M e t a m o d e l o
sig Root {
c l a s s i f i e r s : set Class
}
a b s t r a c t sig Class {
m e t h o d s : set Method
44
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
}
a b s t r a c t sig Method {
}
// Modelo p a r c i a l
sig Watch e x t e n d s Class {}
one sig Start e x t e n d s Method {}
one sig Stop e x t e n d s Method {}
one sig S t a r t A l a r m e x t e n d s Method {}
one sig D i s p l a y T i m e e x t e n d s Method {}
one sig S t a r t V i s u a l A l a r m e x t e n d s Method {}
one sig S t o p A l a r m e x t e n d s Method {}
one sig S t a r t S o u n d A l a r m e x t e n d s Method {}
// R e s t r i ç ~
oes
fact { one Root , all r : Root | # r . c l a s s i f i e r s = 1 }
fact { all c : Class | c in Watch }
fact { all c : Class | one m : Start | m in c . m e t h o d s }
fact { all c : Class | one m : D i s p l a y T i m e | m in c . m e t h o d s }
fact { all c : Class | Start in c . m e t h o d s = > Stop in c . m e t h o d s }
fact { all c : Class | S t a r t A l a r m in c . m e t h o d s <= > S t o p A l a r m in c .←֓
methods }
fact { all c : Class | S t a r t S o u n d A l a r m in c . m e t h o d s = > S t a r t A l a r m in c←֓
. methods }
fact { all c : Class | S t a r t V i s u a l A l a r m in c . m e t h o d s = > S t a r t A l a r m in ←֓
c. methods }
Figura 4.4: Metamodelo XML
O segundo passo é injetar a solução encontrada pelo framework Alloy em um modelo
de instâncias Alloy. Como esta solução é um documento XML, este passo é subdivido em
duas etapas:
1. Injeção em um modelo XML, usando um metamodelo XML já existente em [22]
(Figura 4.4). Esta injeção é feita através do injetor XML do AtlanMod MegaModel
Management (AM3) [6].
2. Posteriormente, este modelo XML é transformado usando ATL para um modelo em
conformidade com o metamodelo de instâncias Alloy (figura 4.5). O metamodelo
45
Figura 4.5: Metamodelo de Instâncias Alloy
de instâncias Alloy foi criado neste trabalho baseado nas especificações do esquema
XSD do XML da instância do Alloy, o que permite capturar as soluções.
Esta transformação foi implementada usando ATL e associa cada elemento do documento XML com seu respectivo elemento do metamodelo de instâncias Alloy. A seguir
temos um exemplo de instância (solução) gerada pelo Alloy que é utilizada como entrada
desta transformação. Esta instância contém um relógio com três métodos: Start, Stop e
DisplayTime (linhas 19-21).
Código 4.2: Solução do Resolvedor - Entrada para a Transformação 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
< alloy b u i l d d a t e ="2012 -09 -25 15:54 EDT " >
< i n s t a n c e b i t w i d t h ="4" maxseq ="4" c o m m a n d =" Run e x a m p l e for 1 Root , 1 ←֓
Class , 7 Method " f i l e n a m e =" C :\ U n t i t l e d 1. als " >
< sig label =" seq / Int " ID ="0" p a r e n t I D ="1" b u i l t i n =" yes " > </ sig >
< sig label =" Int " ID ="1" p a r e n t I D ="2" b u i l t i n =" yes " > </ sig >
< sig label =" String " ID ="3" p a r e n t I D ="2" b u i l t i n =" yes " > </ sig >
< sig label =" this / Root " ID ="4" p a r e n t I D ="2" >
< atom label =" Root$0 "/ >
</ sig >
< field label =" c l a s s i f i e r s " ID ="5" p a r e n t I D ="4" >
< tuple > < atom label =" Root$0 "/ > < atom label =" W a t c h $ 0"/ > </ tuple >
< types > < type ID ="4"/ > < type ID ="6"/ > </ types >
</ field >
< sig label =" this / Watch " ID ="7" p a r e n t I D ="6" >
< atom label =" W a t c h $ 0 "/ >
</ sig >
< sig label =" this / Class " ID ="6" p a r e n t I D ="2" a b s t r a c t =" yes " >
</ sig >
< field label =" m e t h o d s" ID ="8" p a r e n t I D ="6" >
46
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
< tuple > < atom label =" W a t c h $ 0"/ > < atom label =" S t a r t $ 0 "/ > </ tuple >
< tuple > < atom label =" W a t c h $ 0"/ > < atom label =" Stop$0 "/ > </ tuple >
< tuple > < atom label =" W a t c h $ 0"/ > < atom label =" D i s p l a y T i m e $ 0 "/ > </←֓
tuple >
< types > < type ID ="6"/ > < type ID ="9"/ > </ types >
</ field >
< sig label =" this / Start " ID ="10" p a r e n t I D ="9" one =" yes " >
< atom label =" S t a r t $ 0 "/ >
</ sig >
< sig label =" this / Stop " ID ="11" p a r e n t I D ="9" one =" yes " >
< atom label =" Stop$0 "/ >
</ sig >
< sig label =" this / S t a r t A l a r m" ID ="12" p a r e n t I D ="9" one =" yes " >
< atom label =" S t a r t A l a r m $ 0 "/ >
</ sig >
< sig label =" this / D i s p l a y T i m e " ID ="13" p a r e n t I D ="9" one =" yes " >
< atom label =" D i s p l a y T i m e $ 0 "/ >
</ sig >
< sig label =" this / S t a r t V i s u a l A l a r m " ID ="14" p a r e n t I D ="9" one =" yes " >
< atom label =" S t a r t V i s u a l A l a r m $ 0 "/ >
</ sig >
< sig label =" this / S t o p A l a r m" ID ="15" p a r e n t I D ="9" one =" yes " >
< atom label =" S t o p A l a r m $ 0 "/ >
</ sig >
< sig label =" this / S t a r t S o u n d A l a r m " ID ="16" p a r e n t I D ="9" one =" yes " >
< atom label =" S t a r t S o u n d A l a r m $ 0 "/ >
</ sig >
< sig label =" this / Method " ID ="9" p a r e n t I D ="2" a b s t r a c t =" yes " >
</ sig >
< sig label =" univ " ID ="2" b u i l t i n =" yes " >
</ sig >
</ instance >
</ alloy > $
A terceira transformação utiliza como entrada o resultado da transformação 1 e cria
um metamodelo ECore. Os mapeamentos desta transformação estão resumidos na tabela
4.1. Basicamente as assinaturas (signatures) do programa Alloy são mapeadas em EClass
do ECore, e os campos (fields) são mapeados em EReference (quando uma assinatura
faz referência a outra assinatura) ou EAttribute, quando as assinatura possui campos de
tipos primitivos. As cardinalidades foram implementadas de acordo com a referência da
linguagem Alloy [44].
Na figura 4.6 temos o resultado dessa transformação para o exemplo. Comparando
com a entrada da Transformação 1 (Código 4.1), podemos ver que o resultado é correto
e o eclipse verifica corretamente que o modelo é bem formado.
Finalmente temos o quarto passo: a Transformação de Modelos Independente de Metamodelos usando Reflexão.
47
Elementos do Metamodelo
de Alloy
Module
Signatures
Field
Field
ExternalType
Elementos do ECore
EPackage
EClass
EReference
EAttribute
EDataType
Tabela 4.1: Mapeamento entre o metamodelo Alloy e ECore
Figura 4.6: Metamodelo ECore produzido pela transformação 3.
4.3
Transformação de Modelos Independente de Metamodelos
usando Reflexão
Nesta etapa os resultados das transformações 2 e 3 (modelo com a solução do resolvedor
e o metamodelo de saı́da) são utilizados como entrada para produzir um modelo que está
em conformidade com o metamodelo de saı́da. Esta transformação foi implementada
em java devido a sua fácil integração com o framework Alloy, e utiliza a API do EMF.
Em especial os métodos de reflexão, que permite conhecer e manipular os elementos dos
modelos carregados em tempo de execução. Esta transformação (para o caso do framework
Alloy) é genérica e produz um modelo para qualquer metamodelo de saı́da, pois utiliza a
API reflexiva do EMF para obter as informações necessárias para criar o modelo de saı́da.
A Tabela 4.2 lista as principais classes e métodos reflexivos utilizados na implementação.
Classes
EObject,
EStructuralFeature,
EClass, EReference
Métodos
getName(), eGet(), getEType()
Tabela 4.2: Principais classes e métodos do ECore usados na implementação
Esta transformação se baseia no fato de que os metamodelos de entrada e saı́da pos-
48
suem alguma relação entre eles, determinada pelo operador :=. A relação entre modelo
e metamodelo permite identificar quais elementos do modelo estão ligados aos elementos do metamodelo de saı́da. Com isso, o metamodelo de instâncias Alloy serve como
uma ponte entre as soluções encontradas e o metamodelo de saı́da gerado a partir do
programa Alloy que gerou essa solução. As soluções são apenas átomos (atoms) (gerados
a partir de assinaturas) e as relações entre eles (campos). Dada a definição de modelo
M =< G, MM, µ >, os átomos são vértices do grafo G do modelo, os campos representam as arestas deste grafo. A relação entre átomo e assinatura é dada pela função µ (isto
é, se A é um átomo e S é uma assinatura µ(A) = S), esta relação é dada pela capacidade de rastreamento fornecida pelo resolvedor e pela reflexão. Por exemplo, na figura
4.5 temos as classes Atom e Sig, que representam átomos e assinaturas, respectivamente.
A associação ’type’ entre Atom e Sig fornece a informação de restreamento, indicado a
qual assinatura (classe) pertence este átomo (instância da classe). Neste caso a função
µ é definida como µ(A) = A.type. Com isso, podemos criar uma relação entre átomos e
campos para obter qualquer modelo de saı́da desejado.
Note que para outros resolvedores, basta usar esta informação de rastreamento para
auxiliar a definição da ligação dos elementos da solução com as instâncias dos elementos
do metamodelo do problema (isto é, o operador :=). Portanto a rastreabilidade da solução
do resolvedor é um dos requisitos desta abordagem.
O apêndice A lista o código java utilizado nessa transformação, e a seguir (algoritmo
4.1)temos o pseudocódigo do núcleo dessa transformação:
Os atributos label, type, owner, ref, origin estão definidos no metamodelo de instâncias
da figura 4.5, e correspondem, respectivamente, a: nome do elemento, assinatura a qual o
átomo pertence, assinatura a qual o campo pertence, átomo de destino do campo e átomo
de origem do campo.
A linha 1 cria um modelo de saı́da vazio em conformidade com o metamodelo de saı́da
apresentado à TIMeR.
As linhas 2-3 indicam que para cada átomo da solução é criada uma instância da
classe que possui o nome A.type.label. A.type representa a assinatura de origem deste
49
Algoritmo 4.1 Pseudocódigo da TIMeR
TIMeR (Metamodelo De Saı́da MM, Modelo de Instâncias Alloy MI)
1: ModeloSaı́da = new ModeloComforme(MM);
2: for each Átomo A in MI do
3:
C’ = criaInstânciaDaClasse(pegaClassePeloNome(A.type.label));
4:
ModeloSaida.AdicionaObjeto(C’);
5: end for each
6: for each Campo C in MI do
7:
R = pegaReferênciaPeloNome(C.label);
8:
if R != nulo then
9:
ModeloSaı́da.pegaObjetoPeloNome(C.origin.label).criaInstânciaDaReferência(R,
C.ref.label);
10:
end if
11:
T = pegaAtributoPeloNome(C.label);
12:
if T != nulo then
13:
ModeloSaı́da.pegaObjetoPeloNome(C.origin.label).criaInstânciaDoAtributo(T,
C.ref);
14:
end if
15: end for each
16: return ModeloSaı́da
átomo, é uma informação de rastreamento da solução do resolvedor. Esta assinatura está
atrelada a um elemento do metamodelo de saı́da porque, a função “:=” foi definida como
a igualdade do atributo label, e este atributo é obtido através da API de reflexão do EMF.
A linha 4 adiciona esta instância ao modelo.
Tendo criados todas as instâncias necessárias, basta agora adicionar atributos e referências entre as classes. Na linha 5 cada campo da solução e iterado e é realizada a
criação dos atributos e referências necessários.
Nas linhas 7-8, a função pegaReferênciaPeloNome busca no conjunto de referências
do metamodelo se existe uma que possui o nome C.label. Caso afirmativo, na linha 9,
esta referência é adicionada ao objeto da solução que possui o nome C.origin.label para o
objeto C.ref.label.
Nas linhas 11-12, a função pegaAtributoPeloNome, de modo similar, retorna o atributo
do metamodelo que possui o nome C.label. Caso exista este atributo, na linha 13, a
instância do atributo é adicionada ao objeto da solução que possui o nome C.origin.label e
valor C.ref. O tipo do atributo é inferido através da reflexão, onde a classe do metamodelo
com nome C.owner.label possui o atributo de nome C.label. Para tratar casos onde classes
50
diferentes possuem atributos com o mesmo nome, é usado o valor de C.owner.label para
obter a classe correta através da reflexão.
Finalmente, na linha 16 o modelo completo é retornado.
Na figura 4.7 temos o resultado da transformação 4. Um modelo que está em conformidade com o metamodelo produzido pela transformação 3. Mais uma vez, este modelo foi
corretamente verificado pelo Eclipse. Nesta saı́da o relógio produzido possui os métodos
Start, Stop e DisplayTime.
Figura 4.7: Saı́da da Transformação 4
Finalmente, com estas quatro transformações combinadas, temos um único código
para injetar a solução de qualquer programa Alloy no espaço tecnológico MDE.
Porém, esta abordagem possui suposições que introduzem algumas restrições: (1) a
implementação depende do resolvedor utilizado; (2) apenas os aspectos estruturais dos
modelos foram considerados.
Para utilizar outro resolvedor, como por exemplo o ECLiPSe, é preciso reimplementar
as quatro etapas. Para a transformação 1 é preciso definir um novo metamodelo do
programa ECLiPSe e implementar o seu respectivo injetor. Para a transformação 2 é
preciso criar um metamodelo de instâncias e seu respectivo injetor. Para a transformação 3
é preciso reimplementar a transformação utilizando o metamodelo criado na transformação
1. Finalmente, código da TIMeR deve ser reescrito utilizando o metamodelo de instâncias
utilizado na transformação 2.
O metamodelo de instâncias do resolvedor é fixo porque depende do resolvedor utilizado. O código da transformação usa os elementos deste metamodelo para fazer a ponte
entre o modelo da solução do resolvedor e o modelo de saı́da. Por exemplo, um campo da
51
solução Alloy possui um átomo de partida e outro de destino. A transformação usa essa
informação para criar referências entre as classes correspondentes a esses átomos. No caso
da injeção da solução, e onde apenas o metamodelo de saı́da é diferente, esta abordagem
é muito boa, temos uma única transformação para diversos metamodelos de saı́da.
A implementação atual considera apenas os aspectos estruturais dos modelos. Para
suportar modelos comportamentais é preciso estender a abordagem atual e considerar o
elemento EOperation do Ecore.
Esta abordagem é diferente da JTL porque não é necessário criar uma transformação
especı́fica em tempo de execução para cada metamodelo de saı́da.
A seguir temos os resultados obtidos com um estudo de caso de linha de produto de
software e a transformação de modelo de classe para relacional.
52
CAPÍTULO 5
EXPERIMENTOS
Neste capı́tulo apresentaremos os resultados da implementação utilizando dois estudos de caso. O primeiro estudo de caso é a Linhas de Produto de Software (Software
Product Lines, SPL) [15] para a modelagem como busca, e o segundo estudo de caso é a
transformação Class2Relational [22] para a transformação como busca. Nestes dois estudos de caso, apenas os dois arquivos de entrada (programa Alloy e solução Alloy) foram
modificados. O código das transformações usado em todas as fases da cadeia é o mesmo.
Os arquivos com as soluções foram gerados pelo Alloy usando o resolvedor SAT4J [10].
As quatro transformações foram executadas em sequência. Em seguida, o modelo de
saı́da produzido foi verificado empiricamente usando as ferramentas da IDE Eclipse. Esta
verificação consiste em determinar se o modelo está em conformidade com o metamodelo
e se a saı́da está de acordo com a solução produzida pelo resolvedor.
O computador usado em todos os testes possui a seguinte configuração: Processador:
Intel Core i5 2.8 GHz com 8GB de memória RAM com o sistema operacional Windows 7
64-bits. A versão utilizada do Java foi a 1.7.1 32-bits.
5.1
Linhas de Produto de Software
As linhas de produto de software permitem criar um conjunto de sistemas de software
similares a partir de uma especificação comum a todos estes sistemas [37]. O primeiro é
definir um modelo para o domı́nio compartilhado (especificação do sistema, suas caracterı́sticas, componentes e pontos de variação). No contexto da modelagem como busca,
este modelo de domı́nio compartilhado é o metamodelo com restrições.
O exemplo do SPL utilizado é o mesmo de [37]. O metamodelo utilizado neste estudo
de caso (figura 5.3) permite definir classes, e estas classes possuem métodos. O objetivo
é gerar classes que simulam a execução de um relógio. No caso, há cinco possı́veis tipos
53
de relógios a serem produzidos: 1) simples; 2) com alarme; 3) com alarme sonoro; 4) com
alarme sonoro e visual; e 5) com alarme visual. Estas combinações são determinadas pelas
restrições do metamodelo. Estas restrições estão no código 4.1 do capı́tulo anterior.
Figura 5.1: Metamodelo de Classe do estudo de caso SPL
Abaixo temos o resultado da cadeia de transformações: um documento XML produzido
corretamente utilizando a TIMeR. Graficamente este modelo é exibido na figura 5.2. A
solução encontrada pelo Alloy possui os métodos Start, Stop e DisplayTime. Da mesma
forma, podemos ver que no modelo gerado Watch possui referências aos métodos Start,
Stop e DisplayTime. Para as outras soluções os resultados foram similares.
Figura 5.2: Modelo produzido pela TIMeR para o estudo de caso SPL
Etapa
Transformação
Transformação
Transformação
Transformação
Total
1
2
3
4
Tempo Médio
0,0952
2,5007
0,9516
0,6792
4,2267
Tabela 5.1: Tempo médio em segundos de cada etapa do estudo de caso SPL
Na tabela 5.1 temos os tempos de execução em segundos de cada etapa da cadeia. A
54
Entrada
Programa Alloy
Instância Alloy
Tamanho
11 assinaturas, 2 campos
15 assinaturas, 9 átomos, 2 campos, 4 tuplas
Tabela 5.2: Tamanho da entrada de cada etapa do estudo de caso SPL
cadeia foi executada 20 vezes e inclui o tempo de serialização e deserialização dos modelos
em cada etapa. O tamanho das entradas é dado na tabela 5.2.
5.2
Transformação Classe para Relacional
O segundo estudo de caso testado foi o primeiro cenário da transformação como busca
em [38], isto é, a transformação Class2Relational. O objetivo desta transformação é
transformar um modelo de classe em um modelo relacional.
A figura 4.1 ilustra o modelo de classe utilizado como entrada para a transformação
como busca.
Figura 5.3: Metamodelo de Classe usado como entrada
Mais uma vez, o programa Alloy e sua respectiva solução são utilizados como entrada
para a cadeia de transformações. Na figura 5.4 temos o modelo gerado e verificado pelo
Eclipse.
Neste caso a transformação como busca produz como saı́da os dois modelos, o de
classe e o relacional, pois a TIMeR recebeu como entrada um metamodelo que continha
a unificação dos metamodelos de entrada e saı́da. Como vimos anteriormente, na transformação como busca há um passo posterior chamado ’cut’ que extrai desta solução o
modelo de interesse. Também é possı́vel obter apenas a solução do modelo relacional se o
metamodelo de saı́da apresentado à TIMeR for apenas o metamodelo relacional. A figura
55
Figura 5.4: Saı́da do estudo de caso Class2Relational
Figura 5.5: Metamodelo relacional [22]
5.6 ilustra este exemplo como o metamodelo de saı́da na figura 5.5 apresentado à TIMeR
e o modelo produzido na figura 5.6. Neste caso o arquivo de entrada da solução foi o
mesmo.
Na tabela 5.3 temos os tempos médios de execução em segundos, e na tabela 5.4 temos
o tamanho das entradas da cadeia.
Podemos ver mais uma vez que o tempo de execução da transformação 2 foi responsável por grande parte do tempo de processamento (98%). Apesar do tamanho da
56
Figura 5.6: Saı́da do estudo de caso Class2Relational com a operação cut
Etapa
Transformação
Transformação
Transformação
Transformação
Total
1
2
3
4
Tempo Médio
0,1266
185,084
1,2015
0,7901
187,202
Tabela 5.3: Tempo médio em segundos de cada etapa da cadeia para o estudo de caso
Class2Relational
Entrada
Programa Alloy
Instância Alloy
Tamanho
39 assinaturas, 23 campos
43 assinaturas, 55 átomos, 23 campos, 116 tuplas
Tabela 5.4: Tamanho da entrada de cada etapa do estudo de caso Class2Relational
solução do estudo de caso Class2Relational conter mais elementos, o tempo das outras
três transformações não aumentaram proporcionalmente.
No próximo capı́tulo será apresentado as conclusões e sugestões para trabalhos futuros.
57
CAPÍTULO 6
CONCLUSÕES E TRABALHOS FUTUROS
Nesta dissertação foi apresentada uma abordagem que possibilita a interoperabilidade
de modelos escritos no espaço tecnológico da engenharia dirigida por modelos (MDE) com
programas escritos no espaço tecnológico de resolvedores de busca. Esta interoperabilidade
permite que aplicações MDE tirem proveito das capacidades de resolvedores de busca para
executar operações complexas.
Para permitir esta interoperabilidade, foi desenvolvida uma cadeia com quatro transformações de modelos. Estas transformações realizam uma injeção dos dados do programa
do resolvedor de busca em um modelo e metamodelos no formato de uma plataforma MDE.
Destas quatro transformações, uma tem a particularidade de poder ser implementada
sem o conhecimento do metamodelo de saı́da. Este será interpretado no momento da
execução. Por isso a abordagem é chamada de Transformação independente de Metamodelo.
O desenvolvimento da solução teve diferentes contribuições, descritas abaixo:
1. Implementação de um caso de uso de transformação de modelos usando um resolvedor de busca, para avaliação da abordagem chamada “Transformação como Busca”.
Foi escolhida a transformação Class2Relational, por ser uma referência em aplicações
MDE. Esta implementação fortaleceu a hipótese da necessidade de automatização
da cadeia de interoperabilidade entre os diferentes espaços tecnológicos.
2. Definição de uma cadeia de quatro transformações para transformar a solução no
formato do resolvedor em um modelo em conformidade com o metamodelo de saı́da
para uma operação de modelagem como busca. A cadeia de operações foi instanciada usando o framework Alloy. As três primeiras transformações são relativas a
interoperabilidade entre os espaços tecnológicos:
58
2.1 Injeção do programa Alloy em um modelo de programa Alloy no espaço tecnológico MDE.
2.2 Injeção da solução do framework Alloy num modelo XML, e em seguida este
modelo é transformado em um modelo de instâncias Alloy. Este modelo de
instâncias Alloy está em conformidade com um metamodelo criado a partir do
esquema XSD utilizado pelos documentos XML que armazenam a solução do
framework Alloy.
2.3 Extração do metamodelo de saı́da a partir do modelo de programa Alloy.
2.4 Definição de uma transformação independente do metamodelo de saı́da (TIMeR). Esta transformação permite injetar um modelo no espaço tecnológico
MDE em conformidade com um metamodelo conhecido apenas durante o tempo
de execução. A TIMeR, diferente das abordagens atuais, recebe como entrada
tanto o metamodelo de saı́da quanto o modelo com a solução do resolvedor.
A TIMeR produz como saı́da um modelo conforme a este metamodelo de entrada. Para que a transformação possa ser executada, foi necessário definir
uma função de mapeamento entre o modelo e seu respectivo metamodelo.
Pelos resultados encontrados foi verificado que esta abordagem é viável e o objetivo foi
alcançado. As soluções foram injetadas corretamente no espaço tecnológico MDE em dois
casos de estudo. A escrita de uma única transformação foi capaz de realizar transformações
para diferentes metamodelos de saı́da. O uso dos métodos de reflexão do framework EMF
permitiu a TIMeR obter as informações necessárias dos modelos e metamodelos, para que
durante o tempo da execução o modelo de entrada fosse transformado de forma adequada.
Analisando os pontos em aberto da abordagem, verificou-se que a implementação
depende do resolvedor utilizado. Caso seja utilizado outro resolvedor, é preciso reimplementar todas as etapas da cadeia. Como já explicitado, uma das suposições da TIMeR é
considerar que os modelos de entrada e saı́da possuam uma estrutura similar, definida por
uma função de similaridade entre os elementos dos metamodelo. Na implementação atual
esta similaridade é definida por elementos de nomes iguais e de tipos correspondentes.
59
Isto é uma limitação que a impede de ser usada de forma geral, porém no caso de injeções
de soluções de resolvedores não há este problema. Entretanto, a abordagem é extensı́vel
por permitir a trocar a função de mapeamento. Outra limitação da abordagem é que são
considerados apenas os aspectos estruturais do modelo, para tratar os aspectos dinâmicos
dos modelos é preciso estender a abordagem atual.
Há diferentes possibilidades de trabalhos futuros, como descrevemos abaixo:
• Utilizar uma variação desta abordagem para implementar a geração dos dados de
busca (transformação M2SP) da cadeia da modelagem como busca. Nesta transformação o metamodelo de entrada é desconhecido, e o modelo de entrada deve ser
transformado em um modelo de programa Alloy.
• Otimização das quatro etapas da cadeia. Principalmente uma nova implementação
da transformação 2, possivelmente usando a própria API do EMF, de modo a melhorar o tempo de execução.
• Pode ser investigado o uso de um modelo de correspondências entre as entradas da
transformação 4 para permitir flexibilizar ainda mais esta abordagem.
• Implementação destas transformações usando outros resolvedores de programação
por restrições.
60
BIBLIOGRAFIA
[1] IBM ILOG CPLEX Optimizer. http://www-01.ibm.com/software/integration/
optimization/cplex-optimizer/, 2010.
[2] Atl developer guide. http://wiki.eclipse.org/ATL/Developer_Guide, 2013.
[3] Ocl+ usecase. http://www.lsis.org/kleinerm/MS/OCLP_mm.html, 2013.
[4] SAPos - sistema de apoio à pós-graduação. http://web.inf.ufpr.br/didonet/
sapos-sistema-de-apoio-a-pos-graduacao, 2013.
[5] Francis Alizon, Mariano Belaunde, Grégoire DuPre, Bertrand Nicolas, Sébastien Poivre, e Jacques Simonin. Les modèles dans l’action à France Télécom avec SmartQVT.
Génie logiciel: Congrès Journées Neptune No5, 2007.
[6] Freddy Allilaire, Jean Bezivin, Hugo Bruneliere, e Frederic Jouault. Global Model
Management In Eclipse GMT/AM3. 2006.
[7] Krzysztof Apt. Principles of Constraint Programming. Cambridge University Press,
New York, NY, USA, 2003.
[8] Krzysztof R. Apt e Mark Wallace. Constraint Logic Programming using Eclipse.
Cambridge University Press, New York, NY, USA, 2007.
[9] Thorsten Arendt, Enrico Biermann, Stefan Jurack, Christian Krause, e Gabriele
Taentzer. Henshin: Advanced concepts and tools for in-place emf model transformations. DorinaC. Petriu, Nicolas Rouquette, e Oystein Haugen, editors, Model Driven
Engineering Languages and Systems, volume 6394 of Lecture Notes in Computer Science, páginas 121–135. Springer Berlin Heidelberg, 2010.
[10] Daniel Le Berre e Anne Parrain. The sat4j library, release 2.2. JSAT, 7(2-3):59–6,
2010.
61
[11] Matthias Biehl. Literature Study on Model Transformations. Relatório Técnico
ISRN/KTH/MMK/R-10/07-SE, Royal Institute of Technology, julho de 2010.
[12] Marco Brambilla, Jordi Cabot, e Manueal Wimmer. Model-Driven Software Engineering in Practice. Synthesis Lectures on Software Engineering.
[13] Jordi Cabot, Robert Clarisó, e Daniel Riera. Umltocsp: A tool for the formal verification of uml/ocl models using constraint programming. Proceedings of the Twentysecond IEEE/ACM International Conference on Automated Software Engineering,
ASE ’07, páginas 547–548, New York, NY, USA, 2007. ACM.
[14] Antonio Cicchetti, Davide Di Ruscio, Romina Eramo, e Alfonso Pierantonio. Jtl:
A bidirectional and change propagating transformation language. Brian A. Malloy,
Steffen Staab, e Mark van den Brand, editors, SLE, volume 6563 of Lecture Notes in
Computer Science, páginas 183–202. Springer, 2010.
[15] Paul Clements e Linda Northrop. Software Product Lines: Practices and Patterns.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 2001.
[16] Stephen A. Cook. The complexity of theorem-proving procedures. Proceedings of the
third annual ACM symposium on Theory of computing, STOC ’71, páginas 151–158,
New York, NY, USA, 1971. ACM.
[17] György Csertán, Gábor Huszerl, István Majzik, Zsigmond Pap, András Pataricza,
e Dániel Varró. Viatra ”visual automated transformations for formal verification
and validation of uml models. Proceedings of the 17th IEEE international conference
on Automated software engineering, ASE ’02, páginas 267–, Washington, DC, USA,
2002. IEEE Computer Society.
[18] Krzysztof Czarnecki e Simon Helsen. Feature-based survey of model transformation
approaches. IBM Syst. J., 45(3):621–645, julho de 2006.
[19] Marcos Didonet Del Fabro. Metadata management using model weaving and model
transformations. Tese de Doutorado, University of Nantes, setembro de 2007.
62
[20] Eclipse Modeling Project. Xpand / xtend reference, 2012.
[21] Eclipse.org.
Atl
transformation
example
-
book
to
publication.
http://www.eclipse.org/atl/atlTransformations/Book2Publication/
ExampleBook2Publication[v00.02].pdf, 2013.
[22] Eclipse.org.
Atl transformation examples.
http://www.eclipse.org/atl/
atlTransformations/, 2013.
[23] Niklas Eén e Niklas Sörensson. An extensible sat-solver. Enrico Giunchiglia e Armando Tacchella, editors, SAT, volume 2919 of Lecture Notes in Computer Science,
páginas 502–518. Springer, 2003.
[24] Sven Efftinge, Peter Friese, Arno Haase, Clemens Kadura, Bernd Kolb, Dieter Moroff,
Karsten Thoms, e Markus Völter. open Architecture Ware User Guide, 2007.
[25] John Ellson, Emden R. Gansner, Eleftherios Koutsofios, Stephen C. North, e Gordon
Woodhull. Graphviz - Open Source Graph Drawing Tools. Graph Drawing, páginas
483–484, 2001.
[26] Ramez A. Elmasri e Shankrant B. Navathe. Fundamentals of Database Systems.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 3rd edition, 1999.
[27] Martin Gogolla, Fabian Büttner, e Mark Richters. Use: A uml-based specification
environment for validating uml and ocl. Sci. Comput. Program., 69(1-3):27–34, dezembro de 2007.
[28] Philipp Huber. The Model Transformation Language Jungle - An Evaluation and
Extension of Existing Approaches. Dissertação de Mestrado, Technische Universität
Wien, maio de 2008.
[29] Aleksandar. Torlak Emina. Kang Eunsuk. Jackson, Daniel. Milicevic e Joe Near.
Alloy 4.2. http://alloy.mit.edu/alloy/, 2013.
63
[30] Daniel Jackson. Automating first-order relational logic. Proceedings of the 8th ACM
SIGSOFT international symposium on Foundations of software engineering: twentyfirst century applications, SIGSOFT ’00/FSE-8, páginas 130–139, New York, NY,
USA, 2000. ACM.
[31] Daniel Jackson. Software Abstractions: Logic, Language, and Analysis. The MIT
Press, 2006.
[32] Joxan Jaffar e Michael J. Maher. Constraint Logic Programming: A Survey. Journal
of Logic Programming, 19/20:503–581, 1994.
[33] Frédéric Jouault, Freddy Allilaire, Jean Bézivin, e Ivan Kurtev. Atl: A model transformation tool. Sci. Comput. Program., 72(1-2):31–39, junho de 2008.
[34] Frédéric Jouault, Jean Bézivin, e Ivan Kurtev. Tcs:: A dsl for the specification of
textual concrete syntaxes in model engineering. Proceedings of the 5th International
Conference on Generative Programming and Component Engineering, GPCE ’06,
páginas 249–254, New York, NY, USA, 2006. ACM.
[35] Stuart Kent. Model driven engineering. Proceedings of the Third International Conference on Integrated Formal Methods, IFM ’02, páginas 286–298, London, UK, UK,
2002. Springer-Verlag.
[36] Mathias Kleiner, Marcos Didonet Del Fabro, e Patrick Albert. Alloy metamodel and
tcs usecase for model search. http://www.lsis.org/kleinerm/MS/Alloy_mm.html,
2010.
[37] Mathias Kleiner, Marcos Didonet Del Fabro, e Patrick Albert. Model search: Formalizing and automating constraint solving in mde platforms. Thomas Kuhne, Bran
Selic, Marie-Pierre Gervais, e François Terrier, editors, ECMFA, volume 6138 of Lecture Notes in Computer Science, páginas 173–188. Springer, 2010.
64
[38] Mathias Kleiner, Marcos Didonet Del Fabro, e Davi De Queiroz Santos. Transformation as search. Pieter Van Gorp, Tom Ritter, e Louis M. Rose, editors, ECMFA,
volume 7949 of Lecture Notes in Computer Science, páginas 54–69. Springer, 2013.
[39] Dimitrios S. Kolovos, Richard F. Paige, e Fiona A.C. Polack. The epsilon transformation language. Antonio Vallecillo, Jeff Gray, e Alfonso Pierantonio, editors, Theory
and Practice of Model Transformations, volume 5063 of Lecture Notes in Computer
Science, páginas 46–60. Springer Berlin Heidelberg, 2008.
[40] Philippe Kruchten. The Rational Unified Process: An Introduction. Addison-Wesley
Longman Publishing Co., Inc., Boston, MA, USA, 3 edition, 2003.
[41] Ivan Kurtev. State of the art of qvt: A model transformation language standard.
Andy Schurr, Manfred Nagl, e Albert Zundorf, editors, Applications of Graph Transformations with Industrial Relevance, volume 5088 of Lecture Notes in Computer
Science, páginas 377–393. Springer Berlin Heidelberg, 2008.
[42] Jean marie Favre. Towards a basic theory to model model driven engineering. In
Proc. of the UML2004 Int. Workshop on Software Model Engineering, 2004.
[43] Tom Mens e Pieter Van Gorp. A taxonomy of model transformation. Electron. Notes
Theor. Comput. Sci., 152:125–142, março de 2006.
[44] MIT. Alloy language reference. http://alloy.mit.edu/alloy/documentation/
book-chapters/alloy-language-reference.pdf, 2013.
[45] Naouel Moha, Sagar Sen, Cyril Faucher, Olivier Barais, e Jean-Marc Jezequel. Evaluation of kermeta for solving graph-based problems. Int. J. Softw. Tools Technol.
Transf., 12(3-4):273–285, julho de 2010.
[46] Matthew W. Moskewicz, Conor F. Madigan, Ying Zhao, Lintao Zhang, e Sharad
Malik. Chaff: Engineering an efficient sat solver. Proceedings of the 38th Annual
Design Automation Conference, DAC ’01, páginas 530–535, New York, NY, USA,
2001. ACM.
65
[47] Object Management Group, Inc. UML Object Constraint Language (OCL) 2.0 Specification, outubro de 2006.
[48] OMG. Model Driven Architecture (MDA) Guide, 2003. OMG doc. ab/2003-06-01.
[49] OMG. Meta Object Facility (MOF) Core Specification, 2006.
[50] OMG. XML Metadata Interchange (XMI). OMG, 2007.
[51] OMG. Meta Object Facility (MOF) 2.0 Query/View/Transformation (QVT), 2011.
[52] Jean remy Falleri, Marianne Huchard, e Clementine Nebut. C.: Towards a traceability framework for model transformations in kermeta. In: ECMDA-TW Workshop,
2006.
[53] James Rumbaugh, Ivar Jacobson, e Grady Booch. Unified Modeling Language Reference Manual, The (2Nd Edition). Pearson Higher Education, 2004.
[54] Andy Schurr. Specification of graph translators with triple graph grammars. Ernst W.
Mayr, Gunther Schmidt, e Gottfried Tinhofer, editors, Graph-Theoretic Concepts in
Computer Science, volume 903 of Lecture Notes in Computer Science, páginas 151–
163. Springer Berlin Heidelberg, 1995.
[55] Roger S. Scowen. Extended BNF - A Generic Base Standard. Proceedings of the
1993 Software Engineering Standards Symposium (SESS’93), agosto de 1993.
[56] David Steinberg, Frank Budinsky, Marcelo Paternostro, e Ed Merks. EMF: Eclipse
Modeling Framework 2.0. Addison-Wesley Professional, 2nd edition, 2009.
[57] Leon Sterling e Ehud Shapiro. The Art of Prolog (2Nd Ed.): Advanced Programming
Techniques. MIT Press, Cambridge, MA, USA, 1994.
[58] W3C. Extensible markup language (xml) 1.0. http://www.w3.org/TR/REC-xml/,
2008.
[59] W3C. Xml schema 1.1. http://www.w3.org/XML/Schema/, 2010.
66
APÊNDICE A
CÓDIGO DA TRANSFORMAÇÃO 4
Esta é a implementação em Java da TIMeR para transformar um modelo de instância
Alloy em um modelo em conformidade como o metamodelo de saı́da passado pelo segundo
parâmetro de execução.
Código A.1: Código Java da Transformação 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import
import
import
import
import
import
import
import
java . io . I O E x c e p t i o n ;
java . s e c u r i t y. A l l P e r m i s s i o n ;
java . util . A r r a y L i s t;
java . util . C o l l e c t i o n s ;
java . util . H a s h M a p;
java . util . I t e r a t o r;
java . util . List ;
java . util . Map ;
import
import
import
import
import
import
import
import
import
import
import
import
import
org . e c l i p s e. emf . common . util . URI ;
org . e c l i p s e. emf . ecore . EClass ;
org . e c l i p s e. emf . ecore . E D a t a T y p e ;
org . e c l i p s e. emf . ecore . E O b j e c t;
org . e c l i p s e. emf . ecore . E R e f e r e n c e;
org . e c l i p s e. emf . ecore . E S t r u c t u r a l F e a t u r e ;
org . e c l i p s e. emf . ecore . r e s o u r c e. R e s o u r c e;
org . e c l i p s e. emf . ecore . r e s o u r c e. R e s o u r c e S e t ;
org . e c l i p s e. emf . ecore . r e s o u r c e. impl . R e s o u r c e S e t I m p l ;
org . e c l i p s e. emf . ecore . util . E c o r e U t i l;
org . e c l i p s e. emf . ecore . xmi . X M L R e s o u r c e ;
org . e c l i p s e. emf . ecore . xmi . impl . X M I R e s o u r c e F a c t o r y I m p l ;
org . e c l i p s e. emf . ecore . E P a c k a g e;
public class T r a n s f o r m a c a o {
p r i v a t e List < EObject > a l l I n s t a n c e s = new ArrayList < EObject >() ;
p r i v a t e List < EPackage > a l l P a c k a g e s = new ArrayList < EPackage >() ;
p r i v a t e List < EClass > a l l C l a s s e s = new ArrayList < EClass >() ;
p r i v a t e List < E S t r u c t u r a lF ea tur e > allSF = new ArrayList <←֓
E S t r u c t u r a lF ea tu re >() ;
p r i v a t e List < EDataType > a l l D a t a T y p e s = new ArrayList < EDataType >() ;
private
>() ;
private
private
private
List < EObject > s o l u t i o n A l l I n s t a n c e s = new ArrayList < EObject ←֓
List < EObject > s o l u t i o n A l l A t o m s = new ArrayList < EObject >() ;
List < EObject > s o l u t i o n A l l F i e l d s = new ArrayList < EObject >() ;
List < EObject > s o l u t i o n A l l S i g s = new ArrayList < EObject >() ;
67
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
p r i v a t e HashMap < EObject , EObject > A t o m 2 E C l a s s = new HashMap <←֓
EObject , EObject >() ;
p r i v a t e HashMap < EObject , EObject > E C l a s s 2 A t o m = new HashMap < EObject ←֓
, EObject >() ;
p r i v a t e HashMap < EObject , List < EObject > > A t o m F i e l d s = new HashMap <←֓
EObject , List < EObject > >() ;
p r i v a t e HashMap < EObject , Map < String , List < EObject > > > A t o m F i e l d s 2 = ←֓
new HashMap < EObject , Map < String , List < EObject > > >() ;
public T r a n s f o r m a c a o ( String i n p u t E C o re Mod el , String ←֓
i n p u t A l l o y S o l u t io n Ec or e , String i n p u t A l l o y S o lut io n , String ←֓
o u t p u t R e s ul tM ode l , String r o o t C l a s s N a m e )
{
R e s o u r c e. F a c t o r y. R e g i s t r y reg = R e s o u r c e. F a c t o r y. R e g i s t r y.←֓
I N S T A N C E;
Map m = reg . g e t E x t e n s i o n T o F a c t o r y M a p () ;
m . put (" xmi " , new X M I R e s o u r c e F a c t o r y I m p l () ) ;
m . put (" ecore " , new X M I R e s o u r c e F a c t o r y I m p l () ) ;
R e s o u r c e S e t rs = new R e s o u r c e S e t I m p l () ;
R e s o u r c e e c o r e I n R e s = rs . g e t R e s o u r c e ( URI . c r e a t e U R I (""+←֓
i n p u t E C o r e M o d e l ) , true ) ;
// C a r r e g a ←֓
m e t a m o d e l o ecore
R e s o u r c e a l l o y S o l E c o r e I n R e s = rs . g e t R e s o u r c e( URI . c r e a t e U R I (""+←֓
i n p u t A l l o y S o l u t i o n E c o r e ) , true ) ;
// c a r r e g a m e t a m o d e l o ←֓
da s o l u ç ~
a o para e x t r a i r o pacote
E P a c k a g e epkg = ( E P a c k a g e) a l l o y S o l E c o r e I n R e s . g e t C o n t e n t s () . get←֓
(0) ;
// extrai o pacote
rs . g e t P a c k a g e R e g i s t r y () . put ( epkg . g e t N s U R I () , epkg ) ; ←֓
// r e g i s t r a o ←֓
pacote
R e s o u r c e a l l o y S o l I n R e s = rs . g e t R e s o u r c e ( URI . c r e a t e U R I (""+←֓
i n p u t A l l o y S o l u t i o n ) , true ) ;
// C a r r e g a o modelo ←֓
com a s o l u ç ~
a o o.
p r o c e s s E C o r e M o d e l ( e c o r e I n R e s) ;
processAlloySolution( alloySolInRes);
// E x e c u t a a t r a n s f o r m a ç ~
ao
List o u t E l e m e n t s = d o T r a n s f o r m a t i o n () ;
// Salva o modelo
URI uri = URI . c r e a t e U R I ("" + o u t p u t R e s u l t M o d e l ) ;
R e s o u r c e outRes = rs . c r e a t e R e s o u r c e ( uri ) ;
// System . out . p r i n t l n ("\ n \ n R e s u l t a d o da T r a n s f o r m a c a o \ n \ n ") ;
i m p r i m e R e s u l t a d o T r a n s f o r m a c a o ( o u t E l e m e n t s) ;
// System . out . p r i n t l n ("\ n \ n P r e p a r a n d o para salvar \ n \ n ") ;
/**/
List o b j s T o S e a r c h = new A r r a y L i s t () ;
List < EObject > d a n g l i n g O b j s = new A r r a y L i s t () ;
for ( I t e r a t o r i t e r a t o r = o u t E l e m e n t s . i t e r a t o r () ; i t e r a t o r.←֓
h a s N e x t () ;) {
68
79
80
81
E O b j e c t object = ( E O b j e c t) i t e r a t o r . next () ;
if (( object . e C o n t a i n e r () == null && ( r o o t C l a s s N a m e == null ||←֓
r o o t C l a s s N a m e . equals ("") ) )
|| ( object . e C o n t a i n e r () == null && object . eClass←֓
() . g e t N a m e () . equals ( r o o t C l a s s N a m e ) ) )
outRes . g e t C o n t e n t s () . add ( object ) ;
82
83
84
85
86
87
88
89
90
91
92
93
94
95
if ( E c o r e U t i l. getURI ( object ) . t o S t r i n g () . equals ( " # / / " )) {
d a n g l i n g O b j s . add ( object ) ;
}
else {
o b j s T o S e a r c h . add ( object ) ;
}
}
/**/
b o o l e a n c o m p l e t e d = false ;
Object c u r r e n t O b j = null ;
while ( ! c o m p l e t e d && ! ( r o o t C l a s s N a m e == null || r o o t C l a s s N a m e←֓
. equals ("") ) ) {
for ( Iterator < EObject > i t e r a t o r = d a n g l i n g O b j s . i t e r a t o r () ; ←֓
i t e r a t o r. h a s N e x t () ;) {
E O b j e c t object = ( E O b j e c t) i t e r a t o r . next () ;
if ( E c o r e U t i l. U s a g e C r o s s R e f e r e n c e r . find ( object , o b j s T o S e a r c h )←֓
. size () > 0) {
outRes . g e t C o n t e n t s () . add ( object ) ;
o b j s T o S e a r c h . add ( object ) ;
c u r r e n t O b j = object ;
c o m p l e t e d = false ;
break ;
}
c o m p l e t e d = true ;
}
if ( c o m p l e t e d || d a n g l i n g O b j s . size () == 0)
break ;
d a n g l i n g O b j s . remove ( c u r r e n t O b j ) ;
}
/**/
try {
if ( outRes . g e t C o n t e n t s () . size () > 0 ) {
outRes . save ( C o l l e c t i o n s . E M P T Y _ M A P) ;
}
else
System . out . p r i n t l n (" Modelo vazio ") ;
} catch ( I O E x c e p t i o n e ) {
System . out . p r i n t l n (" Erro ") ;
e . p r i n t S t a c k T r a c e () ;
}
/**/
System . out . p r i n t l n (" Pronto ") ;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
}
p r i v a t e List d o T r a n s f o r m a t i o n () {
List o u t E l e m e n t s = new A r r a y L i s t () ;
69
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// cria um e l e m e n t o do modelo para cada atom
for ( E O b j e c t atom : s o l u t i o n A l l A t o m s ) {
// Salva o label do atom e da sig do atom
String label = g e t V a l u e( atom , " label ") . t o S t r i n g () ;
String s i g L a b e l = g e t S i g L a b e l F r o m A t o m ( atom ) . t o S t r i n g () ;
s i g L a b e l = s i g L a b e l. split (" this /") [ s i g L a b e l. split (" this /") .←֓
length -1];
System . out . p r i n t l n (" atom "+ label ) ;
// System . out . p r i n t l n ("1 "+ s i g L a b e l ) ;
// Cria uma classe para cada e l e m e n t o:
EClass eClass = g e t C l a s s B y N a m e ( s i g L a b e l) ;
// System . out . p r i n t l n( eClass ) ;
if ( eClass == null ) {
System . out . p r i n t l n (" Nao tem uma class para a sig " + ←֓
s i g L a b e l) ;
c o n t i n u e;
}
E O b j e c t newObj = eClass . g e t E P a c k a g e () . g e t E F a c t o r y I n s t a n c e () .←֓
create ( eClass ) ;
// System . out . p r i n t l n( newObj ) ;
// Salva o e l e m e n t o
E C l a s s 2 A t o m. put ( newObj , atom ) ;
A t o m 2 E C l a s s. put ( atom , newObj ) ;
List < EObject > l i s t a F i e l d s = new ArrayList < EObject >() ;
HashMap < String , List < EObject > > l i s t a F i e l d s 2 = new HashMap <←֓
String , List < EObject > >() ;
for ( E O b j e c t field : s o l u t i o n A l l F i e l d s ) {
// E O b j e c t owner = ( E O b j e c t) g e t V a l u e( field , " owner ") ;
E O b j e c t origin = ( E O b j e c t) g e t V a l u e( field , " origin ") ;
E O b j e c t dest = ( E O b j e c t) g e t V a l u e( field , " ref ") ;
if ( g e t V a l u e( origin , " label ") . equals ( g e t V a l u e( atom , " label←֓
") ) )
{
System . out . p r i n t l n ("
" + g e t V a l u e( field , " label ") ) ;
System . out . p r i n t l n ("
origem :" + g e t V a l u e( origin , ←֓
" label ") + " d e s t i n o :" + g e t V a l u e( dest , " label ") ) ;
l i s t a F i e l d s . add ( field ) ;
166
167
168
169
170
171
if ( l i s t a F i e l d s 2 . c o n t a i n s K e y ( g e t V a l u e( field , " label ") .←֓
t o S t r i n g () ) ) {
l i s t a F i e l d s 2 . get ( g e t V a l u e( field , " label ") . t o S t r i n g ()←֓
) . add ( field ) ;
}
else {
List < EObject > n o v a L i s t a = new ArrayList < EObject >() ;
n o v a L i s t a. add ( field ) ;
l i s t a F i e l d s 2 . put ( g e t V a l u e( field , " label ") . t o S t r i n g ()←֓
, n o v a L i s t a) ;
}
172
173
174
175
176
177
178
179
180
}
}
70
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
A t o m F i e l d s . put ( newObj , l i s t a F i e l d s) ;
A t o m F i e l d s 2. put ( newObj , l i s t a F i e l d s 2 ) ;
o u t E l e m e n t s. add ( newObj ) ;
}
i m p r i m e R e s u l t a d o P r o c e s s a m e n t o D o s F i e l d s () ;
System . out . p r i n t l n(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n \ n ")←֓
;
// Itera sobre os e l e m e n t o s c r i a d o s e c o m p l e t a os e l e m e n t o s.
for ( Iterator < EObject > i t e r a t o r = o u t E l e m e n t s . i t e r a t o r () ; ←֓
i t e r a t o r. h a s N e x t () ;) {
E O b j e c t m o d e l E l e m e n t = i t e r a t o r. next () ;
System . out . p r i n t l n( m o d e l E l e m e n t . eClass () . g e t N a m e () + " " + ←֓
m o d e l E l e m e n t . h a s h C o d e () ) ;
for ( Iterator < E S t r u c t u r a lF ea tu re > s f I t e r a t o r = m o d e l E l e m e n t .←֓
eClass () . g e t E A l l S t r u c t u r a l F e a t u r e s () . i t e r a t o r () ; ←֓
s f I t e r a t o r . h a s N e x t () ;) {
E S t r u c t u r a l F e a t u r e f e a t u r e = s f I t e r a t o r . next () ;
System . out . p r i n t l n ("
" + f e a t u r e. g e t N a m e () ) ;
// if ( f e a t u r e. g e t N a m e () . equals (" super ") ) System . out . p r i n t l n←֓
("
super !" + f e a t u r e. g e t N a m e () ) ;
List < EObject > fields = A t o m F i e l d s . get ( m o d e l E l e m e n t ) ;
Map < String , List < EObject > > f i e l d s 2 = A t o m F i e l d s 2. get (←֓
m o d e l E l e m e n t) ;
List < EObject > v a l o r e s = f i e l d s 2. get ( f e a t u r e. g e t N a m e () ) ;
// if ( f e a t u r e. g e t N a m e () . equals (" super ") ) { System . out .←֓
p r i n t l n ("
vals =" + v a l o r e s) ; }
if ( f e a t u r e i n s t a n c e o f E R e f e r e n c e )
{
if ( f e a t u r e. g e t U p p e r B o u n d () > 1 || f e a t u r e.←֓
g e t U p p e r B o u n d () == -1 )
{
if ( v a l o r e s == null ) c o n t i n u e;
for ( E O b j e c t e : v a l o r e s) {
E O b j e c t val = ( E O b j e c t) g e t V a l u e(e , " ref ") ;
System . out . p r i n t l n ("
" + A t o m 2 E C l a s s . get (←֓
val ) . eClass () . g e t N a m e () + " " + A t o m 2 E C l a s s .←֓
get ( val ) . h a s h C o d e () ) ;
(( List ) m o d e l E l e m e n t . eGet ( f e a t u r e) ) . add ( ←֓
A t o m 2 E C l a s s . get ( val ) ) ;
}
}
else // mono v a l o r a d o
{
if ( v a l o r e s == null ) c o n t i n u e;
E O b j e c t val = ( E O b j e c t) g e t V a l u e( v a l o r e s. get (0) , "←֓
ref ") ;
if ( val == null ) c o n t i n u e;
71
226
// System . out . p r i n t l n ("
" + A t o m 2 E C l a s s. get (←֓
val ) . eClass () . g e t N a m e () + " " + A t o m 2 E C l a s s . get (←֓
val ) . h a s h C o d e () ) ;
m o d e l E l e m e n t . eSet ( feature , A t o m 2 E C l a s s . get ( val ) ) ;
// m o d e l E l e m e n t . eSet ( feature , val ) ;
227
228
229
230
231
232
233
}
}
else
// ? a t r i b u t o
{
String t y p e N a m e = f e a t u r e. g e t E T y p e () . g e t N a m e () .←֓
t o L o w e r C a s e () ;
234
235
if ( t y p e N a m e. i n d e x O f (" int ") >= 0 || t y p e N a m e. i n d e x O f ("←֓
long ") >= 0) {
E O b j e c t val = ( E O b j e c t) g e t V a l u e( v a l o r e s. get (0) , "←֓
ref ") ;
I n t e g e r i n t V a l u e = new I n t e g e r( I n t e g e r. p a r s e I n t(←֓
g e t V a l u e( val ," label ") . t o S t r i n g () ) ) ;
System . out . p r i n t l n ("
" + i n t V a l u e) ;
m o d e l E l e m e n t . eSet ( feature , i n t V a l u e) ;
} else if ( t y p e N a m e. i n d e x O f (" string ") >= 0)
{
E O b j e c t val = ( E O b j e c t) g e t V a l u e( v a l o r e s. get (0) , "←֓
ref ") ;
String str = g e t V a l u e( val ," label ") . t o S t r i n g () ;
m o d e l E l e m e n t . eSet ( feature , str ) ;
System . out . p r i n t l n ("
" + str ) ;
}
else
System . out . p r i n t l n (" Erro tipo d e s c o n h e c i d o . " + ←֓
t y p e N a m e) ;
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
}
System . out . p r i n t l n ("
eGet ( f e a t u r e) ) ;
r e s u l t a d o: " + m o d e l E l e m e n t .←֓
}
}
return o u t E l e m e n t s;
}
p r i v a t e void i m p r i m e R e s u l t a d o T r a n s f o r m a c a o ( List o u t E l e m e n t s ) {
for ( I t e r a t o r i t e r a t o r = o u t E l e m e n t s . i t e r a t o r () ; i t e r a t o r.←֓
h a s N e x t () ;) {
E O b j e c t object = ( E O b j e c t) i t e r a t o r . next () ;
System . out . p r i n t l n( object . eClass () . g e t N a m e () ) ;
for ( Iterator < E S t r u c t u r a lF ea tu re > s f I t e r a t o r = object . eClass ←֓
() . g e t E A l l S t r u c t u r a l F e a t u r e s () . i t e r a t o r () ; s f I t e r a t o r.←֓
h a s N e x t () ;) {
E S t r u c t u r a l F e a t u r e f e a t u r e = s f I t e r a t o r . next () ;
System . out . p r i n t l n ("
" + object . eGet ( f e a t u r e) ) ;
}
}
}
72
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
p r i v a t e void i m p r i m e R e s u l t a d o P r o c e s s a m e n t o D o s F i e l d s () {
System . out . p r i n t l n ("\ n \n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -")←֓
;
for ( Map . Entry < EObject , Map < String , List < EObject > > > c l a s s e s : ←֓
A t o m F i e l d s 2. e n t r y S e t () ) {
System . out . p r i n t l n( c l a s s e s. getKey () . eClass () . g e t N a m e () ) ;
Map < String , List < EObject > > sf = c l a s s e s. g e t V a l u e () ;
for ( Map . Entry < String , List < EObject > > d : sf . e n t r y S e t () ) {
System . out . p r i n t l n ("
" + d . getKey () ) ;
List < EObject > v a l o r e s = d . g e t V a l u e () ;
for ( E O b j e c t e : v a l o r e s) {
E O b j e c t origin = ( E O b j e c t) g e t V a l u e(e , " origin ") ;
E O b j e c t dest = ( E O b j e c t) g e t V a l u e(e , " ref ") ;
System . out . p r i n t l n ("
" + g e t V a l u e( origin , " label←֓
") + " , " + g e t V a l u e( dest ," label ") ) ;
}
}
}
}
// R e t o r n a o valor de uma s t r u c t u r a l f e a t u r e
p r i v a t e Object g e t V a l u e( E O b j e c t atom , String value )
{
return atom . eGet ( atom . eClass () . g e t E S t r u c t u r a l F e a t u r e ( value ) ) ;
}
p r i v a t e Object g e t S i g L a b e l F r o m A t o m ( E O b j e c t atom )
{
E O b j e c t o = ( E O b j e c t) g e t V a l u e( atom ," type ") ;
return g e t V a l u e (o , " label ") ;
}
// R e t o r n a uma classe a partir do nome
p r i v a t e EClass g e t C l a s s B y N a m e ( String name ) {
String c l a s s N a m e = name . t o L o w e r C a s e () ;
for ( Iterator < EClass > c l a s s e s = a l l C l a s s e s . i t e r a t o r () ; c l a s s e s.←֓
h a s N e x t () ;) {
EClass eClass = c l a s s e s. next () ;
if ( eClass . g e t N a m e () . t o L o w e r C a s e () . equals ( c l a s s N a m e ) )
return eClass ;
}
return null ;
}
public String g e t E l e m e n t N a m e ( EClass aclass , E S t r u c t u r a l F e a t u r e ←֓
f e a t u r e) {
return " d_ " + aclass . g e t N a m e () . t o L o w e r C a s e () + " _ " + f e a t u r e.←֓
g e t N a m e () . t o L o w e r C a s e () ;
}
p r i v a t e String g e t C l a s s N a m e A l l o y S o l ( E O b j e c t obj )
{
EClass o b j C l a s s = obj . eClass () ;
return o b j C l a s s . g e t N a m e () ;
73
324
325
326
327
328
329
330
331
332
333
334
335
}
///////////////////////////
p r i v a t e void p r o c e s s A l l o y S o l u t i o n ( R e s o u r c e model ) {
for ( I t e r a t o r e l e m e n t s = model . g e t A l l C o n t e n t s () ; e l e m e n t s.←֓
h a s N e x t () ;) {
Object e l e m e n t = e l e m e n t s. next () ;
if ( e l e m e n t i n s t a n c e o f E O b j e c t) {
// System . out . p r i n t l n (" E O b j e c t " + e l e m e n t. t o S t r i n g () ) ;
s o l u t i o n A l l I n s t a n c e s . add (( E O b j e c t) e l e m e n t) ;
// Saves the atoms , fields and s i g n a t u r e s
if ( g e t C l a s s N a m e A l l o y S o l (( E O b j e c t) e l e m e n t) . t o L o w e r C a s e () .←֓
equals (" atom ") )
s o l u t i o n A l l A t o m s . add (( E O b j e c t) e l e m e n t) ;
if ( g e t C l a s s N a m e A l l o y S o l (( E O b j e c t) e l e m e n t) . t o L o w e r C a s e () .←֓
equals (" field ") )
s o l u t i o n A l l F i e l d s . add (( E O b j e c t) e l e m e n t) ;
if ( g e t C l a s s N a m e A l l o y S o l (( E O b j e c t) e l e m e n t) . t o L o w e r C a s e () .←֓
equals (" sig ") )
s o l u t i o n A l l S i g s . add (( E O b j e c t) e l e m e n t) ;
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
}
}
}
p r i v a t e void p r o c e s s E C o r e M o d e l ( R e s o u r c e model ) {
for ( I t e r a t o r e l e m e n t s = model . g e t A l l C o n t e n t s () ; e l e m e n t s.←֓
h a s N e x t () ;) {
Object e l e m e n t = e l e m e n t s. next () ;
if ( e l e m e n t i n s t a n c e o f EClass ) {
// System . out . p r i n t l n (" EClass " + e l e m e n t. t o S t r i n g () ) ;
a l l C l a s s e s . add (( EClass ) e l e m e n t) ;
}
if ( e l e m e n t i n s t a n c e o f E P a c k a g e) {
// System . out . p r i n t l n (" E P a c k a g e " + e l e m e n t. t o S t r i n g () ) ;
a l l P a c k a g e s . add (( E P a c k a g e) e l e m e n t) ;
}
if ( e l e m e n t i n s t a n c e o f E S t r u c t u r a l F e a t u r e ) {
// System . out . p r i n t l n (" E S t r u c t u r a l F e a t u r e " + e l e m e n t.←֓
t o S t r i n g () ) ;
allSF . add (( E S t r u c t u r a l F e a t u r e ) e l e m e n t) ;
}
if ( e l e m e n t i n s t a n c e o f E S t r u c t u r a l F e a t u r e ) {
// System . out . p r i n t l n (" E D a t a T y p e " + e l e m e n t. t o S t r i n g () ) ;
allSF . add (( E S t r u c t u r a l F e a t u r e ) e l e m e n t) ;
}
if ( e l e m e n t i n s t a n c e o f E O b j e c t) {
// System . out . p r i n t l n (" E O b j e c t " + e l e m e n t. t o S t r i n g () ) ;
a l l I n s t a n c e s . add (( E O b j e c t) e l e m e n t) ;
}
}
}
p r i v a t e static void d e b u g M o d e l( R e s o u r c e model , String out ) {
System . out . p r i n t l n( out ) ;
for ( I t e r a t o r e l e m e n t s = model . g e t A l l C o n t e n t s () ; e l e m e n t s.←֓
h a s N e x t () ;) {
Object e l e m e n t = e l e m e n t s. next () ;
74
375
376
377
378
379
380
381
382
383
System . out . p r i n t l n( e l e m e n t) ;
}
}
public static void main ( String [] args ) {
if ( args . length < 2) {
System . out . p r i n t l n (" A r g u m e n t s not valid : {←֓
I N _ A l l o y _ P r o b l e m _ m e t a m o d e l _ pa t h , ←֓
I N _ A l l o y S o l u t i o n _ m o d el _ pa t h , O U T _ m o d e l _ p a t h }.") ;
} else {
String in1 = args [0];
String in2 = args [1];
String out = args [2];
T r a n s f o r m a c a o t = new T r a n s f o r m a c a o ( in1 , " T r a n s f o r m a c a o /←֓
A l l o y X S D. ecore " , in2 , out , "") ;
}
384
385
386
387
388
389
390
391
}
}
Download

DAVI AZEVEDO DE QUEIROZ SANTOS