jueves, 1 de octubre de 2015

Transformaciones Model-To-Text con ATL Query

Las Transformaciones Modelo a Texto (Model-To-Text o M2T) tienen por finalidad la generación de artefactos de tipo texto a partir de los Modelos. Las transformaciones M2T son muy importantes para el manejo de operaciones de modelos, ya que se usan en la implementación de generadores de código y de documentación, serializacion, visualización y exploración de modelos.

En este artículo estudiaremos algunas herramientas M2T, mencionando sus características más relevantes, además nos centraremos el estudio en los módulos ATL tipo Query que además de permitirnos recorrer por cualquier elemento del modelo, nos permiten serializar el mismo a un String que posteriormente puede ser almacenado en un fichero de texto.

Completaremos el artículo con un tutorial paso a paso para realizar el proceso de transformación a texto de modelos de clases Java (estudiados en el artículo anterior) que lo denominaremos Java2Code.

Proyectos M2T

Los principales proyectos M2T desarrollados para Eclipse Modeling Tool son los siguientes:
  • MOFScript
  • Acceleo
  • JET
  • Xpand
  • Modulos ATL Query

MOFScript

MOFSCript, es una herramienta relativamente antigua desarrollada por la empresa SINTEF ICT, para la generación de código y/o documentación. Su implementación se basa en la especificación M2T de la OMG, y está alineado al estándar QVT.

La generación de texto puede realizarse desde cualquier modelo basado en MOF, UML, Ecore u otros estándares creados con EMF. Permite la creación de múltiples ficheros de salida, además posee trazabilidad desde los modelos a los bloques de código generado.

MOFScript tiene la capacidad de integrar  código Java, su lenguaje es sencillo con pocos constructores, y es de tipo imperativo, las reglas de emparejamiento se invocan explícitamente excepto la inicial. Permite manejar herencia en las transformaciones.

La arquitectura de MOFScript se muestra en la siguiente figura:


Las siguientes figuras ilustran la sintaxis textual del lenguaje MOFScript:

Las siguientes figuras ilustran una transformación de clases UML a código Java, escrita en MOFScript: 


Acceleo

Acceleo, desarrollado por la empresa Obeo Networks para Eclipse Modeling Tool, es un sistema de generación de código basado en el estándar MOFM2T de la OMG. Soporta cualquier tipo de modelos EMF como ser: UML + Perfiles, Ecore, DSLs, etc.  Algunas de sus características son:
  • Perfectamente integrado en Eclipse, incluyendo todas las características habituales (coloreado sintaxis, quick fixes, etc.) a la hora de escribir las reglas de transformación.
  • Control de la trazabilidad que permite encontrar fácilmente los elementos del modelo, las partes utilizadas del generador y el código finalmente generado.
  • Se puede ejecutar fuera de Eclipse, al incorporar soporte para Maven.
  • Fácil de usar: lenguaje sencillo, parecido al desarrollo de páginas JSP.
  • Generación incremental: Permite modificar el código generado automáticamente y mantener los cambios, incluso después de regenerarlo.
  • Versátil: Permite generar cualquier tipo de código “If you can write it, Acceleo can generate it”.
  • Las transformaciones se escriben en el Lenguaje de Templetas (Template Language).
Las siguientes figuras ilustran el Lenguage de Templetas de Acceleo:


El siguiente código de ejemplo permite generar clases Java Beans a partir de un diagrama de Clases UML:

[comment encoding = UTF-8 /]
 [module generate('http://www.eclipse.org/uml2/3.0.0/UML')/]
 
 [template public generate(aClass : Class)]
 [file (aClass.name.concat('.java'), false)]
   public class [aClass.name.toUpperFirst()/] {
   [for (p: Property | aClass.attribute) separator('\n')]
     private [p.type.name/] [p.name/];
   [/for]
 
   [for (p: Property | aClass.attribute) separator('\n')]
     public [p.type.name/] get[p.name.toUpperFirst()/]() {
       return this.[p.name/];
     }
   [/for]
 
   [for (o: Operation | aClass.ownedOperation) separator('\n')]
     public [o.type.name/] [o.name/]() {
       // TODO should be implemented
     }
   [/for]
   }
 [/file]
 [/template]

JET

Java Emitter Templates (JET) es una herramienta para generación de código cuya sintaxis es muy parecida a las paginas JSP, permitiendo crear fácilmente “Templetas” que expresen el código que uno quiere generar. JET es un motor genérico de templetas y puede ser usado para generar código fuente para SQL, XML, Java u otro tipo de salida desde las templetas. JET es parte de EMF y está localizado en el plug-in org.eclipse.emf.codegen. Una templeta JET es un archivo de texto cuyo nombre termina con “jet”.

Xpand

Xpand es otro motor de templetas similar a Velocity, JET y JSP. Sin embargo, algunas de sus características tienen propiedades únicas lo que permite a Xpand ubicarlo entre los mejores generadores de código a partir de modelos.

El proceso usual para escribir código generado por Xpand es el siguiente:
  • Definir una estructura del modelo que quiere procesar o metamodelo
  • Definir una o más templetas que permitan generar código mediante traducciones del modelo en código
  • Definir un archivo de flujo de tareas que integra el modelo con las templetas y permite su ejecución.

La siguiente figura ilustra la configuración de un proyecto Xpand típico:

Módulos ATL Query

Como mencionamos en el artículo 4, un módulo ATL Query consiste en una transformación a datos primitivos de un modelo, es decir que ATL Query permite la generación a texto u otro tipo de dato de un modelo fuente.

El modulo ATL Query debe comenzar con la instrucción “query” seguido de su nombre y una expresión ATL:

query query_name = expresion_ATL;

La expresión ATL, generalmente se la construye con métodos Helpers que permiten simplificar el proceso de cálculo del Query. Mientras el Query va recorriendo los elementos del modelo fuente, los métodos Helpers se van emparejando (matching) de acuerdo al tipo de objeto del modelo y van procesándolos mediante instrucciones ATL  devolviendo como resultado un String. También es bastante frecuente el uso de expresiones OCL, que permiten trabajar con conjuntos o colecciones de objetos del modelo origen. La sintaxis genérica de un método Helper es la siguiente:

helper [context context_type] def : helper_name(parameters) : String = expression_ATL;

Para serializar el resultado del Query a un archivo de tipo texto se debe utilizar la instrucción writeTo(String file), que tiene como parámetro el nombre de archivo donde se serializara el Query. La sintaxis genérica de un query serializado a texto seria el siguiente:

query queryName = InputModel!ObjectType.allInstances()->
    select(e | e.oclIsTypeOf(ObjectType))->
    collect(x | x.toString().writeTo(fileName));

Transformación M2T Java2Code

