PyEmofUC

EmofUC meta-models

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

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

Table of Contents

EmofUC meta-meta-model

The EmofUC meta-meta-model is an extension of the OMG EMOF 2.4 meta-meta-model, in which minor modifications have been introduced in order to simplify its Python implementation in the PyEmofUC environment:

The class diagram below shows the EmofUC classes organized by containment and inheritance.
Their detailed description (attributes and associations) can be found in the EMOF 2.4 specification.


Python implementation of EMOF classes

The Python classes associated to the meta-meta-model elements are dynamically generated at runtime. The implementation has the following features:

Extensions provided by EmofUC

The EmofUC meta-meta-model incorporates a number of extensions which are specified associating a tag (with predefined key names) to the meta-models elements.
The extensions defined are:

Declaration of native primitive types

EMOF (as well as EmofUC) allows to declare new primitive types. However, EMOF does not provide mechanisms for specifying nor characteristics of the newly defined data types neither inheritance relations among them.
EmofUC declares 5 primitive data types based on the Python native data types:

Their definition is complete because they correspond to well-defined Python types. The types also match those defined in the UML Annex. The only difference is that UML suggests the UnlimitedNatural unsigned type whereas PyEmofUC proposes the PyUnlimitedInteger type, which corresponds to a signed integer.



Declaration of specific primitive types

EmofUC introduces a number of types derived from native primitive types. They increase the detail level when formalizing meta-models, hence allowing model verification before installing the models in the environment.

The types defined by PyEmofUC are shown in the previous figure:

Qualification of primitive types

  Four tags with predefined and reserved names have been specified in order to declare features of the primitive types defined in a meta-model:

<ownedType  name="URI" xmi:id="emof.URI" xsi:type="emof:PrimitiveType">

      <tag name="PT" xmi:id="emof.URI.PT" xsi:type="emof:Tag"

             value="emof#emof.PyString"/>

      <tag name="RE" xmi:id="emof.URI.RE" xsi:type="emof:Tag"

             value="((http://)|(file:///)|(platform:))([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|/|[.]|_)*"/>

</ownedType>

  The table below shows the definition of the primitive data type Percentage as a PyReal type within the range [0.0, 100.0].

<ownedType  name="Percentage" xmi:id="mast2.Percentage" xsi:type="emof:PrimitiveType">

      <tag name="PT" xmi:id="mast2.Percentage.PT" xsi:type="emof:Tag" value="emof#emof.PyReal"/>

      <tag name="MAX" xmi:id="mast2.URI.MAX" xsi:type="emof:Tag" value="100.0"/>

      <tag name="MIN" xmi:id="mast2.URI.MIN" xsi:type="emof:Tag" value="0.0"/>

</ownedType>

Declaration of derived attributes

A derived property has a value that is evaluated based on other attributes in the same class. A derived property is not implemented by means of a Python attribute, but through a Python property in which the getter method calls another specific method.
PyEmofUC uses the "DE" tag for declaring the Python code implementing the method that evaluates the value of a derived property.
The table below shows a chunk of code declaring a derived property named isRoot in the emof.Package class.

<ownedType name="Package" xsi:type="emof:Class" xmi:id="emof.Package" superclass="#emof.NamedElement">

      <ownedAttribute name="nestingPackage" xmi:id="emof.Package.nestingPackage" xsi:type="emof:Property"

              theType="#emof.Package" opposite="#emof.Package.nestedPackage"/>

……..

      <ownedAttribute name="isRoot" xmi:id="emof.Package.isRoot" xsi:type="emof:Property"

                          theType="#emof.PyBoolean" isDerived="True" >

             <tag name="DPE" xmi:id="emof.Package.isRoot.DPE" xsi:type="emof:Tag"

                               value="return self.nestingPackage==None"/>

      </ownedAttribute>

</ownedType>

The code below shows the Python code for the class implemented by the PyEmofUC environment, based on the information provided by the "DPE" tag.

     def getisRoot(self):
           return self.nestingPackage==None
      isRoot=property(getisRoot)

Please, note that the tag value attribute must strictly respect the indentation required by the Python syntax.

Operations implementation

The EMOF specification allows to associate operations to meta-model classes in order to describe the instances behaviour, but it only describes the methods signature, i. e., the operation name, the parameters name and type, and the return type. Its only goal is to describe the public interface of model elements.

PyEmofUC allows to associate the Python code implementing operations by means of "OPE" tags. This mechanism is only useful if the operation code is simple, because it presents dificulties if trying to verify its correctness.
For operations with more complex code, it should be associated using inheritance and extension strategies. (TODO).

The "OPE" tags may be aggregated to emof.Operation elements and the value attribute contains the Python code implementing the operation behaviour. The environment introduces the basic syntax indentation required by the invocation code, but in the code included in the tag, it must be included in the indentation between the code sentences.

The table below shows an example of code operation assignment.

<ownedType name="Familia" xmi:id="fam.Familia" xsi:type="emof:Class" superclass="#fam.Elemento">

                                                                               

      <ownedAttribute name="miembro" xmi:id="fam.Familia.miembro" xsi:type="emof:Property"

                theType="#fam.Persona" isComposite="True" upper="*" opposite="#fam.Persona.familia"/>

      <ownedAttribute name="padre" xmi:id="fam.Familia.padre" xsi:type="emof:Property"

                theType="#fam.Adulto" lower="0"/>

      <ownedAttribute name="madre" xmi:id="fam.Familia.madre" xsi:type="emof:Property"

                theType="#fam.Adulto" lower="0"/>

      <ownedOperation name="hijo" xmi:id="fam.Familia.hijo" xsi:type="emof:Operation"

                theType="#fam.Persona" lower="0" upper="*"> 

             <tag name="OPE" xmi:id="fam.Familia.hijo.OPE" xsi:type="emof:Tag"

                    value="hijos=list(self.miembros);hijos.remove(self.padre)if self.padre else None;hijos.remove(self.madre) if self.madre else None; return hijos"/>

      </ownedOperation>

</ownedType>       


The following chunk of code is incorporated by the environment to the class where the operation is defined.

     def hijo(self):
          hijos=list(self.miembros);hijos.remove(self.padre) if self.padre else None; hijos.remove(self.madre) if self.madre else None; return hijos


Documentation introduction

"DOC" tags are used in order to add documentation into models:

<ownedType name="Elemento" xmi:id="fam.Elemento" xsi:type="emof:Class"

            superclass="emof#emof.Object" isAbstract="True">

      <tag name="DOC" xmi:id="fam.Elemento.DOC" xsi:type="emof:Tag"

                value="Elemento abstracto raiz de otros tipos de elemento de la familia"/>

</ownedType>

Documents

Allocating documentation at model elements:

Links of interest