Interactive OCL Tutorial
Introduction
This in an interactive tutorial on OCL, the Object Constraint Language. You may test your own OCL expressions with the Simple OCL Web Tester .
This tutorial is based on UML 2.0 OCL Specification (in particular see chapter 7)
Please note that there may be a displaying problem with Microsoft explorer when executing the interactive OCL Web Tester since there is a problem representing apostrophes.
OCL primitive types
OCL has four basic primitive datatypes
- Boolean (true, false)
- Integer (1, -5, 2, 34, 26524, ...)
- Real (with the values 1.5, 3.14, ...)
- String (`To be or not to be...`)
Furthermore, OCL has the following comparators: , =, =>, =
Operations on primitive types
- Integer has the operations: *, +, -, /, div(), abs(), mod(), max(), min(), sum(), sin(), cos()
- Real has the operations: *, +, -, /, floor(), sum(), sin(), cos()
- Boolean has the operations: and, or, xor, not, implies, if-then-else
- String has the operations: concat(), size(), substring(), toInteger() and toReal()
Differences between OCL and ATL
- In ATL you can use the operator + for the concatenation of Strings
- Early versions of ATL use div instead of / or div() for division
Examples of operation on primitive datatypes
- Addition of two integers: 1 + 1 (iframe)
- Further mathematical operations: 1 - 80 div 2 (iframe)
- Comparisons of integers: 1 (iframe) and 1 > 2 (iframe)
- Boolean operations: true or false (iframe)
Let expressions
- The let command to define variables: let a : Integer = 1 in a + 1 (iframe)
- Enchaining let expressions:let a : Integer = 1 in let b : Integer = 2 in a + b (iframe)
OCL collections
Collection is the abstract superclass of Set, OrderedSet, Bag and Sequence.
- Set is a collection without duplicates. Set has no order.
- OrderedSet is a collection without duplicates. OrderedSet has an order.
- Bag is a collection in which duplicates are allowed. Bag has no order.
- Sequence is a collection in which duplicates are allowed. Sequence has an order.
Collection operations
- The number of elements in the collection self: size()
- The information of whether an object is part of a collection: includes()
- The information of whether an object isn't part of a collection: excludes()
- The number of times that object occurs in the collection self. count()
- The information of whether all objects of a given collection are part of a specific collection: includesAll()
- The information of whether none of the objects of a given collection are part of a specific collection: excludesAll()
- The information if a collection is empty: isEmpty()
- The information if a collection is not empty: notEmpty()
Iterators over collections
- The selection of a sub-collection: select()
- When specifying a collection which is derived from some other collection, but which contains different objects from the original collection (i.e., it is not a sub-collection) use: collect()
- The information of whether an expression is true for all objects of a given collection: forAll()
- The addition of all elements of a collection: sum() Elements must be of a type supporting the + operation.
OCL collection operation examples
- Specifying a sequence literal: Sequence {1, 2, 3} (iframe)
- Is a collection empty?: Sequence {1, 2, 3}->isEmpty() (iframe)
- Getting the size of a collection: Sequence {1, 2, 3}->size() (iframe)
- Please compare: Sequence {3, 3, 3 }->size() returns 3 (iframe) while Set {3, 3, 3 }->size() returns 1 (iframe)
- Nesting sequences: Sequence { Sequence { 2, 3}, Sequence {1, 2, 3}} (iframe)
- Getting the first element of a sequence: Sequence {1, 2, 3}->first() (iframe)
- Getting the last element of a sequence: Sequence {1, 2, 3}->last() (iframe)
- Selecting all elements of a sequence that are smaller than 3: Sequence {1, 2, 3, 4, 5, 6}->select( i | i (iframe)
- Rejecting all elements of a sequence that are smaller than 3:Sequence {1, 2, 3, 4, 5, 6}->reject( i | i (iframe)
- Collect the names of all MOF classes: MOF!Class.allInstances()->collect(e|e.name). The OCL shorthand expression "MOF!Class.allInstances()->collect(name)" means the same but is not yet implemented in ATL. (iframe)
- Are all numbers in the sequence greater than 2?: Sequence{ 12, 13, 12}->forAll( i | i>2 ) (iframe)
- Exists a number in the sequence that is greater than 2?: Sequence{ 12, 13, 12}->exists( i | i>2 ) (iframe)
- Concatenating Sequences: Sequence {1, 2, 3}->union(Sequence {4, 5, 6}) (iframe)
OCL conditional expression: "if"
You can formulate an if-clause in OCL: if-then-else-endif. Else cannot be dropped.
- If three is greater than two return
else return : if 3 > 2 then `three is greater than two` else `oh` endif (iframe)
OCL classes
In ATL the notation "Metamodel!Class" is used to be able to differentiate classes of different metamodels. This means in ATL it is possible to use several metamodels in the same file. In OCL this is not the case. There are different operations to treat and analyze classes.
- The operation oclIsTypeOf() checks if a given instance is an instance of a certain type (and not of one of its subtypes or of other types).
- The operation oclIsKindOf() checks if a given instance is an instance of a certain type or of one of its subtypes.
- The operation allInstances() returns you all instances of a given Type.
- The operation oclIsUndefined() tests if the value of an expression is undefined (e.g. if an attribute with the multiciplicity zero to one is void or not. Please note: attributes with the multiplicity n are often represented with collections, which may be empty and not void).
Examples on OCL class operations
- Please compare MOF!Attribute.oclIsKindOf(MOF!ModelElement) (iframe) is true while MOF!Attribute.oclIsTypeOf(MOF!ModelElement) (iframe) is false
- Collect the names of all MOF classes: MOF!Class.allInstances()->collect(e|e.name) (iframe)
OCL queries on MOF 1.4
The following examples are based on the metamodel MOF 1.4 which you may use to test OCL expressions with. You may also have a look at the MOF XMI file or at the Java JMI implementation (JMI overview with frames) to learn about MOF. Start with MofClass.
- Count the number of classes in MOF: MOF!Class.allInstances()->size() (iframe)
- Getting the names of all primitive MOF types by filtering: MOF!DataType.allInstances()->select(e|e.oclIsTypeOf(MOF!PrimitiveType))->collect(e|e.name) (iframe)
- Getting the names of all primitive MOF types the simple way:MOF!PrimitiveType.allInstances()->collect(e|e.name) (iframe)
- An enumeration instance in MOF: MOF!VisibilityKind.labels (iframe)
- Getting all (local and inherited) StructuralFeatures of a Class. In the following code example the names of all StructuralFeatures of the class PrimitiveTypes are displayed: MOF!PrimitiveType.findElementsByTypeExtended(MOF!StructuralFeature, true)->collect(e | e.name) (iframe)
- Getting the names of all classes inheriting from more than one class: MOF!Class.allInstances()->select(e | e.supertypes->size() > 1)->collect(e | e.name) (iframe)
- Continue testing, try to understand MOF and find out what these expressions mean:
- MOF!Attribute.contents->select(e | e.oclIsKindOf(MOF!Attribute)) (iframe)
- MOF!Attribute.oclIsKindOf(MOF!Class) (iframe)
- MOF!Class.allInstances()->collect(e | e.oclIsKindOf(MOF!Class)) (iframe)
- MOF!Attribute.allInstances()->collect(e | e.oclIsKindOf(MOF!Class)) (iframe)
- MOF!Attribute.allInstances()->collect(e | e.oclIsKindOf(MOF!Attribute)) (iframe)
- MOF!Attribute.allInstances()->collect(e | e.oclIsKindOf(MOF!StructuralFeature)) (iframe)
- 1.oclIsKindOf(Integer) (iframe)
- MOF!Long.oclIsKindOf(MOF!PrimitiveType) (iframe)
- MOF!Class.allInstances()->collect(e | e.name + ` extends ` + e.supertypes->iterate(e; acc : String = `` | acc + if acc = `` then `` else ` and ` endif + e.name)) (iframe)
OCL comments
OCL comments start with two consecutive hyphens "--" and end at the end of the line.
