PyEmofUCEntorno MDE/EMOF implementado en PythonJ.M. Drake, P. López Martínez y C. CuevasGrupo de
Ingeniería Software y Tiempo Real (ISTR)
- Universidad
de Cantabria
|
PyEmofUC es un entorno ligero para la creación, procesamiento y visualización de información en base al paradigma de ingeniería basada en modelos MDE, en el que todos los elementos (modelo y metamodelos) se formulan de acuerdo a la especificación EMOF 2.4 de la organización OMG.
El entorno ha sido implementado utilizando el lenguaje Python, y con ello, se ha conseguido que sea un entorno:
- Espacio de modelado: Es el espacio tecnológico nativo del entorno. La información se representa con estructuras de datos (Python) que implementan fielmente la estructura de datos que establece la especificación EMOF. Constituye la forma básica de representación de la información que es accesible desde programas.
- Espacio de serialización: La información se representa mediante texto etiquetado XMI, y con referencia formuladas como URIs textuales estándares. El entorno lo utiliza para el almacenamiento persistente de los modelos y para el intercambio de información con otros entornos.
- Espacio de dominio: La información se representa mediante un lenguaje de dominio que el entorno genera automáticamente a partir del correspondiente metamodelo. Su objetivo es facilitar la interacción con el experto de dominio que crea la información desde un editor inteligente o la supervisa en una consola enriquecida.
Las transformaciones pueden ser formuladas con estilo imperativo o declarativo: Python es un lenguaje procedural, orientado a objetos y funcional, y las transformaciones de modelos formuladas como script Python, pueden ser formuladas utilizando un estilo imperativo, declarativo o híbrido.
EmofUC
extiende EMOF con nuevas capacidades: Los modelos son formulados de
acuerdo con el metametamodelo EmofUC que
extiende la especificación EMOF 2.4 de OMG para
su implementación con Python.
Haciendo uso de tag, implementa las siguientes
extensiones de EMOF:
Ofrece reflexividad completa: Cualquier elemento de un modelo cargado en el entono tiene siempre acceso directo a su metaclase, y a partir de ella obtiene la información que describe sus características. La reflexividad es clave para la generación de las estructuras de datos en la fase de ejecución de la aplicación. Así mismo, permite desarrollar herramientas genéricas de gestión de modelos con capacidad de operar sobre modelos cuyos metamodelos no están definidos cuando se desarrollaron las herramientas.
Gestión de los modelos
(AppRepository): El repositorio de aplicación almacena
en memoria un conjunto de modelos sobre los que opera
una aplicación en una determinada fase de su ejecución.
Frecuentemente no referimos a él como "entorno".
Los elementos de su interfaz pública son:
Gestión de los
elementos del modelo (MdlRepository): El repositorio de
modelos almacena los elementos de un modelo.
Frecuentemente nos referimos a él como "modelo".
Su interfaz pública está compuesta de los siguientes elementos:
Gestión de
los atributos propios del entorno (PyEmofObject): PyEmofObject
es la clase raíz de todos los elementos EmofUC.
Aporta los atributos que el entorno PyEmofUC
requiere para la gestión desde el entorno de los
elementos del modelo.
Aporta las operaciones reflexivas que por herencia son pasadas a todos los elementos.
Gestión de la información de los modelos (EMOF::Element y sus clases especializadas): La información de un modelo se formula como una estructura de elementos agregados y mediante los valores que se asignan a las propiedades de estos. El comportamiento de un modelo se formula a través de las operaciones que se declaran en las clases de los elementos. Los elementos del modelo (clases especializadas de la clase EMOF.Element) se implementan en el entorno como clases Python con las siguientes características:
Cuando un modelo va a ser gestionado fuera del espacio de memoria de una aplicación, se representa mediante una secuencia de caracteres alfanuméricos estándares. En la formulación textual, las referencias son hiper-referencias textuales ( URIs textuales estándares) y el acceso a los modelos se realiza a través de localizadores (URL). La formulación textual de los modelos se utiliza en los siguientes casos:
La serialización y des-serialización se realiza a través de las operaciónes dump() y loadModel() de la interfaz pública. Se utilizan tres formatos de serialización:
El código completo de PyEmofUC se
puede descargar con el fichero de PyEmofUC_0_0.zip.
Incluye el código del entorno (carpeta src), un conjunto
de W3C-schemas de apoyo para la edición de metamodelos (carpeta
schemas), y así mismo, los modelos y scripts del ejemplo
CountyCity (carpeta CountyCity).
En la siguiente figura se muestra el árbol de directorios con los elementos del entorno:
PyEmofUC => Carpeta raíz
que resulta al desempaquetar el fichero
PyEmofUC_0_0.zip. Es el origen de los path
relativos. CountyCity => Carpeta raíz del ejemplo CountyCity, que se utiliza para mostrar las capacidades de PyEmofUC. src => Carpeta raíz del código Python del entorno PyEmofUC. Su path debe ser incluido en la variable de entorno PYTHONPATH. pyEmofUC => Paquete Python con el código del entorno PyEmofUC. __init__.py => Inicialización del módulo del paquete python. core.py => Código relativo al soporte del metametamodelo EmofUC. dumper.py => Código de serialización de modelos y metamodelos PyEmosUC a formulaciones textuales. GLOBAL.py => Módulo python con constantes y recursos generales al entorno. loader.py => Código de carga de modelos y metamodelos a partir de sus formulaciones textuales. resource.py => Código de implementación de la interfaz pública del entorno. xmlcore.py => Código auxiliar de localización y gestión de formulaciones XML de modelos y metamodelos. PyRTF => Paquete legado con recursos para la gestión de textos en formato RTF. toolScripts => Paquete con scripts generales proporcionados por el entorno. |
Una aplicación que va a operar con el
entorno PyEmofUC debe crear, como primer paso, un
repositorio de aplicación (instancia de la clases AppRepository).
Con los métodos de su interfaz pública se cargan, transforman y
visualizan los modelos. En una aplicación se pueden crear varios
repositorios de aplicación, pero todos los modelos que tengan
referencias cruzadas entre ellos han de estar cargados en el
mismo repositorio. La creación del repositorio se realiza
invocando su constructor AppRepository().
Si se quiere utilizar URL relativos (platform:...) para
localizar los modelos, debe establecerse en la variable
xmlcore.PLATFORM la dirección absoluta de la carpeta raíz de las
direcciones relativas. En los siguientes ejemplos se establece
como raíz la dirección "c:\temp\PyEmofUC":
>>>
import emofUC.resource as resource >>>
import EmofUC.xmlcore as xmlcore >>>
aRep=resource.AppRepository() >>>
xmlcore.PLATFORM='c:/temp/PyEmofUC' >>> |
>>>
aRep.loadModel('platform:CountyCity/EagleCounty.xmi') <emofUC.resource.MdlRepository
object at 0x0000000002E8D9E8> >>> |
Con la carga del modelo EagleCounty, también se cargan: el metametamodelo EmofUC, y los metamodelos County y City, ya que entre ellos existen las siguientes interdependencias:
>>>
for key in
aRep.getMdlRepositories().keys(): print "- "+key -
http://unican.es/istr/PyEmofUC/CountyCity/EagleCounty -
http://unican.es/istr/PyEmofUC/EmofUC -
http://unican.es/istr/PyEmofUC/CountyCity/City -
http://unican.es/istr/PyEmofUC/CountyCity/County -
http://unican.es/istr/PyEmofUC/CountyCity/EagleCity >>> |
En el siguiente ejemplo se crea un modelo newCity conforme al metamodelo City del proyecto CountyCity.
>>> print
aRep.hasMdlRepository('http://unican.es/istr/PyEmofUC/CountyCity/City') True >>> newModel =
aRep.createMdlRepository(
'http://unican.es/istr/PyEmofUC/CountyCity/Example/newModel',
'platform:CountyCity/City.xmi',
'nme') >>> >>>
newModel.rootPackage = newModel.createElement(
'cty.CompanyDirectory',
'Id_' + str(newModel.nextXmiId())) >>> >>> aCompany =
newModel.createElement('cty.Company', 'Id_' +
str(newModel.nextXmiId())) >>>
newModel.rootPackage.company.append(aCompany) >>> aCompany.name =
'TransAtlantic Ltd.' >>> >>> aEmploy =
newModel.createElement('cty.Employ', 'Id_' +
str(newModel.nextXmiId())) >>> aEmploy.name =
'Director' >>> aEmploy.salary =
87300.00 >>> aEmploy.employer =
aCompany >>> aEmploy.worker =
None >>>
aCompany.employ.append(aEmploy) >>> >>> aEmploy =
newModel.createElement('cty.Employ', 'Id_' +
str(newModel.nextXmiId())) >>> aEmploy.name =
'Sailor' >>> aEmploy.salary =
16100.00 >>> aEmploy.employer =
aCompany >>> aEmploy.worker =
None >>>
aCompany.employ.append(aEmploy) >>> >>>
newModel.dump('platform:CountyCity/DumpedFiles/newModel.rtf') >>> |
# Comprueba
que el mm está cargado # Se crea un
nuevo modelo: # - se le
asigna el URI # - El URL del
metamodelo # - El
identificador del espacio de nombres # Se crea el
elemento repositorio raíz # Se crea un
elemento tipo Company # Se agrega
al contenedor raíz #Se asigna
valor al atributo name # Se crea un
elemento tipo empleo # Se le
asigna valor a sus atributos # Se agrega
al elemento propietario # Secrea un
segundo elemento Employ # El modelo
newModel se guarda en la URL
|
El modelo creado ('platform:CountyCity/DumpedFiles/newModel.rtf') representado en formato .rtf es el siguiente:
MODEL date:2015-03-16T10:44 uri:http://unican.es/istr/PyEmofUC/CountyCity/Example/newModel mmUrl:platform:CountyCity/City.xmi nsPrefix:nme rootType: :CompanyDirectory[Id_0]{ TransAtlantic
Ltd.:Company[Id_1]{ Director:Employ[Id_2]{ salary:87300.0 worker:None employer:#Id_1 } # Director Sailor:Employ[Id_3]{ salary:16100.0 worker:None employer:#Id_1 } # Sailor } # TransAtlantic Ltd. } # |
ElW3C-schema que se genera es laxo y su funcióm es asistir al operador durante la introducción de los modelos. Algunos de los aspectos en los que ayuda el schema son:
En la versión actual, el editor no ayuda en la asignación de las referencias, ya que estas se implementan con tipos genéricos xsd:anyURI.
En la siguiente figura se muestra el uso de un editor XMLSpy de Altova en la generación de un modelo por el operador.La creación, transformación y procesamiento
de los modelos se realiza habitualmente en memoria de las
aplicaciones como un repositorio de modelo, y permanece en ella
mientras el repositorio de aplicación no se destruya. Cuando se
requiere, el modelo se salva persistentemente como un fichero de
texto, y de forma nativa como un texto etiquetado con formato
XMI.
El almacenamiento se realiza haciendo uso del método dump(«url»)
que ofrece la interfaz pública de la clase MdlRepository en cuya instancia
se almacena el modelo en memoria.
El siguiente código almacena el modelo de uri = ‘http://unican.es/istr/PyEmofUC/CountyCity/
EagleCounty’ en el fichero de url =’platform:CountyCity/DumpedFiles/EagleCounty.xmi’.
>>>
model=aRep.getMdlRepository('http://unican.es/istr/PyEmofUC/CountyCity/EagleCounty') >>> model.dump(url='platform:CountyCity/DumpedFiles/EagleCounty.xmi',schemaUrl='../../County.xsd') >>> |
Un modelo puede ser visualizado por el operador en tres formatos:
El formato
de salida es realizado por el método dump()
en base a la extensión del URL del fichero en que se almacena la
forma textual de modelo: para el formato etiquetado XMI la
extensión del URL es “.xmi”,
para el formato texto plano es “.txt” y para el formato
texto plano enriquecido con color es “.rtf”.
En la siguiente tabla se muestra el código que generan los ficheros de texto del modelo EagleCity con los tres formatos, y en las siguientes figuras se muestran la visualización haciendo uso de editores comerciales compatibles con los formatos.
>>>
eagleCityModel=aRep.getMdlRepository('http://unican.es/istr/PyEmofUC/CountyCity/EagleCity') >>> # Store file with XMI format >>>
eagleCityModel.dump(url='platform:CountyCity/DumpedFiles/EagleCity.xmi',schemaUrl='../../City.xsd') >>> # Store file with flat text
format >>>
eagleCityModel.dump(url='platform:CountyCity/DumpedFiles/EagleCity.txt') >>> # Store file with flat
coloured text format >>>
eagleCityModel.dump(url='platform:CountyCity/DumpedFiles/EagleCity.rtf') >>> |
En el estilo imperativo, la transformación de un modelo se realiza a través de bucles y sentencias condicionales que exploran el modelo de entrada, generando, en base a los elementos que encuentra, los elementos del modelo de salida. En PyEmofUC se realiza con un programa Python utilizando su estilo de programación procedural y orientado a objetos.
En el estilo declarativo, la transformación de un modelo se especifica indicando para cada tipo de elemento de modelo de entrada una regla que define el elemento del modelo de salida que debe generar, así como los valores de los atributos y referencias que se le ha de asignar en la transformación.
La transformación la realiza un motor de
transformación que itera sobre los elementos especificados. En PyEmofUC
se realiza con un programa Python en dos fases:
En la página del ejempo CountyCity, se puede ver el código Python de la transformación CountyCity_CountyToTaxCensus_Declarative_script.py. formulada con un estilo declarativo tipo ATL.
En la versión actual de PyEmofUC no se admite la eliminación individual de un modelo dentro del entorno. Esto ocurre ya que la eliminación de un modelo cargado en un repositorio es una operación costosa ya que suele estar fuertemente inter-referenciado con otros modelos que deben permanecer manteniendo su consistencia.
>>> del aRep >>> |