OCL Relationship to Metamodels

OCL Relationship to Metamodels

The Pivot-based OCL implementation provides indirect support for models defined using either the Ecore or the UML metamodel (as implemented by the Eclipse EMF and UML2 projects), and an extensibility API that allows additional EMF-based metamodels to be plugged in. The indirection through the UML-aligned Pivot metamodel makes OMG compliance much easier and decouples the implementationm from particular bindings. Support for an alternate concrete metamodel representation is therefore comparatively simple.

The OCL API implements support for different target metamodels via the EnvironmentFactory interface. An implementation of this interface binds the metamodel’s metaclasses to the generic type parameters of the OCL class. The metamodel-specific Environment implementation constructed by this factory implements the reflection capability required by OCL to discover the elements of the model being constrained and the relationships between them.

The Pivot Metamodel Binding

A preliminary OCL binding for the Pivot metamodel is provided in the Indigo release by the org.eclipse.ocl.examples.pivot plug-in. It is planned to promote this to org.eclipse.ocl.pivot in the Kepler release.

The Pivot metamodel prototypes resolutions of the following problems in the OCL 2.3.1 specification

  • UML-alignment

  • OCL Standard Library model

  • XMI interchange

  • Complete OCL implementability

The support for an OCL Standard Library model enables large parts of the OCL specification to be captured by models. This makes the behavior mutable and extensible through definition of alternate or extended library models. (The corresponding Ecore and UML bindings have an Ecore representation of the library but much of its functionality is directly implemented and so immutable.)

The Pivot metamodel is auto-generated by a package merge of

  • selected parts of the UML metamodel

  • additional OCL packages

  • implementation-specific packages

The implementation-specific packages provide

  • Visitors throughout the entire metamodel (OCL and MOF)

  • Ecore extensions

It is anticipated that the performance advantages of a uniform compliant metamodel, without the complexities of the templates from the org.eclipse.ocl plugin, will outweigh the initial overhead of converting an Ecore or UML metamodel to Pivot form. Once this has been demonstrated, the direct Ecore and UML metamodels will be deprecated.

The Pivot binding is provided by the PivotEnvironmentFactory class. For compatibility, as a default, the Pivot environment uses the static EPackage registry to look up package names. This default is deprecated since the domain of allInstances() may be very large when many models are registered. It should therefore be supplied with an alternative package registry (for example, one local to a ResourceSet) for relevant metamodels. The static registry is then used as a backup for package lookups, but not for allInstances(). The Pivot environment factory maintains the Pivot models associated with

  • Ecore metamodels in use

  • UML metamodels in use

  • Library models in use

  • Concrete Syntax source models

    • OCLinEcore (rather than Ecore)

    • Complete OCL

    • OCL Standard Library

The Pivot binding for OCL will provide the full capabilities of the UML binding, but at present only the Ecore facilities have been tested. The Pivot binding has the additional ability to support extensions to the library.

For applications that work exclusively with the Pivot binding for OCL, the org.eclipse.ocl.examples.pivot package defines an OCL class that provides similar facilities to the corresponding Ecore and UML binding equivalents.

The Pivot metamodel is used by Eclipse OCL for:

  • all Xtext editors; editing, parsing, analysis and validation

  • the Xtext OCL console; editor and evaluation

  • EMF delegates using the http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot URI

  • explicit use of the Pivot metamodel from Java

The Pivot metamodel is not used by Eclipse OCL for:

  • OCL console editing and evaluation

  • EMF delegates using the http://www.eclipse.org/emf/2002/Ecore/OCL/LPG URI

  • Impact Analyzer.

  • explicit use of the Ecore or UML bindings from Java

EMF delegates using the http://www.eclipse.org/emf/2002/Ecore/OCL virtual URI are redirected to either http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot or http://www.eclipse.org/emf/2002/Ecore/OCL/LPG by the setting of the “Executor targeted by the default OCL delegate” preference setting, which defaults to http://www.eclipse.org/emf/2002/Ecore/OCL/LPG for compatibility.

