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.

No hay comentarios:

Publicar un comentario