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
interface. An implementation of this interface binds the metamodel’s metaclasses to the generic type parameters of the
class. The metamodel-specific
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.
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
OCL Standard Library model
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
The implementation-specific packages provide
Visitors throughout the entire metamodel (OCL and MOF)
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
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)
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
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
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.
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().
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.
CollectionTypeIds are a degenerate form of specialization/generalization with a single template parameter. The template parameter is declared explicitly in generalizations.
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.
LambdaTypes are self-contained in the same way as tuples with specializations of generalizations.
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.
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.
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.)
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.