Note that the Indigo and Juno OCLinEcore editor uses the http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot URI and so uses the Pivot Evaluator, whereas the Helios OCLinEcore editor used the http://www.eclipse.org/emf/2002/Ecore/OCL URI and so the Ecore evaluator. A file using the http://www.eclipse.org/emf/2002/Ecore/OCL URI will automatically be upgraded to the http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot URI when edited using the Indigo or Juno OCLinEcore editors.

In Kepler, the OCLinEcore editor preserves any existing delegate URI selection. The new “Preferred executor requested for OCL constraints” preference determines the URI when no previous setting is available. This defaults to http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot for backwards compatibility. h2(#Pivot-Ids). Ids

The ElementId hierarchy provides the simplest base level of metamodel representation. The ElementIds feature

  • identity

  • uniqueness

  • thread-safety

  • predictability

  • hashcodes

Every primary hierachical metamodel object such as a Package, Type, Operation or Property has a globally unique identity established by the package-class-feature path.

Auxiliary metamodel object such as a TemplateParameter, TuplePart or List-of-Parameter have a locally unique identity supporting fast matching of tuples or single lookup for operation parameters.

Id Equality

ElementIds are unique, whereas metamodel elements are not; there may be many meta-models in many applications all with their own Boolean PrimitiveTypeImpl instances. The equivalence of these elements may be established rapidly since each returns the same TypeId.BOOLEAN singleton from PrimitiveTypeImpl.getTypeId().

IdManager

Uniqueness of ElementIds is enforced by the various getXxxId methods of the single IdManager.INSTANCE. These methods are synchronized to ensure thread safety. Child hierarchical objects are similarly mediated by their parent.

CollectionTypeId

CollectionTypeIds are a degenerate form of specialization/generalization with a single template parameter. The template parameter is declared explicitly in generalizations.

TupleTypeId

TupleTypes are self-contained, that is all external template parameter references with the part types are bindings of a specialized tuple type whose generalization replaces those external references by the template parameters of the generalization.

For instance given a declaration

Set(A)::op(B)() : Tuple(a:A, b:Bag(B), c:B)

Tuple(a:A, b:Bag(B), c:B) is the (A,B) specialization of the Tuple(T1,T2)(a:T1,b:Bag(T2),c:T2) generalization.

LambdaTypeId

LambdaTypes are self-contained in the same way as tuples with specializations of generalizations.

ParameterIds

A ParameterIds identifies an ordered list of typeid suitable for identifying an operation’s parameter list by a single object and hashcode.

A ParameterIds has no knowledge of its parent Operation and so ParameterIds are reused whenever the typeid list arises. Note that collection typeIds are always collectionTypeIds, so there is no need for multiplicities. The residual optional existence is not subject to overloading and is ignored in ParameterIds.

LambdaTypes reuse ParameterIds to capture the extended type list comprising the typeids of context-type, result-type then parameter-types.

TuplePartId

A TuplePartId identifies a part of a Tuple. It has a name, typeid and index. The index is the part position in the set of parts in a parent tuple alphabetically sorted by name. It provides efficient access to a slot position in a tuple representation.

A TuplePartId has no knowledge of its parent Tuple and so TuplePartIds are reused whenever the same combination of name, typeid and index arise.

TemplateParameterId

A TemplateParameterId identifies a template parameter in the ordered list of template parameters in a parent templateable element. It has just an index in the parent list. For debugging purposes a TemplateParameterId has a name such as $0 or $1.

A TemplateParameterId has no knowledge of its parent templateable element and so only a couple of TemplateParameterIds ever exist. Three are statically defined as TypeId.T_1, T_2, T_3.

TemplateParameterId has no knowledge of whether it is a type or value parameter. Pragmatically a TemplateParameterId extends a TypeId. (This design decision may need revision.)

Code Generation

Since the ElementIds are predictable and unique, code generation can assign them for computation once in static variables so that large parts of the costs of model elememnt location can be performed at compile time. At class load time it is only necessary to construct/share the ElementId object. At run-time the ElementId provides a hashcode to provode rapid lookup.