Complete OCL tutorial

Complete OCL tutorial

This tutorial has been updated for Eclipse Mars: Eclipse 4.5, EMF 2.11, OCL 6.0.

Overview

In this example you will

  • Get an Overview of the Complete OCL language

  • Load a Complete OCL document into a third party application

  • Enhance Ecore validation for derived properties

  • Validate an Ecore model using additional Complete OCL validation

  • Enhance UML validation

  • Validate a UML model using additional Complete OCL validation

  • Enhance Xtext validation

  • Validate an Xtext grammar using additional Complete OCL validation

Complete OCL Utility

By itself, OCL is almost useless, since without any models to operate on, the constraints cannot achieve a great deal.

The simplest way to make OCL useful is to embed OCL expressions within a model to enrich the basic structural characteristics of a model with more complex behavior. OCLinEcore provides this capability for Ecore models. Papyrus provides comparable capabilities for UML models.

This tutorial introduces the Complete OCL language which may be used to provide a self-standing document that complements a pre-existing meta-model.

Load Complete OCL Tutorial Example Project

All the material for this tutorial is available as part of the CompleteOCLTutorial Example project that you may load by selecting New then Example... using the right button context menu of the Project Explorer. This should give the New Example dialog in which you can select the OCL (OCL Constraint Language) Plugins and the Complete OCL Tutorial and then Next.

Then Finish.

If you do not see these example projects, follow the Instructions for installing the OCL Editors.

The resulting project has a few test files.

Complete OCL Language Overview

The Complete OCL language is described in detail in the Complete OCL section of this documentation. In this tutorial we will provide just a brief overview of the language. If not already open, double click on ExtraEcoreValidation.ocl to show the following text that provides examples of many important aspects of the Complete OCL syntax.

import declarations

The import statement is a serious omission from the OMG specification, since without it, any attempt to align the Complete OCL constraints with external models relies on implementation-specific magic. The import statement is therefore an Eclipse OCL extension that is likely to be part of a future OCL specification revision.

Zero or more import statements may be present to specify the URIs of external model elements and optionally alias names for those elements. In the example:

import ecore : 'http://www.eclipse.org/emf/2002/Ecore#/'

http://www.eclipse.org/emf/2002/Ecore specifies the URI of the Ecore metamodel and #/ is the fragment URI navigating to the root element which is the Ecore package. The ecore specifies an alias for this package, which happens to be the same as the name of the package. Within the Complete OCL document, the imported model element may be referred to by its alias.

When using the Ecore and UML bindings, the Java API support for using Complete OCL documents requires implementation-specific magic; the imported models must be loaded into the package registry by the invoking code. Import statements are not used.

Prior to the Juno release, import statements were not understood and so there was a usage conflict between Pivot and Ecore/UML bindings. Preparation of a Complete OCL document using the Xtext editor, or usage with Pivot model and Xtext parser required import statements. But re-use with the Ecore and UML LPG parser required the import statements to be removed.

In Juno, the LPG parser ignores the import statements, so they may be left in.

package context declaration

A package context declaration may bracket declarations that complement model elements within the complemented package.

package ecore

...

endpackage

This specifies that additional Complete OCL declarations will complement the pre-existing declarations of the ecore package.

Multiple package context declarations may be used to complement multiple packages.

The package context declaration may be omitted if subsequent classifier context declarations have a fully qualified name identifying the package.

classifier context declaration

A classifier context declaration introduces declarations that complement subsequent model elements within the complemented classifier.

context EModelElement

The classifier context is terminated by a context or an endpackage.

feature definitions

Additional operations and properties may be defined for use within the Complete OCL document. These features may be used as if they were part of the complemented meta-model.

def: asError(verdict : Boolean) : Boolean =
if verdict then true else null endif

def: hasDerivation : Boolean = eAnnotations->select(source.startsWith(
'http://www.eclipse.org/emf/2002/Ecore/OCL'))->notEmpty()

A definition starts with the new feature name, then the parameters for operations and the feature type followed by an OCL expression that evaluates the operation or the property.

For properties such as hasDerivation there is very little difference between a property definition hasDerivation and a parameter-less operation definition hasDerivation(). The property definition and usage is two characters shorter and may seem more natural. The operation definition has the advantage that it can be overloaded in derived classes.

class invariants

Invariants may be imposed on a complemented meta-model. The invariant comprises the name of the invariant followed by an OCL expression that evaluates true when the invariant is satisfied.

inv DerivationIsTransient: hasDerivation implies transient

These invariants are executed when a model is validated in an application that has loaded the complementing Complete OCL document. The significance of this is explained in OCL->Load Document Menu Action.

The readability of constraints can be significantly enhanced by the use of let-variables or the re-use, as above, of the hasDerivation helper property.

custom messages

Eclipse OCL supports two extensions to invariants that allow the validation failure messages and severities to be customized.

inv DerivationIsVolatile(
'"volatile" must be specified for derived feature ' + self.toString()):
asError(hasDerivation implies volatile)

