OCL Persistence

OCL Persistence

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.3.1 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.

The Type Resolver

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.