PyEmofUC

MDE/EMOF environment implemented with Python

J.M. Drake, P. López Martínez and C. Cuevas

Software Engineering and Real-Time Group (ISTR) - University of Cantabria

Table of Contents

Goals

PyEmofUC is a lightweight environment for the creation, processing and visualization of information following the Model-Driven Engineering paradigm (MDE).
Every artefact (model / meta-model) in this environment is formulated according to the
EMOF 2.4 OMG specification.

The environment has been implemented using the Python language and thereby, it is:

The design of the PyEmofUC environment targets the following specific features:



  • Modelware space: It is the native technological space of the environment. The information is represented by means of Python data structures that closely match the object structures proposed by the EMOF specification. This space is the basic form of data representation that is accessible from the code of applications and tools.
  • XML space: The information is represented by tagged XMI text and the references to internal and external elements are formulated through standard textual URIs.
    The environment uses this space for storing models in persistent repositories and for exchanging information with other enviroments.
  • Domain-specific languages space: The information is represented by a domain-specific language automatically generated by the environment from the corresponding meta-model.
    This space aims at facilitating the interaction with the domain expert who will formulate the information using a smart editor or will supervise it on a console.

  • It does not require additional code generation: The applications operate directly on models already present in the environment and without previously requiring the generation of source code for models instantiation.
    Loading a model requires preload of its meta-model and the data structures required by the application are
    dynamically generated at runtime, with information provided by the meta-model.


  • Transformations can be formulated in an imperative or declarative style: The model transformations are formulated as Python scripts using an imperative, declarative or hybrid style.
    Python is a procedural, object-oriented and functional language.

  • EmofUC extends EMOF by adding some new capabilities: The meta-models are formulated according to the EmofUC meta-meta-model, which constitutes an extension of the EMOF 2.4 OMG specification in order to facilitate its implementation with Python.
    The extensions are accomplished using the tag proposals in EMOF and define the following aspects:

    • Inheritance between primitive types: The EmofUC declares it by means of “PT”.
    • Restricted ranges for primitive types values: The EmofUC formulates them using “RE”, “MAX” and “MIN” tags.
    • Specification of the code that implements the derived properties: “DPE” tags describe the code that evaluates derived properties.
    • Specification of the code that implements the operations: “OPE” tags describe the operations code.
    • Textual documentation can be attached to meta-model elements: “DOC” tags point out textual documentation for meta-model elements.
  • Full reflectivity provided: Every model element has direct access to its meta-class and thus to the information describing its characteristics. Reflectivity is a key feature for the creation of data structures for representing model elements during application execution. It also allows the development of model management tools regardless if the corresponding meta-models were unknown at development time.





Public interface

The PyEmofUC environment provides a public interface which can be used by the applications and tools processing the models data. The interface elements are the properties and operations declared in the AppRepository, MdlRepository, PyEmofObject and Element classes (along with their specialized classes in each model).


Textual serialization of models

When a model is managed outside from an application memory space, it is represented by a text consisting of standard alphanumeric characters and where references are formalized as URIs (hyper-references) and  the models are accessed via URL locators. The textual formulation is useful in the following cases:

Model serialization and deserialization (model creation from textual formulation) are performed through the dump() and loadModel() operations of the public interface.
Three serialization formats are used, namely:



Basic processes in the PyEmofUC enviroment

The CountyCity example is used to show the basic environment use cases. When the PyEmofUC environment is installed, the models and meta-models relative to this example are installed too.
File location depends on the folder where the environment has been installed. For the examples described below, the example root folder is supposed to be "c:\temp\PyEmofUC".

1.Environment installation

The full code for the PyEmofUC environment can be downloaded as a ZIP archive (PyEmofUC_0_0.zip).
Along with the environment code (src folder), this ZIP archive includes a set of W3C-schemas for meta-model edition (schemas folder), and some stuff (data and scripts) related to the CountyCity example used for demonstration purposes (CountyCity folder).

Below there is an outline of the PyEmofUC environment once installed.


PyEmofUC => It is the resultant root folder after unpacking the ZIP archive PyEmofUC_0_0.zip. It is used as origin for relative paths. 
CountyCity => Root folder of the CountyCity example, which is used to show the capabilities of PyEmofUC.
src => Root Folder of the Python code of the PyEmofUC environment. Its path is included in the PYTHONPATH environment variable.
pyEmofUC => Python package with the code of the PyEmofUC environment.
__init__.py => Initialization module of the python package.
core.py => Code supporting the meta-meta-model EmofUC.
dumper.py => Code for the textual serialization of models and meta-models
GLOBAL.py => Python module with the constant and global resources of the environment.
loader.py => Code for loading models and meta-models from its textual formulations.
resource.py => Python code for implementating the models repositories.
xmlcore.py => Auxiliar code for location and access to models and meta-models formuled as XML files.
PyRTF => Legacy Phyton package with resources for managing text in RTF format.
toolScripts =>
Python package with utility scripts provided by the PyEmofUC environment.


2. Accessing to the environment from an application

An MDE application operating within the PyEmofUC environment must first create an application repository, which is done by invoking the AppRepository() constructor.
Then, using the environment public interface, the application can load, transform and display models.
One application may create m
ultiple repositories, but every set of models with cross-references between them must be loaded in the same one.