The invariant name may be followed by a parenthesized OCL expression that computes a String to be used as the validation failure message.

The severity of a validation failure may be controlled by the non-true value evaluated by the invariant expression.

  • a false return indicates a warning severity

  • a null return indicates an error severity

  • an invalid return indicates a fatal severity

See Custom Validation Messages for more details.

operation and property context declarations

Complete OCL also allows an incomplete operation or property declaration in the complemented meta-model to be completed.

  • initial value expressions or derived value constraints may be specified for properties.

  • body expressions and precondition/postcondition constraints may be specified for operations.

These facilities are of limited use since OCLinEcore avoids the need for incomplete meta-models.

OCL->Load Document Menu Action

The major disclaimer in the above is that the Complete OCL only complements the complemented meta-model in applications that have loaded the Complete OCL.

Prior to the Juno release, this meant that Complete OCL was only usable in custom Java applications since no standard modeling applications would load the complementing document.

The OCL->Load Document menu action enables a Complete OCL document to be loaded into a wide variety of applications.

The OCL->Load Document menu action is added to the right button menu of applications with a ResourceSet accessible from the current selection.

It has been observed that the extra menu action is not always immediately available, so if you do not see it, hit Esc to cancel the menu, select something corresponding to a model object and right click again.

In Mars, suitable applications are

  • an editor generated from an Ecore meta-model

    • the Sample Ecore Editor

    • the UML Model Editor

    • the Papyrus Model Editor

    • your model editor

  • an editor generated by Xtext

    • the Xtext Editor

    • the MWE2 Editor

    • the OCLinEcore Editor

    • your DSL editor

The OCL->Load Document menu action activates the Load Complete OCL Document dialog in which you can browse Registered Complete OCL Documents, the File system or the Workspace for one or more Complete OCL documents to load, or often more conveniently you can just Drag and Drop them from an Operating System Explorer or an Eclipse Explorer.

After clicking OK the documents load.

Behind the scenes, it is necessary to install global wrappers around all complemented packages. These wrappers are sensitive to the ResourceSet for which complementing has been requested and so although this incurs a small performance penalty for use of the complemented packages in other applications, it should not affect the functional behavior of other applications.

Example Complete OCL complements for Ecore

The Sample Ecore Editor has acquired many useful validation rules, so that for many usages just invoking Validate is quite sufficient. But what if it isn’t? Perhaps you have some style conventions that you wish to apply. Perhaps the built-in rules are not sufficient.

Prior to Juno and the OCL->Load Document capability, your only choice would be to check out the Ecore Editor and create a custom variant. Now you can use Complete OCL to extend the Sample Ecore Editor.

We will revisit the ExtraEcoreValidation.ocl document that we have just examined and use it to rectify inadequate checking of derived properties by the Sample Ecore Editor. The document provides six invariants, at least three of which detect problems that were encountered by users during the Indigo release cycle.

DerivationIsVolatile

The EMF code generation templates have a simple treatment of volatile. Non-volatile variables have an associated field which is returned by the get operation. This overrides any derivation that might be supplied.

inv DerivationIsVolatile: asError(hasDerivation implies volatile)

We therefore want to diagnose that if an EStructuralFeature has a derivation then the volatile declaration is also present to avoid the derivation being ignored.

This problem is so serious that the basic expression is wrapped in the asError operation to convert the default true / false okay/warning severity into the true / null okay/error severity.

DerivationIsTransient

The EMF code generation templates have a similarly simple treatment of transient. Non-transient variables will be serialized as part of a model save. This is not usually appropriate since the derived value is redundant and can be recomputed when the model is loaded again.

inv DerivationIsTransient: hasDerivation implies transient

We therefore want to diagnose that a derivation is not serialized because of a default non-transient declaration.

DerivationIsNotComposed

Composition is handled directly by EMF and it is not clear that it is appropriate to define an alternate meaning of composition. It is pretty certain that EMF will not permit an alternate semantics.

inv DerivationIsNotComposed: asError(hasDerivation implies not containment)

We therefore want to diagnose if a derivation is attempting to specify alternate composition semantics and report an error if this occurs.

DerivationWithOppositeHasOppositeDerivation

Opposites are also handled directly by EMF, but it is possible to replace this functionality. However if the forward functionality is replaced, it is very unlikely that EMF’s default reverse functionality will be appropriate.

inv DerivationWithOppositeHasOppositeDerivation:
hasDerivation and eOpposite <> null implies eOpposite.hasDerivation

We therefore want to diagnose that a derivation that redefines the forward semantic of opposite also redefines the corresponding reverse semantics.

DerivationIsUninitialized

An initial value for a property may be specified as a simple default value or as a derived expression.

inv DerivationIsUninitialized:
hasDerivation implies defaultValue.oclIsUndefined()

We want to diagnose the occlusion of the derived expression by a default value.

DerivationDoesNotResolveProxies

