02291: System Integration Design By Contract and OCL Hubert Baumeister huba@dtu.dk DTU Compute Technical University of Denmark Spring 2019
What does this function do? Implementation public List<Integer> f(List<Integer> vector) { if (vector.size() <= 1) return vector; int k = vector.elementAt(0); List<Integer> less = new List<Integer>(); List<Integer> equal = new List<Integer>(); List<Integer> bigger = new List<Integer>(); g(k,vector,less,equal,bigger); List<Integer> r = f(less); r.addAll(equal); r.addAll(f(bigger)); return r; } public void g(int k, List<Integer> vector, List<Integer> less, List<Integer> equal, List<Integer> bigger) { for (int i : vector) { if (i < k) less.add(i); if (i == k) equal.add(i); if (i > k) bigger.add(i); } }
Contract for the sort function in OCL Specification (Contract) in OCL context C::sort(a : Sequence(Integer)) : Sequence(Integer) pre: a <> null post: isSorted(result) and sameElements(a,result) def: isSorted(result) = Sequence {1..a.length}->forAll(i | Sequence {1..a.length}->forAll( j | i < j implies a->at(i) <= a->at(j)) def: sameElements(a1, a2 : Sequence(Integer)) = a1->forAll( i | a1->count(i) = a2->count(i)) and a2->forAll( i | a1->count(i) = a2->count(i))
Contracts {The field i should always be greater than 0.} Counter {The operation dec should be called only if i is greater than i : int zero. In this case i is decremented by one.} inc() : void dec() : void {The inc operation increases i by one.} public T n(T1 a1, .., Tn an, Counter c) ... c.dec(); ... Contract for dec ◮ Method n ensures pre-condition c . i > 0 before calling c.dec() ◮ Method dec ensures counter is decremented , only when c . i > 0 → Undefined what happens when c . i < = 0
Example {The field i should always be greater than 0.} Counter {The operation dec should be called only if i is greater than i : int zero. In this case i is decremented by one.} inc() : void dec() : void {The inc operation increases i by one.}
Example {The field i should always be greater than 0.} Counter {The operation dec should be called only if i is greater than i : int zero. In this case i is decremented by one.} inc() : void dec() : void {The inc operation increases i by one.} Counter {context Counter inv: i >= 0} {context Counter :: dec ( ) i : int pre: i > 0 post: i = i@pre - 1 } inc() : void dec() : void {context Counter :: inc ( ) post: i = i@pre + 1}
Object Constraint Language (OCL) Express constraints in UML diagrams in a formal way 1 Invariants of UML diagrams 2 The contract of operations (i.e. pre- and postconditions of operations) 3 body of query operations ( {query} ; don’t change the state) query operations can be used in OCL constraints, but not state changing operations
Bank example with constraints {context Bank Bank inv: accounts->forAll(a | a.owner = self) 1 owner accounts 0..* Account bal : int {inv: bal >= 0} update(n : int) : void {pre: bal + n >= 0 post: bal = bal@pre + n and 1 history.oclIsNew() and history.bal = bal@pre and history.prev = history@pre} 0..1 0..1 History bal : int prev History() : void 1
Update operation of Account State before executing update(n) { n + b > = 0 } a: Account bal = b h: History bal = m
Update operation of Account State before executing State after executing update(n) update(n) a: Account { n + b > = 0 } bal = b + n a: Account bal = b h1: History bal = b prev h: History h: History bal = m bal = m
OCL Syntax ◮ More on OCL operators and OCL ◮ Online on Safari books: ”Object Constraint Language” by Jos Warmer, Anneke Kleppe (cf. course home page)
OCL expressions and their evaluation ◮ OCL expression evaluated in a context . ◮ Class, Operation, Association, ... ◮ Expression cannot change the state of the system → can’t call state changing operations (basically no method calls are allowed) → Exception: calls to methods marked {query} are allowed → No assignment operator ( = means equality)
Type of constraints The type of the constraint ◮ Most common ◮ Invariant for classes ( inv: ) ◮ precondition for operations ( pre: ) ◮ postcondition for operations ( post: ) ◮ Others ◮ body: exp ◮ def: name(parameter:type) : type = expr Ex. def: initial : String = name.substring(1,1) Ex. def: getTotalPoints(d:Date) : Integer = OCL expression
Notation ◮ Within notes in {} Counter {inv: i >= 0} {pre: i > 0 i : int post: i = i@pre -1} inc {post: i = i@pre + 1} dec ◮ As separate text. ◮ In this case the context part must be present context Counter :: inc context Counter post: i = i@pre + 1 inv: i >= 0
OCL Syntax (simplified): Available types ◮ Basic datatypes: Integer, Real, Boolean, String ◮ Boolean operators: = , <> , not, and, or, implies, . . . , x . isOCLTypeOf ( C ) ◮ All classes C from the UML model ◮ Collection types: Set(C), OrderedSet(C), Bag(C), Sequence(C)
OCL Syntax (simplified): Basic operations A B a b y:int x:int m() ◮ Attribute / Navigation (in the context of class A) ◮ self ◮ self . b . x ◮ Operation Calls ◮ self . m ( c 1 , · · · , c n ) (Method call) ◮ self . b → cop ( . . . ) (Call to a method on collections) context A inv: self.b.x->includes(3)
Navigation Navigation via dot (.) notation to roles and attributes A B a b y:int x:int a1:A b1:B { y = 1 0 } { x = 5 } a1.b = a1.b.x =
Navigation Navigation via dot (.) notation to roles and attributes A B a b y:int x:int b1:B {x = 3} a1:A {y = 10} b2:B {x = 5} a1.b = a1.b.x =
OCL Syntax (simplified): OCL Boolean Operators and Collections ◮ Boolean operators ◮ Equal ( = ), Not-Equal ( <> ) ◮ not, and, or, implies, . . . ◮ x . isOCLTypeOf ( C ) is true if x is an object of type C or a subtype thereof ◮ Collections ◮ Collection(C): Abstract supertype ◮ Set(C) (not ordered, no duplicates) ◮ OrderedSet(C) (ordered, no duplicates) ◮ Bag(C) (not ordered, allowes duplicates) ◮ Sequence(C) (ordered, allowes duplicates)
OCL Syntax (simplified): Operations on collections I ◮ collection → forAll ( x | P [ x ]) corresponds to ∀ x ∈ collection : P [ x ] ◮ collection → exists ( x | P [ x ]) corresponds to ∃ x ∈ collection : P [ x ] ◮ collection → select ( x | P [ x ]) corresponds to { x ∈ collection | P [ x ] } ◮ collection → collect ( x | E [ x ]) corresponds to { E [ x ] | x ∈ collection } ◮ self . employee → collect ( birthday ) = self . employee . birthday P [ x ] and E [ x ] means that x occures in predicate P and expression E
OCL Syntax (simplified): Operations on collections II ◮ Sequence { 1 , 2 , 3 }→ includes ( 3 ) = true ◮ more: includesAll(collection), excludes, isEmpty, union, intersection, count . . . ◮ compare with ◮ Sequence { 1 , 2 , 3 }→ including ( 5 ) = Sequence { 1, 2, 3, 5 } ◮ Conversions between collections: asSet, asBag, asSequence, . . . ◮ C . allInstances () ◮ sequence → at ( i ) ( s → at ( 1 ) is the first element)
Flattening Collections Federation Club Person member 1 * * * f.club.member = f.club->collect(member) = f.club->collectNested(member) =
OCL Syntax (simplified): Postconditions ◮ Additionally in postconditions: ◮ result ◮ x @ pre , x . bal @ pre ◮ x . oclIsNew () ◮ x ˆ m () ◮ ”Message m was send to x” ◮ e.g. observer ˆ update
Observer Pattern «Interface» Observable Observer changed : bool update(Observable o, Object arg) addObserver(Observer o) * hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg)
Observer Pattern «Interface» Observable Observer changed : bool update(Observable o, Object arg) addObserver(Observer o) * hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) context Observable::setChanged() post: changed
Observer Pattern «Interface» Observable Observer changed : bool update(Observable o, Object arg) addObserver(Observer o) * hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed)
Observer Pattern «Interface» Observable Observer changed : bool update(Observable o, Object arg) addObserver(Observer o) * hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() post: result = changed
Observer Pattern «Interface» Observable Observer changed : bool update(Observable o, Object arg) addObserver(Observer o) * hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() context Observable::hasChanged() post: result = changed body: changed
Recommend
More recommend