# Unified or Pivot Programmers Guide

The Unified or Pivot Programmers Guide describes the ways in which the Pivot binding Eclipse OCL can be used from Java programs.

The Pivot binding was first available as an examples quality prototype in 3.1.0 (Indigo). The Pivot binding became the preferred binding in 6.0.0 (Mars). The older Ecore and UML bindings are described in a separate Ecore/UML 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.pivot`: the neutral Pivot model, interfaces, Standard Library and evaluator.

- `org.eclipse.ocl.examples.codegen`: the OCL to Java code generator.

- `org.eclipse.ocl.examples.debug...`: the extensible debugger.

- `org.eclipse.ocl.examples.validity`: the Validation View.

- `org.eclipse.ocl.xtext...`: Xtext editors.

## OCL Environment

The Pivot-based Eclips OCL maintains signifcant amount of working state to cache aspects of the user metamodels and models.

The OCL working meta-state used for OCL parsing and analysis comprises at least a `CompleteEnvironment`, `CompleteModel`, `EnvironmentFactory`, `MetamodelManager`, `Orphanage` and `StandardLibrary`.

The additional OCL working state for OCL execution comprises an `Executor` and a `ModelManager`.

### OCL Implementation Problem

Eclipse OCL exploits the Eclipse Modeling Framework (EMF) and so has to comply with EMF APIs. Unfortunately the most basic EMF API `getXXX()` to access the feature `xxx` provides no ability to pass any OCL working state to an OCL implementation of `getXXX()`. There is also no ability to create or destroy the OCL working state before and after a sequence of activities for which the OCL requirement of model invariance is satisfied.

### OCL adapters pre-2021-03

Prior to the 2021-03 (6.14.0) release, the OCL working meta-state was lazily created on demand and eventually garbage collected. The working meta-state was persisted by use of an `EnvironmentFactoryAdapter` to attach the state to the `ResourceSet` containing the user model / metamodel. The state could be recovered by a hiearchical search of the user model’s containment hierarchy. The `OCL` facade supports multiple usage of the state via a share count so that GC only kicks in once all usage is done. A `WeakOCLRef` provides another mechanism for sharing.

The OCL working state is similarly maintained via `ResourceSet` adapters and also by an entry in the validation context of the EMF `validate()` API.

The above approaches work for straightforward usage. But...

When OCL invariants or getters are executed from an installed model, there is no `ResourceSet` and so the user’s OCL context is not available. Rather a special global OCL working meta-state is used; it ignores any Complete OCL contributions from the user’s application.

Models shared between applications are isolated by careful use of `ValidationAdapter`s to identify which OCL is involved.

Multi-threaded applications may successfully share the working state provided the user has resolved all other threading hazards.

Applications using multiple OCLs such as one reference OCL for an old-way, and another experimental OCL for a new way, may successfully use distinct adapters.

However from a developer’s perspective it’s all very fragile and complicated and metamodel schizophrenia is always waiting for an opportunity to bite.

Avoiding leakage with EMF applications is quite hard since a single refernce from one of the global registries can easily lock everything into memory,

Identifying when the user model analysis in the working state can be re-used and when it must be recomputed is hard since there is no mechanism for a user to delimit the duration of model invariance.

Investigation of a bug in the implicit opposites underpinning a stereotype in a static UMLprofioe revealed that the analyses supporting allInstances and implicitOpposites was very very pessimitic and consequently very inefficient.

The major use cases for OCL applications are model validation and model transformation. For the latter, the transformation tool can easily initialize the OCL state prior to transformation and clean up afterwards. For the former case, a massive performance improvement is possible if the one working state can be re-used throughout the model validation.

### OCL per Thread post-2021-03

For the 2021-03 (6.14.0) release a new approach is taken. The OCL working state is referenced by a thread local variable making discovery easy and cleanup inherent in the demise of the thread. Lazy creation is fairly easy too.

There is no need for a special global OCL context with defective capabilities; the `GlobalEnvironmentFactory` and its `INSTANCE` is obsolete.

But, by default multi-threaded applications have a distinct OCL working state per-thread, which may be beneficial or inefficient. if the programmer is able to manage thread safety, then the `ThreadLocalExecutor.set` API may be used to share the same OCL state on more than one theead. NB the current OCL code has some synchronizations that may help with thread safety but overall there is no guarantee of thread safety.

But, multi-OCL applications cannot have more than one active OCL per-thread.

One variation of the multi-OCL use case was prevalent in the OCL JUnit tests where one OCL processed a reference model while another OCL processed an application model. The solution for interleaved usages is to invoke `OCL.deactivate` or `ThreadLocalExecutor.detachEnvironmentFactory` to suspend one OCL before `OCL.activate` or `ThreadLocalExecutor.attachEnvironmentFactory` resumes another OCL. The multiple OCLs can therefore co=exist till eventually `OCL.dispose()` cleans up.

Another variation of the multi-OCL use case was prevalent in the QVTd JUnit tests where one main extended OCL processed an application model while a nested OCL validated/serialized intermediate results. The same `deactivate`/`activate` solution again ensures that only one OCL is actve.

The use of concurrent OCLs on the same thread is diagnosed and results in a log message such as Concurrent EnvironmentFactory instances inhibit local thread Executor passing forcing th code to fall back on the old adapter mased approach. The solution, as described above, is to use `deactivate`/`activate` to eliminate the concuurent activity.

But, whereas the old approach was very pessimistic creating a new OCL working state far too often, the thread-based OCL state must be invalidated by invoking `ThreadLocalExecutor.reset()` whenever the user models are changed in any way that might undermine the OCL assumption that models do not change. (This change could be automated using EMF’s TrackingModificatinAdapters but the cost is considered too high compared to a manual reset).

But, there is currently no support for sharing the UI thread across many `IWorkbenchPart`. i.e if two views both use OCL on the UI thread, the state of one view may confuse the other. Fortunately OCL activity such as validation is generally delegated to a worker thread avoiding the confusion and guaranteeing a new OCL per usage.

The adapters associated with the old approach are now obsolete but remain for now as legacy/compatibility clutter. They will be removed in a future release.