This section may be contrasted with the corresponding Parsing Constraints and Queries for the Ecore binding to see examples of the small changes needed to migrate from the Ecore binding to the Pivot binding.
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
API provides a Facade for the various objects that support different aspects of OCL parsing and evaluation activities in a that spans activities for which the meta-models remain unchanged. A new OCL Facade is required if the meta-models change.
The
OCL
class is a simple type.
There is no need for the Ecore/UML template parameters that parameterize the equivalent Ecore/UML class.
Behind the scenes, the unified Pivot variants of the primary UML, OCL and user and meta-models, complementing Complete OCL documents and Standard Libraries are maintained by a
MetaModelManager
, which also maintains all the collection and tuple specialization singletons so that they can be shared by subsequent processing. A distinct
MetaModelManager
is required for each combination of primary meta-models and complementing Complete OCL documents and so for safety a new
MetaModelManager
is created for each OCL session. Increased metya-model sharing can be achieved by re-using
MetaModelManager
s when constructing a
PivotEnvironmentFactory
.
An OCL parsing activity maintains the root and nested parsing context in
Environment
instances which are created by an
EnvironmentFactory
.
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.
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). It is also good practice to invoke
dispose()
to release all
OCL-related Resource references.
Using the shared Pivot environment factory , we can create an OCL environment suitable for parsing OCL constraints on any Ecore model and evaluating them on instances of the model:
From an OCL instance, we can create a helper object with which to parse constraints and additional operation/attribute definitions.
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
createDerivedValueExpression()
: convenience for attribute derived values
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 or a constraint is an
ExpressionInOCL
,
an instance of the
Abstract Syntax Model.
The Ecore/UML binding variously produces a Constraint or OCLEXpression result. A Constraint has too much context and an OCLExpression too little. An ExpressionInOCL is just right.
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: