# Classic Ecore/UML Programmers Guide

The Ecore/UML Programmers Guide describes the ways in which the Ecore or UML bindings of Eclipse OCL can be used from Java programs.

The Ecore binding has been available since Eclipse OCL 1.0.0 (Callisto). The UML binding was added in 1.1.0 (Europa). Both will remain for as long as necessary. Examples quality prototypes of the new UML-aligned Pivot binding were first available in 3.1.0 (Indigo). The Pivot binding became the preferred binding in 6.0.0 (Mars). The Pivot binding is described in a separate Pivot Programmers Guide.

The OCL Parser/Interpreter provides an implementation of the Object Constraint Language 2.4 specification for EMF-based metamodels and models. It offers OCL constraint and query parsing and evaluation, model-based validation, and provides an infrastructure for content assist in textual editors.

The following features are supported in the current version:

- Classifier invariant constraints

- Operation precondition and postcondition constraints and body conditions

- Property constraints (initial-value and derivation)

- Attribute and operation definitions (def: expressions)

- Package context declaration

- Basic values and types

- Collection types

- Navigation of attributes and association ends

- Operation invocation

- Iteration expressions (all standard iterators)

- Let expressions

- If expressions

- Tuples

- Message expressions, including unspecified values

- Operations predefined by OCL: allInstances(), oclIsKindOf(), oclIsTypeOf(), oclAsType(), oclIsNew()