If locations use relative URLs (format "platform: ..."), the user must previously assign to the variable xml core.PLATFORM the root folder absolute address.
In the following examples, the address "c:\temp\PyEmofUC" is assigned as root path for relative locators:

>>> import emofUC.resource as resource

>>> import EmofUC.xmlcore as xmlcore

>>> aRep=resource.AppRepository()

>>> xmlcore.PLATFORM='c:/temp/PyEmofUC'

>>> 


3. Model loading

The loadModel(«modelURL») method must be called for loading a model in a repository.
In addition, this load operation requires loading the meta-model (mandatory) and other referenced models (only if the respective URLs are valid in the context in which they are used).


>>> aRep.loadModel('platform:CountyCity/EagleCounty.xmi')

<emofUC.resource.MdlRepository object at 0x0000000002E8D9E8>

>>> 

In this example, the load of the EagleCounty model has also required the load of the EmofUC meta-meta-model as well as the County meta-model but also the EagleCity model along with its corresponding City meta-model, because there are inter-references among the two models.



The models loaded in the repository can be viewed by obtaining the list of URIs using the getMdlRepositories() method, which returns a map with all uploaded models with their URIs as key.

>>> 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

>>> 


4. Creating a model from an application.

A Python application can create a model, provided that the corresponding meta-model is preloaded within the same application repository.

The following code creates a model (named newCity) compliant to the City meta-model of the CountyCity project.

>>> 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')

>>> 

# Check that the mm is loaded

 

# A new model is created:

#  - The assigned URI

#  - The URL of the metamodel

#  - The mame space prefix

 

# The root repository element is created

 

 

 

# An element of Company type is created

# The root repository element are added

# A value is assignet to name attribute

 

# An elenment of Employ type is created

# The values are assigned to attributtes

 

 

 

# Its added to the owner element

 

# A second Employ element is created

 

 

 

 

 

 

# The newModel is stored according its URL

The table below shows the created model formulated in the RTF format ('platform:CountyCity/DumpedFiles/newModel.rtf').

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.

} #


5. Model creation using the W3C-Schema

When a meta-model is stored in XMI format (e.g. City.xmi), the dump() method also generates and stores the corresponding W3C-Schema (e.g. City.xsd), which describes the contents of the compliant models.
By using that W3C-Schema and a smart XML editor, the operator can enjoy assistance during model edition.

However, the generated schema is lax and only assists the operator in certain aspects. For instance:

In the current version, the editor does not help when assigning references, since they are implemented by means of the generic xsd: anyURI type.

The figure below shows the Altova XMLSpy XML editor used for generating a model.



6. Model creation using the domain-specific language.

When a meta-model is stored in XMI format (e.g. City.xmi), the dump() method also generates and stores the grammar corresponding to it.

The environment provides an editor based on that grammar that assists the operator when formulating the model in textual format. This editor has not been implemented yet. (TODO)


7. Model persistence

Creation, transformation and processing of models are usually done at application memory level using a model repository, remaining there while the application is running.
Upon request, the model is stored in textual or XMI format using a persistent repository. The persistence is performed using the dump(«url») method provided by the public interface of the MdlRepository class.

The following code persists the model with uri = ‘http://unican.es/istr/PyEmofUC/CountyCity/EagleCounty’ in the file with 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')

>>> 


8. Displaying a model

The operator can visualize a model in three formats:

In the current version, the visualization is performed by invoking the corresponding editor on the model file. Previously, the text file must be stored using the dump() method offered by the public interface of the MdlRepository class.

The dump() method generates the required output format according to the corresponding URL extension: ".xmi" is used if the XMI format is the desired one, while for the plain text format the ".txt” is required.
Last, the coloured text uses the ".rtf" extension.

The table below shows the code for generating the EagleCity model files in the three formats whereas the following snapshots show the use of commercial editors compatible with the formats. 

>>> 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')

>>> 



9. Imperative model transformation

An imperative model transformation uses loops and conditional statements for selectively traversing the input model, generating output elements according to the encountered input one. In PyEmofUC this is done with a Python program using its procedural and object oriented styles.

An example of imperative transformation in the context of the CountyCity sample project can be found at CountyCity_CountyToTaxCensus_Imperative_script.py.

10. Declarative model transformation.

Using a declarative style, a model transformation is a two-step process.
  1. The definition of the scope of the input model elements to which the transformation is applied.
  2. A transformation rule produces the output model elements corresponding to each selected input element.

A transformation engine successively iterates over the set of input elements generating the corresponding output elements. In PyEmofUC this is done by means of a Python program in two steps:

  1. The list of output elements is generated using a functional programming style as well as sentences for list compression and generators.
  2. Setting of the references between the output model elements that have been generated during the first step.

An example of a declarative model transformation applied to the CountyCity sample project is CountyCity_CountyToTaxCensus_Declarative_script.py.
For the transformation specification, a style similar to the one used in ATL is used.

11. Removing an application repository.

The deletion of a single model is not yet supported in the current version of PyEmofUC.
Removing a model loaded in a repository is an unsafe and time-consuming operation because in the repository there are defined multiple inter-referenced models, and the deletion of a single model requires solving the references that are left undefined.
The in-memory models are deleted when the application removes the repository containing them.

>>> del aRep

>>> 

Documents

Links of interest