Derived expressions are not references.

inv DerivationDoesNotResolveProxies:
hasDerivation implies not resolveProxies

We can therefore diagnose whether the EMF proxy resolution logic is not suppressed.

Validating Ecore with additional Complete OCL

In the previous section we described additional Complete OCL validation constraints to detect problems with inadequate Sample Ecore diagnosis of derived properties. We will now apply those constraints to a test file.

Select EcoreTestFile.ecore and use the right button menu to Open With->Sample Ecore Model Editor. This is probably the default for double-clicking with the left button, but if you open with the OCLinEcore editor the required validation will not work (in Juno).

Now right click within the Sample Ecore Editor pane as described in OCL->Load Document Menu Action and load ExtraEcoreValidation.ocl. An additional Resource is shown in the editor tree.

Select a model element such as the Bad package and use the right button menu to invoke Validate.

This shows an error. Depending on the order in which the constraints are evaluated, you may also see one or two warnings. You should use the Validity View to see all failures.

If we now open EcoreTestFile.ecore with the OCLinEcore editor we can see that the transient and volatile keywords are indeed missing.

Editing the Complete OCL

You may edit the Complete OCL to experiment with alternate constraints or messages.

However the Complete OCL complements the meta-model and EMF does not support live modification of meta-models. It is therefore necessary to restart the Sample Ecore Editor and Reload the modified Complete OCL document in order to exploit the changes.

A solution for this may occur in a future release.

Example Complete OCL complements for UML

The extension of the Sample Ecore Editor validation described in Validating Ecore with additional Complete OCL is applicable to any tree editor generated by EMF tooling.

The ExtraUMLValidation.ocl file provides a very simple style check that class names start with an upper case letter.

The UML meta-model is imported and an invariant is specified for the Class classifier which is fully qualified to avoid the need for a surrounding package context declaration.

You may open the PapyrusTestFile.uml with the UML Model Editor, load the ExtraUMLValidation.ocl, select the Model and then Validate in the same way as for the Ecore example.

Unfortunately the Papyrus UML editor does not use the EValidator framework and so loading Complete OCL documents into Papyrus fails to enhance validation capabilities. To use additional Complete OCL functionality, you may load and validate in the UML Model Editor, then start the Papyrus editor which will then show the problem markers on diagram elements. Alternatively you may use Validity View concurrently with Papyrus.

Example Complete OCL complements for Xtext

Xtext editors use EValidator and so a Complete OCL document may be loaded into an Xtext editor, including Xtext itself, to provide enhanced validation.

The ExtraXtextValidation.ocl file provides some demonstration style checks.

The Xtext root package is imported and within the package declaration context for the xtext package, invariants are supplied for four classes. These are all just examples of how constraints may use the Xtext model. It is not suggested that users should use all of these constraints for real grammars.

NoAnonymousImports

context ReferencedMetamodel
inv NoAnonymousImports: alias <> null

This invariant diagnoses whether any import statements omit the as xxxx model name.

NoActions

context Action
inv NoActions : false

This invariant diagnoses whenever an {xxx} action statement is used.

CamelCaseName

context ParserRule
inv CamelCaseName : name.matches('[A-Z][A-Za-z]*')

This invariant verifies that the name of a parser rule starts with an upper case letter and uses only letters.

UpperName

context xtext::TerminalRule
inv UpperName : name = name.toUpperCase()

This invariant verifies that the name of a terminal rule is uppercase.

You may open the XtextTestFile.xtext with the Xtext Editor, load the ExtraXtextValidation.ocl and then Validate in the same way as the Ecore example.

The additional validations appear as warning markers in the editor.

Unfortunately Xtext does not have a nice toString() method for its Concrete Syntax tree so the descriptions of erroneous elements are a little inelegant.

You may edit the Xtext test file to delete the “as ecore” in the import statement and see that the additional Complete OCL constraints are contributing to the ongoing functionality of the editor.

Complete OCL Editor

The Complete OCL editor is invoked automatically for an existing or new *.ocl file. You can create an empty file using either New->File or a partial content file using New->Other... followed by OCL and Complete OCL File. The editor is Xtext-based and so has most of the facilities that you find in many other Eclipse editors.

Royal and Loyal Example

The Royal and Loyal Example was first provided by Jos Warmer and Anneke Kleppe in The Object Constraint Language: Getting Your Models Ready for MDA and has subsequently been used in many tutorials. The example provides substantial examples of Complete OCL and Essential OCL. The models are available by invoking New->Example...->OCL (Object Constraint Language) Plugins.

Summary

To illustrate how to work with Complete OCL we have

  • Examined the Complete OCL language

  • Examined constraints to rectify inadequate Ecore validation of derived features

  • Loaded Complete OCL constraints to enhance validation of an Ecore model

  • Loaded Complete OCL constraints to enhance validation of a UML model

  • Loaded Complete OCL constraints to enhance validation of an Xtext grammar