En este tutorial describiremos la transformación de un modelo fuente basada en el Metamodelo Java (descrito en el artículo Atlas Transformation Language ATL) a código fuente. El resultado de la transformación consistirá en un conjunto de archivos de tipo texto que codifican las clases Java definidas en el modelo fuente, para esto trabajaremos en el proyecto “UML2Java” y en la carpeta denominada “transformations”.

Para comenzar, presione click derecho en el folder “transformations” y luego seleccione las opciones  “New” → “Other…” → “ATL → ATL File” → “Next”, luego ingrese el nombre del archivo ATL “Java2Code.atl”.


Presione “Next”, a continuación seleccione el tipo de archivo a “query”, y luego presione el botón “Finish”.


En el editor de ATL, ingrese como primera instrucción “query”, este comando recorrerá todas las instancias de las clases Java establecidas en el modelo fuente y creara un archivo de tipo texto por cada una de ellas, cuyo nombre será el nombre de la clase seguido de la extensión “.java”, el directorio destino será el folder “src” del proyecto “UML2Java”, además como las clases Java generalmente se definen en una ruta de directorios definida por el paquete que lo contiene, antes del nombre del archivo java se define dicha ruta según el paquete que contiene la clase Java en el modelo, si el paquete no está definido se crea una ruta simple para el archivo.


query Java2Code = Java!JavaClass.allInstances()->
	select(e | e.oclIsTypeOf(Java!JavaClass))->
	collect(x | x.toString().writeTo('UML2Java/src' +
	if x.package.oclIsUndefined() then '/' else '/' + 
	x.package.name.replace('.','/') + '/' endif+ x.name + '.java'));

A continuación se codificaran una seria de métodos helpers que nos servirán para detallar la construcción de la clase Java, en este caso se consideran las siguientes propiedades:

  • Superclases definidas para la clase
  • Visibilidad de la clase
  • Nombre completo de la clase
  • Paquete que contiene la clase, etc.


helper context Java!JavaClass def: visibility() : String =
if self.isPublic then
'public '
else
'private '
endif;

helper context Java!JavaClass def: modifierAbstract() : String =
if self.isAbstract then
'abstract '
else
''
endif;

helper context Java!Type def : fullName() : String = self.name;

helper context Java!JavaClass def : fullName() : String =
if self.package.oclIsUndefined() then self.name else self.package.name + '.' + self.name endif;

helper context Java!JavaClass def: toString() : String =
if self.package.oclIsUndefined() then '\n\n' else 'package ' + self.package.name + ';\n\n' endif+
self.visibility() +
self.modifierAbstract() +
'class ' + self.name +
self.superClasses->
iterate( sc; acc : String = '' |
    acc +
    if acc = '' then
       ' extends '
    else
       ', '
    endif +
    sc.fullName()
) +
' {\n' +
'\n}\n\n';

Finalmente completaremos el método helper “Java!JavaClass def: toString()”, que es el método principal sobre el cual se guía la transformación, definiendo los atributos de la clase y sus métodos.


helper context Java!JavaClass def: toString() : String =
if self.package.oclIsUndefined() then '\n\n' else 'package ' + self.package.name + ';\n\n' endif+
self.visibility() +
self.modifierAbstract() +
'class ' + self.name +
self.superClasses->
iterate( sc; acc : String = '' |
    acc +
    if acc = '' then
       ' extends '
    else
       ', '
    endif +
    sc.fullName()
) +
' {\n' +
--Fields Definition
self.fields->iterate(i; acc : String = '' |
acc + i.toString()
) +
--Methods Definition
'\n'+
self.methods->iterate(i; acc : String = '' |
acc + i.toString()
) +
'\n}\n\n';

helper context Java!Modifier def: visibility() : String =
if self.isPublic then
'public '
else
'private '
endif +
if self.isStatic then
'static '
else
	''
endif +
if self.isFinal then
'final '
else 
	''
endif;

helper context Java!Field def: toString() : String =
'\t' + self.visibility() +
if self.type.oclIsUndefined() then 'String' else self.type.fullName() endif + ' ' + self.name + ';\n';

helper context Java!Method def: toString() : String =
'\t' + self.visibility() +
if self.type.oclIsUndefined() then 'void' else self.type.fullName() endif
+ ' ' + self.name + '(' +
self.parameters->iterate(i; acc : String = '' |
acc +
if acc = '' then
''
else
', '
endif +
i.toString()
) +
')\n' + '\t{\n\t\t   //TODO METHOD \n\t}\n';

helper context Java!MethodParameter def: toString() : String =
if self.type.oclIsUndefined() then 'String' else self.type.fullName() endif
+ ' ' + self.name;

Para descargar el código completo de “Java2Code.atl” presione aquí.

Ejecución del Módulo de Transformación ATL Query


Para ejecutar el módulo de transformación ATL Query por primera vez, deberemos configurar su entorno de ejecución, para realizar esta tarea presione click-derecho sobre el archivo Java2Code.atl, seleccione: “Run As” → “Run Configutarions…”.

En la pantalla “Run Configurations..”, en la parte izquierda (“ATL Transformation”) seleccione la transformación “Java2Code.atl”, en la sección “Meta Models” ingrese en el campo “Java:” el valor “/JavaMetamodel/model/Java.ecore” (puede utilizar el botón “Workspace…” para buscar el metamodelo Java), en la sección “Source Models” ingrese en el campo “IN:” el valor “/UML2Java/run/Personas.xmi” (puede utilizar el botón “Workspace…” para buscar el modelo fuente para la transformación), finalmente presione el botón “Apply” y luego el botón “Run”.


Si todo salió bien la ejecución de la transformación deberá generar una ruta de folders y archivos dentro el directorio “src” del proyecto, de lo contrario la pestaña “Console” mostrara los errores de ejecución del módulo ATL.


Puede descargar el proyecto UML2Java completo de aquí.

Resumen


En este artículo se explicó las herramientas disponibles para elaborar transformaciones M2T en el ámbito de Eclipse Modeling Tools, también se mostró la forma de crear un módulo ATL Query. De manera práctica se detalla un tutorial paso a paso para transformar a texto (serializacion) una instancia de un  modelo basado en el metamodelo Java estudiado en un artículo anterior, el resultado es un conjunto de archivos de tipo texto que representan clases Java y que siguen la ruta de directorios según el paquete que los contenga.

lunes, 14 de septiembre de 2015

Atlas Transformation Language ATL

Atlas Transformation Language (ATL) es un lenguaje de transformación de modelos que posee un conjunto de herramientas libres (toolkit) para Eclipse. Desarrollado por la empresa OBEO y en el ámbito de MDE permite a los desarrolladores un medio para producir modelos destino a partir de un conjunto de modelos origen, a través de sus respectivos metamodelos.

En este artículo estudiaremos las características más relevantes de este lenguaje, el proceso de transformación de modelos definido en ATL, los módulos que soporta, los tipos de reglas de emparejamiento, métodos helpers y querys. Asi mismo se revisara la instalación de este framework en Eclipse Luna Modeling Tool.

Finalmente expondremos un tutorial paso a paso para realizar un proceso de transformación de clases UML a clases Java que lo denominaremos UML2Java.

Características de ATL


ATL es un lenguaje hibrido con programación declarativa e imperativa. En el estilo declarativo se expresar mapeos simples entre un elemento del modelo origen y su correspondiente elemento en el modelo destino. Sin embargo, ATL también provee constructores imperativos a fin de facilitar la especificación de mapeos que pueden expresarse con mucho trabajo declarativamente.

Un programa de transformación ATL está compuesto de reglas que definen emparejamientos de elementos del modelo origen, creando e instanciado elementos del modelo destino. Desarrollado bajo la plataforma Eclipse, el ATL Integrated Development Environment (ATL IDE) provee una seria de herramientas de desarrollo estándares (verificador de sintaxis, depurador, etc.) cuyo objetivo es el de diseñar transformaciones ATL de manera simple. El ambiente de desarrollo de ATL también ofrece un número de facilidades adicionales dedicadas al manejo de modelos y metamodelos.

El lenguaje ATL provee a los desarrolladores diseñar diferentes tipos de unidades ATL, una unidad ATL cualquiera sea su tipo se almacena en un único archivo con extensión "atl".

Las transformaciones de modelos en ATL, se las realiza a través de módulos, además el lenguaje ATL permite a los desarrolladores crear programas que desplieguen los datos primitivos de los modelos, estas unidades se denominan ATL queries. El objetivo de un query es el de computar un valor primitivo como un string o un entero desde los modelos origen. Finalmente el lenguaje ATL también ofrece la posibilidad de desarrollar librerías independientes que pueden ser importadas en diferentes tipos de unidades ATL, inclusive en las librerías mismas. Esto propiedad permite modularizar convenientemente el código ATL que se usa en múltiples unidades.

Proceso de transformación ATL

Para ilustrar el proceso de transformación ATL consideremos un pequeño ejemplo de transformación, donde se requiere transformar un metamodelo de Autores (Author) a un metamodelo de Personas (Person), la siguiente figura ilustra el modelado del ejemplo:
Metamodelo Autor y Persona

Como se observa, en ambos modelos se tiene el mismo número y nombre de propiedades (name, surname, gender y age). El objetivo será el de diseñar una transformación ATL que permita generar un modelo para Person a partir del modelo Author. La transformación se diseñara implementando las siguientes reglas semánticas:
  • Cada elemento Persona (Person) se genera a través de un elemento Autor (Author)
  • El nombre (name) de la Persona generada tiene que ser inicializada con el nombre del Autor
  • El apellido (surname) de la Persona generada tiene que ser inicializada con el apellido del Autor.
El proceso de transformación del modelo Author al modelo Person, se ilustra de mejor manera en el siguiente diagrama:

Proceso de transformación ATL de Author a Person.

La figura muestra un resumen de la transformación ATL (Author2Person) que permite generar el modelo Person, ajustándose al metamodelo MMPerson, desde el modelo Author que está conformada por el metamodelo MMAuthor. La transformación diseñada, el cual se expresa en el lenguaje ATL, se ajusta al metamodelo ATL. En este ejemplo, los tres metamodelos (MMAuthor, MMPerson y ATL) son expresados usando la semántica del metametamodelo Ecore.

Módulos ATL


Un módulo ATL corresponde a la transformación a realizarse de un modelo a otro. Este tipo de unidad permite a los desarrolladores especificar la forma de producir un conjunto de modelos destino a partir de un conjunto de modelos origen. Ambos modelos “origen” y “destino” de un módulo ATL deben corresponder a su respectivo metamodelo. Por otra parte, un módulo ATL acepta un número fijo de modelos de entrada, y retorna un número fijo de modelos destino.

La estructura de un módulo ATL está compuesta de los siguientes elementos:

  • Una sección de encabezado (header section) que define algunos atributos que serán utilizados en el módulo de transformación;
  • Una sección de importación opcional que permite importar librerías ATL.
  • Un conjunto de asistentes (helpers), que son equivalentes a métodos Java, que definen variables globales y/o funciones escritas en OCL;
  • Un conjunto de reglas que definen la manera como los modelos destino son generados desde los modelos fuente.

module module_name;
create output_models [from|refining] input_models;
uses library_file_name1;
uses library_file_name2;

helper [context context_type] def : helper_name(parameters):
return_type = exp;


rule Rule1{

}
rule Rule2{

}
Estructura genérica de un Módulo ATL.

Reglas

En ATL existen dos tipos de reglas que corresponden a los dos diferentes modos de programación (declarativo e imperativo): reglas de emparejamiento (“matched rules”) utilizadas en la programación declarativa y reglas de invocación (“called rules”) utilizadas en la programación imperativa.

Las reglas de emparejamiento constituyen el núcleo de las transformaciones declarativas en ATL ya que permite especificar desde que clase de elementos origen se generan los elementos destino y la manera en que los elementos destino generados deben ser inicializados. Una regla de emparejamiento se identifica por su nombre, se empareja a un determinado elemento de un modelo origen dado y genera una o más clases de elementos del modelo destino.

La definición de una regla de emparejamiento comprende un patrón origen y un patrón destino, un bloque imperativo opcional y un bloque para definición de variables también opcional. El patrón origen consiste de un conjunto de elementos, cada uno de ellos define una variable asociada al elemento del modelo local de un tipo dado (por ejemplo una metaclase). El conjunto de emparejamientos potenciales de la regla es el producto cartesiano de los conjuntos emparejados por cada elemento del patrón origen. Este conjunto puede ser opcionalmente restringido por una condición de guarda expresado en lenguaje OCL. Cada emparejamiento de la regla genera elementos destino por cada elemento origen. Para el ejemplo anterior, la siguiente regla de emparejamiento ATL puede transformar el metamodelo MMAuthor a MMPerson:


rule Author {
from
a : MMAuthor!Author
to
p : MMPerson!Person (
name<- a.name,
surname<- a.surname
)
}
Regla de emparejamiento ATL para transformar el metamodelo MMAuthor a MMPerson.

La sintaxis completa de una regla de emparejamiento se define de la siguiente forma:

rule Name
{
	using -- optional
	{
	variable : type = OCL-expression;
	...
	}
	from s : Source-Metamodel!Source-Metaclass [( OCL-expression )] -- optional guard
	[, ...]
	to t : Target-Metamodel!Target-Metaclass
	(
	target-meta-property<- OCL-expression [, ...]
	)
	[, ...]
	do -- optional
	{
	imperative part of the rule
	}
}
Sintaxis de una Regla de Emparejamiento ATL.