- Escape syntax for illegal names: type, operation, attribute, etc. names that correspond to OCL reserved words can be escaped in the standard fashion using a leading underscore (‘_’). In addition, names that contain spaces or tabs can be escaped by enclosing them in double-quotes (‘"’; this is non-standard). e.g., `self.ownedRule->forAll(c : Constraint | c._context = self)`

The above constructs are supported by the parser for parsing and for evaluation, with the exception of the oclIsNew() operation and message expressions. All of the above are supported for both Ecore and UML models. The following are supported by default for UML (both in parsing and evaluation):

- Navigation of non-navigable association ends (including those that are owned by the association)

- Qualified association end navigation

- Navigation to association classes, including source qualifiers

- Operations predefined by OCL: oclIsInState()

The following features are provided in addition to the OCL specification:

- String case conversion operations: toUpper(), toLower()

- Support for comparison (<, <=, etc.) and sorting of any java `Comparable` s of conformant types

- Transitive closure of associations: closure(expr : OCLExpression) iterator

- Navigation of “hidden” opposites of references specified in Ecore models using a `Property.oppositeRoleName` annotation with source `http://schema.omg.org/spec/MOF/2.0/emof.xml` on the forward reference, producing an `OppositePropertyCallExp` expression

The OCL implementation is defined in plug-ins for convenient deployment in Eclipse, but as is the case for EMF, it can also be used stand-alone. The plug-ins are partitioned thus:

- `org.eclipse.ocl`: the core parsing, evaluation, and content assist services. Definition of the OCL Abstract Syntax Model and Environment API. These APIs are generic, independent of any particular metamodel (though using Ecore/EMF as the meta-meta-model).

- `org.eclipse.ocl.ecore`: implementation of the Ecore metamodel environment, binding the generic Environment and AST APIs to the Ecore language. Provides support for working with OCL constraints and queries targeting Ecore models.

- `org.eclipse.ocl.uml`: implementation of the UML metamodel environment, binding the generic Environment and AST APIs to the UML language. Provides support for working with OCL targeting UML models.

Please refer to the OCL Interpreter Tutorial for review of the code samples.

## Parsing Constraints and Queries

The OCL parser provides two APIs for parsing constraint and query expressions. The `OCLHelper` interface is designed primarily for parsing constraints and query expressions embedded in models, such as Ecore or UML models. The `OCL` class serves as the main entrypoint into the parsing API but also implements the parsing of OCL documents, for example from text files. In both cases, the concept of `Environment` is crucial.

### The OCL Environment

The following diagram shows the core of the `Environment` API, that clients of the OCL parser interact with:

The `OCL` class is a generic type; its type parameters represent the various metaclasses of the metamodels that OCL works with in the UML/MOF family of OMG specifications. For example, `<C>` represents the Classifier concept, `<O>` the Operation concept, etc. See the discussion of metamodels supported by OCL for details of the mappings. The same type parameter names are used consistently throughout the OCL APIs to represent the same metaclasses.

The `OCL` class defines instances of autonomous OCL parsing and evaluation environments. It has a single root `Environment` created by an `EnvironmentFactory` implementation for a particular EMF-based metamodel. The OCL environment consists, conceptually, of the model that is to be constrained together with all of the constraints and additional operations and attributes defined (via OCL) for the purpose of formulating constraints.

`Environment` s nest. Usually the root environment has no correlation to an element in the model, or it may correspond to some `Package` providing a default namespace (called a package context). Alternatively, it may contain one or more nested environments defining package namespaces. A package context contains one or more classifier contexts, which in turn can contain operation and/or attribute contexts. Whereas the purpose of a package context is primarily to assist in the look-up of named model elements, the classifier, operation, and attribute contexts have deeper meaning.

A classifier context defines the type of the `self` variable in OCL constraints and queries. By itself, it is the context for invariant constraints for the context classifier. Additionally, as the parent context for operation and attribute constraints, it indicates the classifier in which context an operation or attribute constraint applies; this may be the classifier that defines these features, or it may inherit them from some more general classifier.

An `Environment` may contain named `Variable` s to which OCL expressions can refer. The most common of these is `self`. Others include the parameters defined by an operation (and its `result`), in the case of an operation context. The OCL API even allows clients to add variables, in code, to define “global” names.

### Creating an OCL Environment

The static factory methods on the `OCL` class are used to create instances. It is a good practice to re-use the same OCL instance for all parsing and evaluation of constraints and queries on a model while that model is loaded (usually in some `ResourceSet` in an editor). Using the shared environment factory for the Ecore metamodel, we can create an OCL environment suitable for parsing OCL constraints on any Ecore model and evaluating them on instances of the model:

[Text for cut and paste]

Several of the type parameters in the `OCL` generic type signature are useful mostly within the OCL API. We leave them, here, as wildcards.

### The OCL Helper

From an OCL instance, we can create a helper object with which to parse constraints and additional operation/attribute definitions. This `OCLHelper` stores all of the instantiations of OCL template metaclasses (such as `CollectionType(T)` and `TupleType` and additional operation/attribute definitions in the root environment of the `OCL` that created it. This ensures that all of these constructs are available for reuse in subsequent parsing.

The `OCLHelper` is primarily designed for parsing constraints and query expressions embedded in models, providing the following API for that purpose:

- `createQuery()`: parses a query expression

- `createConstraint()`: parses a constraint of a given `ConstraintKind`

- `createInvariant()`: convenience for invariant constraints

- `createPrecondition()`: convenience for pre-condition constraints

- `createPostcondition()`: convenience for post-condition constraints

- `createBodyCondition()`: convenience for body conditions

- `createInitialValueExpression()`: convenience for attribute initial values

- `createDerivedValueExpression()`: convenience for attribute derived values

- `defineOperation()`: convenience for additional operation definitions

- `defineAttribute()`: convenience for additional attribute definitions

Different kinds of constraints require different context environments. The `setContext()`, `setOperationContext()`, and `setAttributeContext()` methods create the appropriate nested `Environment@s in the host @OCL` instance’s root environment.

The result of parsing a query expression is an `OCLExpression` , an instance of the Abstract Syntax Model . The result of parsing a constraint is an instance of the `Constraint` metaclass defined by the `OCL`'s target metamodel .

[Text for cut and paste]

Ecore does not define a `Constraint` metaclass, so the OCL binding for Ecore supplies one.

### Operation and Attribute Contexts

In the case of constraints on operations or attributes, the context consists of two elements: the constrained operation/attribute and a classifier in the context of which the constraint is to apply. This accounts for the possibility that a classifier defines constraints on inherited features. As an example, consider the `EModelElement::getEAnnotation(EString)` operation and `EReference::eReferenceType` property in the Ecore metamodel. These can be constrained as follows:

[Text for cut and paste]