1
Introduction to OCL
Fernando Brito e Abreu (fba@di.fct.unl.pt) Universidade Nova de Lisboa (http://www.unl.pt)
QUASAR Research Group (http://ctp.di.fct.unl.pt/QUASAR)
Introduction to OCL Fernando Brito e Abreu (fba@di.fct.unl.pt) - - PDF document
Introduction to OCL Fernando Brito e Abreu (fba@di.fct.unl.pt) Universidade Nova de Lisboa (http://www.unl.pt) QUASAR Research Group (http://ctp.di.fct.unl.pt/QUASAR) Abstract Why formalization? Formalization in OO OCL types and
QUASAR Research Group (http://ctp.di.fct.unl.pt/QUASAR)
Graphical elements of the diagrammatic
easy to understand how they fit together ;)
Modeling details, such as uniqueness and
often they cannot be conveyed graphically examples: Christian marriage, who‟s the boss, ...
boss 0..1
Employee
name : string
front_car 1 waggons 0..1 * loco 1 Train Waggon Locomotive Car
train_id : integer waggon_id : integer number_places : integer horse_power : integer
Accuracy and unambiguity in specification is the
Several attempts have been made to combine
Extending
Ex: Z++, Object-Z, VDM++
This approach is not in line with industrial practice
Most practitioners
Z is a specification language developed by the
Programming Research Group at Oxford University
"Understanding Z", J.M.Spivey, Cambridge U Press, 1988
Z is used for describing and modeling computing systems
It is based on axiomatic set theory and first order predicate logic Z is written using many non-ASCII symbols
Z++ is an object-oriented extension of Z
"Z++, an Object-Oriented Extension to Z", Lano, Z User Workshop,
Oxford 1990, Springer Workshops in Computing, 1991, pp.151-172
Object Z is another object-oriented extension of Z
developed at University of Queensland, Australia
"Object Orientation in Z", S. Stepney et al eds, Springer 1992
Complementing
Ex: Syntropy (subset of Z combined with OMT), ROOA
(A. Moreira), Metamorphosis (J. Araújo)
Compromise
Drawback1: conceptual gap between formalisms Drawback2: same as in previous approach
Use of a constraint language to express design by
Ex: BON (Business Object Notation) object-oriented
method (Waldén 95).
Has a full-fledged textual assertion mechanism, allowing to
specify system structure and semantics (constraints, invariants, properties of expected results) Bridges
the semantic gap but failed widespread acceptance (too tied to Eiffel language world)
Acceptance often comes from standardization ...
The last and more promising road is OCL Allows
Therefore
Is a part of the UML standard published by the
Used
Can the grandpa inherit from the grandson?
It is a formal, yet simple notation, to be used jointly
Its syntax has some similarities to those of some
It is underpinned by mathematical set theory and
However it was designed for usability and is easily
OCL brings the best of the previous
simplicity and powerfulness of graphical
preciseness and non-ambiguity granted by
Moreover, since it is a part of UML, it has
also de facto because there is an increasing number
OCL is strongly type checked Style convention is Camel Case starting with:
Lower case letter: objects, attributes, operations Upper case letter: classes
Dot notation is used for:
Attribute access Operation access Association end access (navigation in diagram)
Person, Date
boy, girl
boy.name girl.birthday
boy.marries(girl), girl.age()
Note: parameterless operations can be written with or without parenthesis
Person.allInstances
boy.spouse.name
Consider the object:
bill: Customer
Attribute access
bill.name
Operation access
bill.age()
Navigation through associations
bill.cards bill.cards.color
Invariants are constraints that represent
Their context is, therefore, a class Context can be represented differently:
Example:
OMG standard USE tool
Customer inv CustomerAge: age() >= 18 context Customer inv CustomerAge: age() >= 18
PRE-CONDITION POST-CONDITION CLIENT Obligation Right SUPPLIER Right Obligation
Pre-conditions are constraints that must be true
In the design by contract paradigm, they represent the
rights of the object that offers the service or, if you want, the client responsibilities.
Post-conditions are constraints that must be true
They represent the obligations to be fulfilled by the object
that offers the service, or, if you want, the client rights.
The context of both pre and post-conditions is,
This is a scope indicator
OclAny Enumeration Collection Real Integer Sequence Bag Set String Boolean
OclAny is the superclass of all classes in OCL (even user defined ones)
OclAny is the supertype of all model types Features on OclAny are available on each
To avoid name conflicts between features in
(note: object is the instance of OclAny)
(note: object is the instance of OclAny)
All types defined in an UML model, or pre-
That type is an instance of the OclType
Access to OclType allows the modeler to
(note: type is the instance of OclType)
type.name : String The name of type type.attributes : Set(String) The set of names of the attributes of type, as they are defined in the model type.associationEnds : Set(String) The set of names of the navigable associationEnds of type, as they are defined in the model type.operations : Set(String) The set of names of the operations of type, as they are defined in the model type.supertypes : Set(OclType) The set of all direct supertypes of type. post: type.allSupertypes->includesAll(result) type.allSupertypes : Set(OclType) The transitive closure of the set of all supertypes of type type.allInstances : Set(type) The set of all instances of type and all its subtypes Example: Customer.allInstances Transaction.allInstances
(note: object is the instance of OclAny)
Type Operations Boolean =, not, and, or, xor, implies, if-then-else Real =, +, -, *, /, abs, floor, max, min, <, >, <=, >= Integer =, +, -, *, /, abs, div, mod, max, min, <, >, <=, >= String =, size, toLower, toUpper, concat, substring
Notes
Duplicates Order Set No No Bag Yes No Sequence Yes Yes
Collection
size() : Integer includes(object : OclAny) : Boolean count(object : OclAny) : Integer includesAll(c2 : Collection(T)) : Boolean isEmpty() : Boolean notEmpty() : Boolean sum() : Real exists(expr : OclExpression) : Boolean forAll(expr : OclExpression) : Boolean iterate(expr : OclExpression) : OclType
Sequence Bag Set Collection
Set
union(set2 : Set(T)) : Set (T) union(bag1 : Bag(T)) : Bag (T) =(set2 : Set(T)) : Boolean intersection(set2 : Set(T)) : Set (T) intersection(bag1 : Bag(T)) : Bag (T)
including(object : T) : Set (T) excluding(object : T) : Set (T) symmetricDifference(set2 : Set(T)) : Set (T) select(expr : OclExpression) : Set (T) reject(expr : OclExpression) : Set (T) collect(expr : OclExpression) : Set (expr.evaluationType()) count(object : T) : Integer asSequence() : Sequence (T) asBag() : Bag (T)
Bag
=(bag2 : Bag(T)) : Boolean union(bag2 : Bag(T)) : Bag (T) union(set1 : Set(T)) : Bag (T) intersection(bag2 : Bag(T)) : Bag (T) intersection(set1 : Set(T)) : Set (T) including(object : T) : Bag (T) excluding(object : T) : Bag (T) select(expr : OclExpression) : Bag (T) reject(expr : OclExpression) : Bag (T) collect(expr : OclExpression) : Bag (expr.evaluationType[)) count(object : T) : Integer asSequence() : Sequence (T) asSet() : Set (T)
Sequence
count(object : T) : Integer =(sequence2 : Sequence(T)) : Boolean union(sequence2 : Sequence(T)) : Sequence (T) append(object : T) : Sequence (T) prepend(object : T) : Sequence (T) subSequence(lower : Integer, upper : Integer) : Sequence (T) at(at : Integer) : T first() : T last() : T including(object : T) : Sequence (T) excluding(object : T) : Sequence (T) select(expr : OclExpression) : Sequence (T) reject(expr : OclExpression) : Sequence (T) collect(expr : OclExpression) : Sequence (expr.evaluationType[)) iterate(expr : OclExpression) : OclType asBag() : Bag (T) asSet() : Set (T)
“@pre” is a timing tag (state at preconditions evaluation) “->” is used to apply an
Customer (H1) Customer.allInstances->forAll(c1, c2: Customer | c1 <> c2 implies c1.client_id <> c2.client_id) (H2) Customer.allInstances->count(client_id = self.client_id)=1 (H3) Customer.allInstances->isUnique(client_id) Which is the least efficient implementation?
Customer
client_id : Integer name : String title : String isMale : Boolean dateOfBirth : Date age()
OCL expressions can be built by navigating
By definition, the result of navigating
The result of navigating through more than
Exception: if the association is adorned with
Customer not self.related_with->includes(self)
+related_with 0..* Customer
client_id : Integer name : String title : String isMale : Boolean dateOfBirth : Date age()
Loyalty program management system Customers must become members to get an
Customers make earning and burning
Transactions are associated with a given card Program partners offer services of a given level Adapted example from [Warmer & Kleppe 1999]
Burning Earning Membership LoyaltyAccount
0..1
1
0..1
1 ProgramPartner ServiceLevel 1 0..*
+actualLevel
1 0..* Transaction
0..*
1
+transactions 0..*
1 Service
0..*
1
+deliveredServices 0..*
1 0..* 1
+availableServices
0..* 1 0..* 1 +transactions 0..* 1 LoyaltyProgram
1..*
1..*
+partners 1..*
1..*
1..*
1
1..* {ordered}
1 CustomerCard 1 1 +card 1 1 0..* 1 +transactions 0..*
+card
1 Customer 0..* 0..* +program 0..* 0..* 1
0..* +owner
1
+cards 0..*
0..* 0..*
+related_with
Rule 0 - Class names start with an uppercase
Rule 1 - While navigating from a class to
Rule 2 - While navigating from a class to
Enumeration values are prefixed with “ #”
color = #silver or color = #gold
actualLevel.name = 'Silver' implies card.color = #silver and card.color = #silver implies actualLevel.name = 'Silver' and actualLevel.name = 'Gold' implies card.color = #gold and card.color = #gold implies actualLevel.Name = 'Gold'
The partners of a given program cannot burn
partners.deliveredServices.transactions-> select (oclType = Burning)->collect(points)->sum < 10000
partners.deliveredServices.transactions.points->sum < 10000
The partners of a given program cannot burn
partners->forAll(p: Partner | p.deliveredServices.transactions-> select (oclType = Burning)->collect(points)->sum < 10000) partners->forAll(deliveredServices.transactions-> select (oclType = Burning)->collect(points)->sum < 10000)
Example: there is one service level whose
self.serviceLevel->exists( s: ServiceLevel | s.name = 'basic' )
serviceLevel->exists( s | s.name = 'basic' )
serviceLevel->exists( name = 'basic' )
Date::isBefore(t:Date): Boolean = if self.year = t.year then if self.month = t.month then self.day < t.day else self.month < t.month endif else self.year < t.year endif
Date
day : Integer month : Integer year : Integer now : Date isBefore(t : Date) : Boolean isAfter(t : Date) : Boolean isEqual(t : Date) : Boolean yearsSince(t : Date) : Integer today() : Date yearsTo(t : Date) : Integer
Customer.age() ? Customer.age():Integer =
(H1) dateOfBirth.today().yearsSince( dateOfBirth ) (H2) dateOfBirth.yearsTo( dateOfBirth.today() )
Date
day : Integer month : Integer year : Integer now : Date isBefore(t : Date) : Boolean isAfter(t : Date) : Boolean isEqual(t : Date) : Boolean yearsSince(t : Date) : Integer today() : Date yearsTo(t : Date) : Integer
Customer
client_id : Integer name : String title : String isMale : Boolean dateOfBirth : Date age()
The initial date of the card
CustomerCard inv CardValidity: (H1) validFrom.isBefore(goodThru) (H2) goodThru.isAfter(validFrom)
Date
day : Integer month : Integer year : Integer now : Date isBefore(t : Date) : Boolean isAfter(t : Date) : Boolean isEqual(t : Date) : Boolean yearsSince(t : Date) : Integer today() : Date yearsTo(t : Date) : Integer
The name printed in the card is a concatenation of
The number of valid cards for every
A customer cannot hold more than one valid
Senior customers (above 65 years old) earn bonuses
Earning let seniorBonus: Real = 0.15, oldAge: Integer = 65 in card.owner.age() > oldAge implies points = (service.pointsEarned * (1+seniorBonus)).floor Note: multiple variable definition is included in the OCL2 standard, but in the USE tool only one variable is supported
Write the predicate Alarm that allows detecting
Example: Valid cards are "gold" for holders that
color = if membership.program.customer.cards ->select(owner = self.owner) -> exists(goodThru.isBefore(self.validFrom) and transactions.points->sum >= 15000) or owner.cards -> select (goodThru.isBefore(self.validFrom)) -> forAll (transactions.points -> sum > 5000) then #gold else #silver endif
In some circumstances it is desirable to use a
Since the property is not defined on the current known
type, this results in a type conformance error
When it is certain that the actual type of the object
This operation results in the same object, but the known
type is the argument OclType
An object can only be re-typed to one of its subtypes If the actual type of the object is not equal to the type to
which it is re-typed, the expression is undefined
Example:
Graphic Editors
System X Diagrams System Z Diagrams System Y Diagrams
Modeling Tools
Tool Repository
OCL Expressions Evaluator
UML Model Workload (Model Objects) OCL Expressions (Model Constraints) Expression Results
Workload Generator
UML Model
The model is stored in textual format Model includes the definition of
Classes (with their attributes and operations) Association classes (idem, plus association info) Associations, aggregations and/or compositions Invariants (at the class level) Pre and post conditions (at the operation level)
model Company class Employee attributes name: String salary: Integer
getName(): String end … … class Department attributes budget: Integer end class Project attributes budget: Integer end …
association WorksIn between Employee[ 1..* ] role employee Department[ 1 ] role place end association WorksOn between Employee[ 1..* ] role colaborators Project[ 1..* ] role project end association Controls between Department[ 1] role place Project[ 1..* ] role project end
constraints context Department
inv MoreEmployeesThanProjects: self.employee->size >= self.project->size
… context Employee
inv MoreProjectsHigherSalary: Employee.allInstances->forAll(e1, e2 | e1.project->size > e2.project->size implies e1.salary > e2.salary)
… context Project
inv BudgetWithinDepartmentBudget: self.budget <= self.department.budget
inv EmployeesInControllingDepartment: self.department.employee->includesAll(self.employee)
Models can be instantiated:
interactively, or through a batch facility (command language)
open [-q] FILE
The FILE extension here is “use” (the model file) “-q” is for quiet reading info model
info class NAME
read FILE
readq FILE
The FILE extension here is “cmd” info state
The system state is given by its objects and links
info vars
reset
This means keeping the model but deleting the objects
and links
! CMD
Executes state manipulation command
: EXPR
use> : Set{2004,2005,2006,2007}->select(e | e > 2005) -> Set(Integer)
? EXPR
use> ? Set{2004,2005,2006,2007}->select(e | e > 2005) -> Set{2006,2007} : Set(Integer)
?? EXPR Compiles and evaluates EXPR (verbose)
use> ? Set{2004,2005,2006,2007}->select(e | e > 2005) -- see the verbosity for yourself
!create <id-list> : <class> [between (<id-list>)]
Creates objects (class instances) If <class> is an association class, then the link ends
must be given after 'between'
!destroy <id-list>
Destroys objects; id-list may be a collection
!set <obj-id>.<attr-id> := <expr>
Set attribute value of object
!let <id> [ : <type> ] = <expr>
allows to bind new variables
!insert (<id-list>) into <assoc>
Creates a link (association instance); the id-list must
conform to the association definition
!delete (<id-list>) from <assoc>
Deletes a link among identified objects from the named
association
!insert (john,cs) into WorksIn !insert (frank,cs) into WorksIn !create research : Project !set research.name := 'Research„ !set research.budget := 12000 !create teaching : Project !set teaching.name := 'Validating UML„ !set teaching.budget := 3000 !insert (cs,research) into Controls !insert (cs,teaching) into Controls !insert (frank,research) into WorksOn !insert (frank,teaching) into WorksOn !insert (john,research) into WorksOn
check [-v] [-d] [ -a | inv-list ]
Verbose output of subexpression results for failing invariants
Show which instances cause and invariant to fail.
Check all invariants (including the loaded ones from the generator)
inv-list Check only given invariants (space separated)
Signature of an invariant is <context>::<invName>
context CustomerCard inv CardValidity1: validFrom.isBefore(goodThru) inv CardValidity2: goodThru.isAfter(validFrom)
use> check CustomerCard::CardValidity1
Implicit flattening is only done when used with the shorthand notation for collect. For instance: company.branches.employees
results in a Bag(Employee)
company.branches->collect(c | c.employees)
results in a Bag(Set(Employee))
This result can be flattened into a Bag(Employee) by explicit flattening the collection with the `flatten' operation added in USE: company.branches->collect(c | c.employees)->flatten
Collection types can be nested to any level, e.g.,
All types include an undefined value. For example, the expression 1/0 results in the value Undefined of type Integer Checking for an undefined value can be done with the new
These are defined for all types (that is, in OclAny) e.g.: (1/0).isUndefined() results in "true"
An undefined value may be explicitly specified with the new
gen unload [invnames]
Unloads added class invariants
gen loaded
Prints loaded class invariants
gen flags [invnames] [+d|-d] [+n|-n]
Switch invariant evaluation flags
gen start [options] FILE PROCNAME([params])
Search valid system state
gen result Prints results of last generator search gen result inv Prints statistics of last generator search gen result accept Accept result of last generator search
A model can be animated to validate the
System states (snapshots of a running system)
For each snapshot the OCL constraints are
automatically checked
Information about a system state is given by graphical
views
OCL expressions can be entered and evaluated to
query detailed information about a system state
Feature IBM Parser Dresden Toolkit TU Munich Tool ModelRun (… Rose) Bremen USE Syntactical analysis
Type checking
Logical consistency checking Dynamic invariant validation
Dynamic pre / post condition validation
Test automation
Code verification and synthesis
Version Date Submitters / Supporters
1.1 (36 p.) Sep 1997 Rational, Microsoft, Hewlett
Software, MCI Systemhouse, Unisys, ICON Computing, IntelliCorp, i
Platinum Technology, Ptech, Taskon, Reich Technolog ies, Softeam 1.2 … … 1.3 June 1999 … 1.4 … … 2.0 (214 p.) Jan 2003 Submitters: Boldsoft, Rational, IONA, Adaptive Ltd. Supporters : Klasse Objecten, Borland, Kings College, University of Bremen, Dresden University of Technology, Kabira Technologies, IBM, Telelogic, University of Kent, Project Technology, University of York, Compuware, Syntropy Ltd., Oracle, Softeam
Its grammar has been extended, but keeps its
The OCL grammar (its concepts and semantics)
This metamodel defines and acts as an abstract
syntax for the language
Alternative concrete syntaxes (e.g. Java-like syntax
OCL 1.* is side-effect free (only selectors allowed)
Selectors are query operations which return a value but do not
change the object state (their label isQuery = true)
OCL 2.* allows expressing messages sent by
components, classes or other constructs that may have behavior (using the OclMessage concept)
This allows the specification of behavioral constraints
UML 1.4 predefined types and operations are defined as
the OCL 2.0 Standard Library.