Las reglas de ejecución proveen a los desarrolladores facilidades para la programación imperativa. Estas reglas pueden verse también como un caso particular de helpers, deben ser explícitamente invocados para ser ejecutados y pueden aceptar parámetros, son muy similares a un procedimiento con parámetros de la programación tradicional. Sin embargo, en contraposición a los helpers, estas reglas pueden generar elementos del modelo destino, al igual que las reglas de emparejamiento lo hacen.  Una regla de ejecución puede ser llamada desde la sección de código imperativo de una regla de emparejamiento o de otra regla de ejecución.

Estas reglas son usadas frecuentemente para tratar con variables globales o para generar elementos de salida independientes desde el patrón de emparejamiento origen. En vez de usar patrones orígenes se debe definir una lista de parámetros, es por esta razón que deben ser invocados desde bloques imperativos de otras reglas.


rule NewPerson (na: String, s_na: String) {      
to 
   p : MMPerson!Person ( 
       name <- na 
   ) 
do { 
      p.surname <-s_na 
    } 
}
Ejemplo de Regla de Ejecución ATL.

Del anterior ejemplo se puede mencionar lo siguiente:
  • Permite generar un elemento destino de tipo Persona (“Person”)
  • Acepta dos parámetros que corresponden al nombre (“na”)  y al apellido (“s_na”) de la Persona
  • El patrón destino crea la clase Persona cada vez que la regla se ejecuta e inicializa el atributo “name” del elemento del modelo destino.
  • La sección del código imperativo se ejecuta después de la inicialización del elemento creado.

Helpers

ATL permite a los desarrolladores definir métodos entre las diferentes unidades ATL, a estos métodos se los conoce como métodos helpers. Una de sus ventajas en su uso, es que permiten factorizar (modularizar) el código ATL, los cuales pueden ser invocados desde diferentes puntos de un programa.

Existen dos tipos de helpers: helpers de tipo funcional que pueden aceptar parámetros y helpers de atributos. Ambos tipos de helpers deben ser definidos en el contexto de un tipo de datos específico.
La sintaxis general de un método helper es la siguiente:

helper [context context_type] def : helper_name(parameters) : return_type = exp;

Un ejemplo de un método helper sería el siguiente:


helper def : averageLowerThan(s : Sequence(Integer), value : Real) : Boolean =
	let avg : Real = s->sum()/s->size() 
in avg < value;
Ejemplo de método helper ATL.

Queries


Un query ATL consiste en una transformación a datos primitivos de un modelo. Puede verse como una operación que calcula un valor primitivo desde un conjunto del modelo origen. El uso más común de query’s ATL es la generación de salida textual (codificado en un valor de tipo String) desde el modelo fuente. Sin embargo, un query ATL no está limitado al cómputo de valores String y puede también retornar valores numéricos o booleanos. La estructura de un query ATL, comienza con una sección de importación opcional, luego se debe definir la instanciación del query. Un query se define usando la palabra reservada query y especifica la forma de cómo se calcula el resultado utilizando una expresión ATL, la sintaxis de un query es la siguiente:
query query_name = expresion_ATL;

El uso de métodos helpers es bastante recomendado para simplificar los procesos de cálculo de un query, además que ayuda a modularizar su contenido, el siguiente código muestra un ejemplo de un query ATL:


query XQuery2Code = XQuery!XQueryProgram.allInstances()->
collect(e | e.toString().writeTo('C:/test.xquery'));

helper context XQuery!XQueryProgram def: toString() : String =
self.expressions->iterate(e; acc : String = '' |
acc + e.toString() + '\n');

helper context XQuery!ReturnXPath def: toString() : String =
'{' + self.value + '}';

helper context XQuery!BooleanExp def: toString() : String =
self.value;
Ejemplo de query ATL.

Librerías ATL


Las librerías ATL permiten definir un conjunto de métodos helpers que pueden ser invocados desde otras unidades ATL.
 
Como otro tipo de unidades ATL, una librería puede incluir opcionalmente una sección de importación, debajo de dicha sección, luego se definen los métodos helpers que estarán habilitados para su uso en las unidades ATL que importaran la librería.

Una librería ATL no puede ejecutarse independientemente, ni tampoco puede definirse un elemento por defecto. Un ejemplo de una librería ATL seria el siguiente:


library Strings;

helper context String def : firstToUpper : String =
	self.substring(1, 1).toUpper() + self.substring(2, self.size());

helper context String def : startsWith(begin : String) : Boolean =
	if (self.size() < begin.size()) then
		false
	else
		self.substring(1, begin.size()) = begin
	endif;

helper context String def : endsWith(end : String) : Boolean =
	if (self.size() < end.size()) then
		false
	else
		self.substring(self.size() - end.size() + 1, self.size()) = end
	endif;
Ejemplo de librería ATL.

Instalación del Plug-in ATL para Eclipse

La instalación del Plug-in para Eclipse de ATL, puede realizarse mediante la opción Help Install Modeling Components, de la ventana Eclipse Modeling Components Discovery seleccione la opción ATL y presione “Finish”.

Luego siga los pasos de la instalación por defecto, hasta que el plug-in se instale completamente en su IDE y el sistema le pida reiniciarlo.

Proyecto de Transformación ATL UML2Java

El proyecto de Transformación ATL UML2Java, describe la transformación de un modelo UML a un modelo Java. El modelo Java permite almacenar información de clases Java, especialmente en lo que concierne a la estructura de las clases, el paquete de referencia de la clase, sus atributos y sus métodos.

Metamodelo de Clases Java

En este tutorial consideramos al metamodelo de clases Java como  metamodelo Destino que consiste principalmente en elementos de Java (JavaElements) que tienen un nombre (name). Una clase Java (JavaClass) tiene métodos (Methods) y atributos (Fields) que pertenecen a un paquete (Package).  Los métodos, atributos y clases Java son subclases de modificadores Java (Modifiers) que indican si son elementos públicos, estáticos o finales (public, static, final). Las clases metodos pueden contener un conjunto de parámetros (MethodParameter) de un tipo indicado. Las clases Java y los métodos se declaran con el atributo isAbstract que permite definir si son abstractos o no.  Las clases Java y la clase PrimitiveTypes son del tipo Type. Por otro lado un método define un tipo Type de retorno y sus parámetros son del tipo Type, un atributo también es del tipo Type. Finalmente en un paquete pueden definirse un conjunto de tipos Enumerativos Java (Enumeration) que poseen un grupo de literales (EnumerationLiteral) que son del tipo JavaElement.

Puede recurrir al artículo “Creación de Meta Modelos con EMF y Ecore”, para la creación paso a paso del proyecto EMF de un metamodelo.

