The Eclipse OCL component implements the OCL Abstract Syntax model as an EMF-based metamodel. Thus, parsed OCL expressions and constraints can be serialized, for example in XMI documents. The OCL 2.4 specification is unclear about how the serialization of expressions should look (this will be solved in the next OCL 2.5 specification), especially where references to demand-created types are concerned. This topic discusses the approach taken by the Eclipse OCL component to provide a practical solution to this problem.
OCL defines a number of template metaclasses, including the
CollectionType
metaclass and its specializations,
MessageType
, and
TupleType
. In all of these cases, OCL specifies that these
templates are instantiated as needed in the OCL environment, and that only one instance
of a template exists for any given combination of template arguments. For example, only one
OrderedSet(String)
exists and it is created on the occasion when
it is first needed. Likewise, the
OclMessage
type for invocations
of the
EModelElement::getEAnnotation(EString)
operation and the
Tuple{a : String, b : EClass}
type.
The problem is, that the OCL Specification does not indicate how expressions that reference
such demand-created types can be persisted, because it does not define what should own these
types. A similar problem exists for additional operations and attributes defined in OCL
via
def:
expressions. The
TypeResolver
API is responsible for the demand-creation of these types and for their persistence.
Every
Environment
has a
TypeResolver
that persists demand-created types and additional features. For a client that doesn’t require persistence, the
TypeResolver
will create a
Resource
with the dummy
ocl://
scheme (no resource factory is provided for this scheme).
A client that does require persistence of OCL expressions and these demand-created elements
should provide a specific resource in which to store them, either via the
OCL
class’s
newInstance(EnvironmentFactory, Resource)
factory method or via
the
EnvironmentFactory
interface’s
load(Resource)
method.
Resource modelResource = getResourceSet().getResource(
URI.createPlatformResourceURI("/models/My.ecore", true), true);
// persist demand-created types etc. in my model resource
OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl;
ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE, myResource);
// use the OCL to parse constraints, store them in the Ecore model,
// and save everything together in one resource for a consistent,
// self-contained OCL environment
...
The
AbstractTypeResolver
class creates packages in which to store the different elements that it creates: collection types, message types, tuple types, and additional operations and attributes. These last are owned by classes that “shadow” the classifiers in which context they are defined, in
the manner by which the OCL specification’s adaptation for EMOF indicates that operations
are to be “owned” by EMOF
DataType
s.
An environment implementation can customize the way these demand-created elements are
stored, by choosing different packages or using some other strategy altogether. Or, using
the default
TypeResolver
implementation, a client of the OCL
parser can find the demand-created objects in the resolver’s resource and relocate them
as needed.