La siguiente figura ilustra el metamodelo Java (el archivo Ecore puede descargarlo de aquí).

Metamodelo UML

Este metamodelo se lo considera como metamodelo Origen y esta descrito íntegramente en OMG, para este tutorial solo ilustramos una porción limitada del mismo.

Creación del Proyecto ATL

El primer paso es la creación de un proyecto de Transformación ATL en el espacio de trabajo de Eclipse (Workspace). En el IDE seleccione las opciones “File” → “New” → “Other…” y elija “ATL → ATL Project”.

Presione “Next”, ingrese el nombre del proyecto “UML2Java”, y luego presione “Finish”:


El proyecto ATL se creara vacío, en el mismo crearemos los siguientes folders para estructurar de mejor manera el proyecto:
  • config: almacenara archivos de librerías ATL
  • models: almacenera los modelos UML de ejemplo que se crearan posteriormente para ser transformados
  • metamodels: en este folder se guardaran los metamodelos origen y destino para las transformaciones ATL.
  • profile: folder que almacenara perfiles UML siempre y cuando nuestros metamodelos tengan adicionados esta característica.
  • run: folder que almacenara archivos XMI relacionados a los metamodelos destino obtenidos por la ejecución de las transformaciones ATL.
  • transformations: almacenara los módulos de transformación ATL.
  • src: almacenara las clases Java serializadas en archivos desde el modelo destino generado, por módulos query de ATL.

La parte fundamental del proyecto es la creación de la transformación ATL.  Presione click derecho en el folder transformations y luego seleccione las opciones  “New” → “Other…” → “ATL → ATL File” → “Next”, luego ingrese el nombre del archivo ATL “UML2Java.atl”.


A continuación, se deberán especificar los metamodelos de entrada, salida y módulos de librerías (opcional) necesarias para ejecutar la transformación.


Para definir el metamodelo origen, presione el botón “Add…” de la sección “Input Models”, ingrese en el campo “Metamodel Name” el valor “UML” y en el campo “Resource URI” el valor “http://www.eclipse.org/uml2/5.0.0/UML”, puede utilizar la opción “Browse Registered Packages” para buscar el metamodelo UML de los metamodelos registrados en el IDE Eclipse, luego presione el botón “Ok”.


Para definir el metamodelo destino, presione el botón “Add…” de la sección “Output Models”, ingrese en el campo “Metamodel Name” el valor “Java” y en el campo “Resource URI” el valor “platform:/resource/JavaMetamodel/model/Java.ecore”, puede utilizar la opción “Browse Workspace” para elegir desde espacio de trabajo de Eclipse el archivo Ecore del metamodelo Java, luego presione el botón “Ok”.


Una vez definidos los metamodelos presione el botón “Finish”, el sistema le preguntara si desea abrir la perspectiva ATL en este momento, elija la opción “Yes”, Eclipse abrirá el editor del módulo de transformación ATL, con la configuración de los metamodelos UML y Java.

Reglas de Transformación UML2Java

Las reglas de transformación para UML2Java se pueden resumir en las siguientes:
  • Para cada instancia UML Package, se creara una instancia Java Package. El nombre del paquete UML corresponderá con el de Java, sin embargo el nombre del paquete Java contendrá la ruta completa de la información separada por puntos.
  • Para cada instancia UML Class, se creara una instancia Java Class, donde los nombres de las clases se corresponderán uno a otro, la referencia Package se corresponderá uno a otro, los Modificadores de Clase se corresponderán uno a otro.
  • Para cada instancia UML Data Type, se creara una instancia Java Primitive Type, donde el nombre y el paquete de referencia se corresponderán uno a otro.
  • Para cada instancia UML Attribute, se creara una instancia Java Field, donde los nombres, los tipos, modificadores de clase y clases se corresponderán uno a otro.
  • Para cada instancia UML Operation, se creara una instancia Java Method, donde los nombres, los tipos, modificadores de clase y clases se corresponderán uno a otro.
  • Para cada instancia UML Enumeration se creara una instancia Java Enumeration, donde los nombres y los literales del Enumerador se corresponderán uno a otro.
Cabe mencionar que se añadieron al programa ATL métodos Helpers de ayuda, así como también una lista de datos primitivos Java que será utilizada para corresponder un tipo de dato primitivo de UML (como ser: String, Integer y Boolean) al tipo de dato primitivo de Java correspondiente.

Código ATL

El código ATL para esta transformación es el siguiente, copie y pegue el mismo al editor ATL o puede descargarlo de aquí.

-- @nsURI UML=http://www.eclipse.org/uml2/5.0.0/UML
-- @path Java=/JavaMetamodel/model/Java.ecore

module UML2Java;
create OUT : Java from IN : UML;

helper def : primitiveTypesMap : Map(String,Java!PrimitiveType) = Map{};

helper context UML!Namespace def: getExtendedName() : String =
	if self.namespace.oclIsUndefined() then
		''
	else if self.namespace.oclIsKindOf(UML!Model) then
		''
	else
		self.namespace.getExtendedName() + '.'
	endif endif + self.name;

helper context UML!Type def: getType() : Java!Type =
    if self.oclIsUndefined() 
	then OclUndefined
	else 
		if self.oclIsKindOf(UML!PrimitiveType)
		then thisModule.primitiveTypesMap->get(self.name) 
		else self
		endif
	endif;

rule P2P {
	from e : UML!Package (e.oclIsTypeOf(UML!Package))
	to out : Java!Package (
		name <- e.getExtendedName()
	)
}

rule C2C {
	from e : UML!Class
	to out : Java!JavaClass (
		name <- e.name,
		isAbstract <- e.isAbstract,
		isPublic <- if e.visibility='public' then true else false endif,
		package <- e.namespace,
		superClasses <- e.generalization->collect( g | g.general )
	)
}

rule D2P {
	from e : UML!DataType
	to out : Java!PrimitiveType (
		name <- e.name,
		package <- e.namespace
	)
}

rule T2T {
	from e : UML!Type(e.oclIsKindOf(UML!PrimitiveType))
	to out : Java!PrimitiveType (
		name <- e.name,
		package <- e.namespace
	)
}

rule A2F {
	from e : UML!Property
	to out : Java!Field (
		name <- e.name,
		isStatic <- e.isStatic,
		isPublic <- if e.visibility=#public then true else false endif,
		--isFinal <- e.isFinal(),
		owner <- e.owner,
		type <- if e.type.oclIsUndefined() then OclUndefined else e.type.getType() endif 
	)
}

rule O2M {
	from e : UML!Operation
	to out : Java!Method (
		name <- e.name,
		isStatic <- e.isStatic,
		isPublic <- if e.visibility=#public then true else false endif,
		owner <- e.owner,
		type <- if e.ownedParameter->select(x|x.direction=#return)->first().oclIsUndefined() 
		        then OclUndefined 
				else e.ownedParameter->select(x|x.direction=#return)->first().type.getType()
				endif,
		parameters <- e.ownedParameter->select(x|x.direction<>#return)->collect( par | thisModule.PM2JP( par ) )
	)
}

rule PM2JP(p : UML!Parameter)
{
    to out : Java!MethodParameter
    (
         name <- p.name,
		 owner <- p.owner,
		 type <- if p.type.oclIsUndefined() then OclUndefined else p.type.getType() endif 
    ) do {
		out;
	}
}

rule E2E
{
    from e : UML!Enumeration ( UML!Property.allInstances()->exists( p |
        p.class.oclIsTypeOf( UML!Class ) and p.type = e ) )
    to je : Java!Enumeration
    (
        name <- e.name,
        package <- e.package,
        enumerationLiterals <- e.ownedLiteral->collect( el | thisModule.EL2EL(el))
    )
}

rule EL2EL(el : UML!EnumerationLiteral)
{
    to out : Java!EnumerationLiteral
    (
        name <- el.name
    ) do {
		out;
	}
}

rule makeType(type : UML!Type) {
	to t : Java!Type (
		name <- type.name
	) do {
		t;
	}
}

entrypoint rule Init() {
	to s : Java!PrimitiveType (
		name <- 'String'
	),
	i : Java!PrimitiveType(
		name <- 'Integer'
	),
	b : Java!PrimitiveType(
		name <- 'Boolean'
	)
	do {
		thisModule.primitiveTypesMap <- thisModule.primitiveTypesMap->including(s.name,s)->including(i.name,i)->including(b.name,b);
		s;
		i;
		b;
	}
}

Modelo UML Origen

A continuación se deberá diseñar un o más modelos de Clases UML “Origen”, los mismos pueden ser diseñados con una herramienta de modelado UML, algunas herramientas sugeridas son las siguientes:
  • Papyrus: esta es una herramienta de software libre basada en UML 2 y Eclipse, que provee soporte para DSL, UML2 y SysML, posee un plug-in para su instalación en el IDE Eclipse.
  • Magic Draw, es una herramienta comercial con muy buenas prestaciones para el modelado de sistemas con UML, SysML, BPMN y UPDM.
Una vez diseñado el modelo Origen, que generalmente se crea en un archivo  con extensión UML y en formato XMI, cópielo al folder “models” del proyecto ATL. Para nuestro ejemplo se creó un modelo denominado "Personas.uml" con las siguientes clases:

Puede descargar el archivo “Personas.uml” de aquí.

Ejecución del Módulo de Transformación ATL

Para ejecutar el módulo de transformación ATL por primera vez, deberemos configurar su entorno de ejecución, para realizar esta tarea presione click-derecho sobre el archivo UML2Java.atl, seleccione: "Run As → Run Configutarions…"



En la pantalla “Run Configurations” y en la sección “Source Models” ingrese el valor “/UML2Java/models/Personas.uml”, puede utilizar el botón “Workspace…” para recuperar el modelo origen del folder models. Luego en la sección “Target Models” ingrese el valor “/UML2Java/run/Personas.xmi”  que corresponde al archivo del modelo Destino, en nuestro caso ingresamos el nombre de “Personas.xmi”, luego presione el botón “Apply” y posteriormente ejecute la transformación presionando el botón “Run”.


Si todo salió bien la ejecución deberá generar el archivo “Personas.xmi” en el folder “run”, de lo contrario la pestaña “Console”, mostrara los errores de ejecución del módulo ATL.


Para abrir por primera vez el archivo XMI generado con el editor EMF por defecto, previamente deberemos registrar el metamodelo Java, para realizar esto seleccione el archivo “Java.ecore”, presione click-derecho y seleccione la opción “Register Metamodel”. Finalmente presione doble-click en el archivo “Personas.xmi” y el mismo debería lucir de la siguiente manera:


Puede descargar el archivo "Personas.xmi" de aqui y el proyecto UML2Java completo de aquí.

Resumen

En este artículo se explicó al lector las características principales del Atlas Transformation Language (ATL), se mostró cómo se lleva a cabo el proceso de transformación entre modelos y de manera práctica se hizo un tutorial paso a paso para transformar diagramas de Clase UML a Clases Java. Sin embargo puede que la transformación no cubra todas las expectativas de los lectores, cualquier mejora es bienvenida.

Algunos recursos recomendados son:
En el próximo artículo veremos ATL Query y la serialización de los modelos a archivos, hasta la próxima….

miércoles, 2 de septiembre de 2015

Creación de Meta Modelos con EMF y Ecore

Eclipse Modeling Framework (EMF), representa el núcleo de la plataforma Eclipse para el desarrollo dirigido por modelos. EMF es un framework muy útil para el desarrollo de metamodelos, mediante una sintaxis abstracta, y también permite generar automáticamente clases de implementación en código Java para los elementos de los metamodelos.

En el presente artículo, inicialmente definiremos al metamodelo y al metamodelado, luego analizaremos el framework EMF, posteriormente estudiaremos las herramientas para construir metamodelos como Ecore y finalmente mostraremos un tutorial para la creación y prueba de un caso de estudio.

Metamodelo


Un metamodelo es un modelo que define un lenguaje para expresar modelos, en otras palabras un metamodelo es un Modelo de Modelos. Un modelo, por otro lado, es la abstracción de un fenómeno del mundo real, por lo tanto un metamodelo no es nada más que una abstracción de mayor nivel. Un modelo está conformado por su metamodelo de la misma manera que un programa de computación está conformado por la gramática del lenguaje de programación en el cual está escrito.

El metamodelado nos servirá para realizar el análisis, construcción y desarrollo de reglas, marcos de trabajo, restricciones, modelos y teoría aplicables para el modelado de un tipo predefinido de problemas. El metamodelado será la construcción de conceptos de un determinado dominio que típicamente involucra el estudio de salidas y entradas relacionadas estrechamente con su respectivo metamodelo.

El metamodelo de un lenguaje es una descripción de todos los conceptos que pueden usarse en el mismo. Por ejemplo, los conceptos de package, clase, atributo y operaciones aparecen en UML; los conceptos de métodos, constructores e interfaces en JAVA; los conceptos de tabla, columna y clave primaria son parte de SQL.

Cada elemento de un modelo es una instancia de una metaclase en el metamodelo. Una clase define a sus objetos y una metaclase define a los elementos del modelo. Como ejemplo, la siguiente figura representa a una porción del Metamodelo UML.
Porción de Metamodelo UML.

En el siguiente diagrama se muestra el metamodelo para representar al lenguaje SQL.
Metamodelo SQL

Por otra parte, a los metamodelos se les puede adicionar una serie de reglas de validación o restricciones conocidas como "constraints", los constraints se los expresa utilizando el lenguaje OCL.

Herramientas de Modelado en Eclipse


El Eclipse Modeling Framework más conocido como EMF, es el framework provisto por Eclipse para la creación de modelos y metamodelos, con facilidades para la generación automática de código y para la construcción de herramientas basadas en modelos.

EMF permite generar automáticamente clases Java que implementan elementos de nuestros modelos, además de clases adaptadoras que permiten visualizar y editar un modelo.

Las principales funcionalidades de EMF son:
  • Diseñar metamodelos Ecore, con dos tipos de editores:
    • Editor basado en una estructura de tipo árbol
    • Editor visual, similar a un diagrama de clases UML
  • Construir editores de modelos basados en una estructura de tipo árbol, EMF permite generar clases Java que permiten soportar al metamodelo y clases para testeo con JUnit.
El núcleo de EMF (EMF core) consiste de los siguientes elementos:
  • EMF, permite definir metamodelos basados en Ecore, en este framework los modelos pueden ser creados y modificados a partir de un metamodelo Ecore, también existe soporte para manejar la persistencia de modelos mediante serializacion XMI y además de un API para reflexión de objetos.
  • EMF.Edit, este framework permite generar clases Java para editar un modelo EMF y consiste en:
    • Clases que soportan edición de propiedades, proveedores de contenido (content and label provider), edición en Hojas de Propiedad (property sheets).
    • Un framework de comandos para la construcción de un modelo EMF que incluye operaciones de “undo” y “redo”.
  • EMF.Codegen, esta herramienta permite la generación de un editor completo a partir de un metamodelo Ecore.

Metamodelos Ecore


Ecore es el framework propuesto por la comunidad Eclipse que es una versión simplificada de MOF. Los metamodelos Ecore se almacenan en ficheros XMI con extensión .ecore.

Componentes de Ecore


Los componentes de Ecore se resumen en el siguiente diagrama:

Diagrama de componentes de Ecore

Los principales componentes de Ecore son los siguientes:
  • EPackage: es un componente que permite organizar clases y tipos de datos.
  • EClass: permite definir conceptos en el metamodelo
  • EReference: permite definir asociación entre conceptos
  • EAttribute: permite definir propiedades de los conceptos
  • EDataType: define un tipo para un atributo como por ejemplo EString, EInt, EDouble, etc..

Los componentes Ecore tienen las siguientes relaciones, atributos y operaciones:
Diagrama Ecore de relaciones, atributos y operaciones.

Creación de un metamodelo Ecore


Para la creación de un metamodelo Ecore, utilizaremos el IDE Elipse Luna Modeling Tool, en el cual realizaremos las siguientes tareas:
  • Creación de un proyecto de modelado EMF
  • Diseño del metamodelo Ecore
  • Generación de código Java, para el editor del metamodelo
  • Validación y prueba de una instancia del metamodelo.

Metamodelo ejemplo


En este tutorial crearemos un metamodelo para representar una Maquina de Estado UML simple. Un diagrama de máquina de estado modela el comportamiento de un objeto, especificando la secuencia de eventos que la misma atraviesa durante su tiempo de vida en respuesta a dichos eventos.

Como ejemplo, el siguiente diagrama de máquina de estado muestra los estados que una puerta atraviesa durante su tiempo de vida.


La puerta puede estar en uno de tres estados: “Opened” (Abierta), “Closed” (Cerrada) o “Locked” (Bloqueada). Puede responder a cuatro eventos: Abrir, Cerrar, Bloquear y Desbloquear. Tener en cuenta que no todos los eventos son válidos en todos los estados, por ejemplo, si una puerta esta abierta, no se puede bloquear hasta que esté cerrada. También se debe tener en cuenta que una transición de estado puede tener una o más condiciones de guarda adjuntas. Si la puerta está abierta, esta solo puede responder al evento “Closed” si la condición doorWay->isEmpty es verdadera.

Los elementos que se modelaran de la máquina de estados son:
  • Estados
  • Estados Inicial y Final
  • Transiciones
  • Triggers de Transiciones

Creación del proyecto de Modelado

El primer paso es la creación de un proyecto de modelado vacío en el espacio de trabajo de Eclipse (Workspace). En el IDE seleccione las opciones “File” → “New” → “Other…” y elija “Eclipse Modeling Framework → Empty EMF Project”.

Presione “Next”, ingrese el nombre del proyecto “org.mda.ejemplo.StateMachine”, y luego presione “Finish”:

La parte esencial del proyecto de modelado es el modelo en sí, definido en formato Ecore. Presione click derecho en el folder del modelo y luego seleccione las opciones  “New” → “Other…” → “Eclipse Modeling Framework → Ecore Model” → “Next”, luego ingrese el nombre del archivo Ecore “Statemachine.ecore”.



Presione “Finish” para crear el modelo.  Esta acción abrirá el editor Ecore por defecto, el mismo permite definir el modelo en un árbol de elementos. Existen opciones adicionales para editar modelos Ecore que incluyen un editor gráfico, editor de texto, editores con anotaciones Java e incluso la importación de archivos de herramientas UML. Por el momento usaremos el editor por defecto y posteriormente habilitaremos el editor gráfico.

En el editor en árbol, usted puede crear y eliminar elementos del modelo así como la modificación de la estructura del modelo mediante operaciones drag-and-drop. Las propiedades de los elementos del modelo pueden ser modificadas en una segunda ventana la cual se abre presionando doble-click sobre el elemento raíz del modelo o presionando click-derecho →  “Show Properties View”.

Ahora, definiremos el nombre y la propiedad URI del elemento “package” del modelo creado, utilizando la ventana de propiedades, escriba “Statemachine” en la propiedad “Name”, luego ingrese en la propiedad Ns Prefix: “org.mda.ejemplo.Statemachine” y en la propiedad Ns URI “http://org/mda/ejemplo/Statemachine”.


Para habilitar el editor gráfico del modelo, seleccione el archivo “Statemachine.ecore” del navegador, presione click-derecho y seleccione la opción “Initialize ecore_diagram diagram file”, ingrese el nombre del archivo del diagrama por defecto y presione “Finish”.

La acción habilitara el editor gráfico del modelo Ecore, con una paleta de herramientas al lado derecho que nos permite crear elementos de tipo EClass, EPackage, EAttribute, EOperation, EDataType, EEnum, EEnumLiteral, Asociation, Agregation, Generalization y otros.


Ahora, crearemos las siguientes clases, realizando operaciones drag-and-drop desde la paleta de herramientas al diagrama:

  • La clase “Class”, permite definir la clase para la cual se elaborara la máquina de estados
  • La clase “StatemachineUML”, es la clase principal de la máquina de estados, la cual contendrá estados y transiciones
  • La clase “Declaration”, es una superclase de la cual se heredaran Estados y Transiciones
  • Las clases “InitialState”, “FinalState” y “NormalState”, representan los estados de la máquina.
  • La clase “Transition”, representa las transiciones de la máquina.
  • La clase “TriggerEvent”, representa a los eventos que ejecutan una transición.
Como siguiente paso se definirán los atributos para las clases creadas, utilizando la opción “EAttribute” de la paleta de herramientas, realice una operación de drag-and-drop sobre una de las clases declaradas y escriba el nombre del atributo seguido de dos puntos y su tipo Ecore (por ejemplo “name : EString”), luego presione Enter, deje el diagrama de la siguiente manera:


Ahora definiremos las relaciones de herencia (“Generalization”), agregación (“Aggregation”) y asociación (“Association”) entre las clases.

Defina herencia (propiedad ESuperTypes) de “State” y “Transition” a “Declaration” y también de “InitialState”, “FinalState” y “NormalState” a “State”.

Defina una relación de agregación (clase EReference) de “StatemachineUML” a “Declaration”, ingrese el nombre de la relación como “elements” (propiedad “Name”), especifique la multiplicidad de la relación de 0 a muchos (propiedad “Upper Bound” a -1) ya que una máquina de estados puede contener muchos elementos declarativos (estados y transiciones), finalmente coloque la propiedad “Contaiment” a true.

Defina otra relación de agregación de “Transition” a “TriggerEvent”, coloque el nombre de la relación a “events”, especifique una relación de 0 a muchos ya que una transición puede ejecutar varios eventos, coloque la propiedad “Contaiment” a true.

Defina una relación de asociación desde “Transition” a “State”, la multiplicidad será de 0 a 1 y el nombre de la relación “source”.

Defina otra relación de asociación desde “Transition” a “State”, la multiplicidad será de 0 a 1 y el nombre de la relación “target”.

Finalmente defina una relación de agregación desde “StatemachineUML” a “Class”, la multiplicidad será de 0 a 1 y el nombre de la relación “class”, coloque la propiedad “Contaiment” a true.


Generación de Código Java


En este paso, generaremos las entidades desde el modelo Ecore, note que este proceso es iterativo, es decir que si se cambian, añaden o eliminan elementos del modelo uno puede regenerar las entidades nuevamente (opción “Reload…” del modelo generador).

Para generar las entidades, primero deberemos crear el modelo generador (“Generator Model”). Este modelo permite configurar varias propiedades antes de generar el código Java que permite manipular las entidades y crear un editor simple para el modelo. También podemos indicar que el código generado se crea como un proyecto Plugin de Eclipse con una serie que folders y paquetes Java.

Para crear el modelo generador, primeramente seleccione el archivo “Statemachine.ecore” del navegador, seleccione las opciones: File → “New” → “Other…” → “Eclipse Modeling Framework → EMF Generator Model” → “Next”, ingrese  como nombre de archivo del modelo generador: Statemachine.genmodel. 

Proceda con la siguiente página y seleccione “Ecore model” como el modelo a importar. Presione “Next”, si el modelo URI está vacío, presione “Browse Workspace…” y seleccione el modelo Statemachine.ecore de la carpeta “model”. Ingrese a la siguiente página y presione “Finish”.


En el nodo raíz del modelo generador, se pueden setear varias propiedades para generar el código Java. En todos los nodos del árbol del modelo generador se pueden setear propiedades para cada entidad a generar. Por ser la primera vez que generamos el código, utilizaremos los valores por defecto. EMF generara como máximo cuatro diferentes proyectos plug-in para el modelo indicado:
  • Proyecto Model: este proyecto contiene todas las entidades, paquetes y clases de factoría que permiten crear objetos instanciados del modelo.
  • Proyecto Edit: este proyecto contiene clases proveedoras (providers) para desplegar el modelo en una interfaz de usuario. Por ejemplo los providers ofrecen una etiqueta para cada elemento del modelo, los cuales pueden ser usados para desplegar una entidad mostrando un icono y su nombre.
  • Proyecto Editor: este proyecto es un editor generado para crear y modificar instancias del modelo.
  • Proyecto Test: contiene templetas que permiten escribir test de funcionalidad para el modelo.
Para generar estos plug-ins, presione click-derecho en el nodo raíz del modelo generador y seleccione la opción “Generate All”.

En el explorador de proyectos, deberán crearse los proyectos ya mencionados como muestra la siguiente figura:


Creación de un modelo ejemplo


Este paso consiste en crear un modelo ejemplo, para ello se ejecutara el proyecto plug-in, presione click-derecho en el proyecto que contiene el archivo Ecore y seleccione “Run as → Eclipse Application”. Esta opción ejecuta una nueva sesión del IDE Eclipse.

En la nueva sesión de IDE, crear un proyecto vacío seleccionando “File” → “New” → ”Other…” → “General” → “Project” coloque el nombre de StatemachineExample.


Presione click-derecho sobre el proyecto creado y seleccione “New” → “Other…” → “Example EMF Model Creation Wizards” → “Statemachine Model” → “Next” e ingrese “Puerta.statemachine” como nombre del modelo. Este archivo contendrá el modelo serializado en formato XMI.
Seleccione el objeto UML del modelo Ecore que representa al objeto de la máquina de estados, desde la cual se crearan los diferentes elementos del modelo, luego presione “Finish”.


El editor generado para manejar la instancia del modelo trabaja de forma similar al editor Ecore, los elementos del modelo pueden crearse presionando click-derecho y eligiendo las opciones “New child” o “New sibling”, mientras que los atributos pueden ser modificados desde la ventana de propiedades. A continuación se editara el modelo ejemplo del ciclo de vida de la Puerta, tal cual se muestra en el grafico del modelo ejemplo.

Resumen


El presente artículo introdujo al lector en el framework EMF, en el metamodelado con Ecore y mostró un caso práctico de estudio. Si bien los conceptos desarrollados son iniciales, nos sirven para introducirnos al mundo del MDA de forma práctica.

A manera de resumen podemos mencionar que EMF es un framework bastante amplio y es un proyecto que incluye nuevas tecnologías que amplían o complementan a EMF, como ser CDO, Compare, Model Query, Net4j, SDO, Teneo, EEF, Ecore Tools, etc.

Algunos recursos recomendados son:
  • Eclipse Modeling Framework (EMF) – Tutorial de Lars Vogel
  • Eclipse Modeling Framework (EMF)  Eclipse Modeling Framework Technology (EMFT) de Juan Otero y Andres Quintana
  • EMF Tutorial de  Maximilian Koegel y Jonas Helming

Hasta la próxima…