02291: System Integration Design By Contract and OCL Hubert - - PowerPoint PPT Presentation

02291 system integration
SMART_READER_LITE
LIVE PREVIEW

02291: System Integration Design By Contract and OCL Hubert - - PowerPoint PPT Presentation

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) {


slide-1
SLIDE 1

02291: System Integration

Design By Contract and OCL Hubert Baumeister

huba@dtu.dk

DTU Compute Technical University of Denmark

Spring 2019

slide-2
SLIDE 2

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); } }

slide-3
SLIDE 3

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))

slide-4
SLIDE 4

Contracts

Counter i : int inc() : void dec() : void {The field i should always be greater than 0.} {The inc operation increases i by one.} {The operation dec should be called only if i is greater than

  • zero. In this case i is decremented

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

slide-5
SLIDE 5

Example

Counter i : int inc() : void dec() : void {The field i should always be greater than 0.} {The inc operation increases i by one.} {The operation dec should be called only if i is greater than

  • zero. In this case i is decremented

by one.}

slide-6
SLIDE 6

Example

Counter i : int inc() : void dec() : void {The field i should always be greater than 0.} {The inc operation increases i by one.} {The operation dec should be called only if i is greater than

  • zero. In this case i is decremented

by one.}

Counter inc() : void dec() : void i : int {context Counter inv: i >= 0} {context Counter :: inc ( ) post: i = i@pre + 1} {context Counter :: dec ( ) pre: i > 0 post: i = i@pre - 1 }

slide-7
SLIDE 7

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

  • f 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

slide-8
SLIDE 8

Bank example with constraints

Bank Account

update(n : int) : void bal : int

History

History() : void bal : int 0..1 prev 1 1 0..1 1

  • wner

0..* accounts {context Bank inv: accounts->forAll(a | a.owner = self) {inv: bal >= 0} {pre: bal + n >= 0 post: bal = bal@pre + n and history.oclIsNew() and history.bal = bal@pre and history.prev = history@pre}

slide-9
SLIDE 9

Update operation of Account

State before executing update(n)

a: Account bal = b h: History bal = m { n + b > = 0 }

slide-10
SLIDE 10

Update operation of Account

State before executing update(n)

a: Account bal = b h: History bal = m { n + b > = 0 }

State after executing update(n)

h1: History bal = b h: History bal = m a: Account bal = b + n prev

slide-11
SLIDE 11

OCL Syntax

◮ More on OCL operators and OCL

◮ Online on Safari books: ”Object Constraint Language” by

Jos Warmer, Anneke Kleppe (cf. course home page)

slide-12
SLIDE 12

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)

slide-13
SLIDE 13

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

slide-14
SLIDE 14

Notation

◮ Within notes in {}

{pre: i > 0 post: i = i@pre -1} {inv: i >= 0} {post: i = i@pre + 1} Counter i : int inc dec

◮ As separate text.

◮ In this case the context part must be present

context Counter inv: i >= 0 context Counter :: inc post: i = i@pre + 1

slide-15
SLIDE 15

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)

slide-16
SLIDE 16

OCL Syntax (simplified): Basic operations

b a A y:int m() B x:int ◮ Attribute / Navigation (in the context of class A)

◮ self ◮ self.b.x

◮ Operation Calls

◮ self.m(c1, · · · , cn) (Method call) ◮ self.b → cop(. . .) (Call to a method on collections)

context A inv: self.b.x->includes(3)

slide-17
SLIDE 17

Navigation

Navigation via dot (.) notation to roles and attributes

b a A y:int B x:int

b1:B { x = 5 } a1:A { y = 1 0 }

a1.b = a1.b.x =

slide-18
SLIDE 18

Navigation

Navigation via dot (.) notation to roles and attributes

b a A y:int B x:int

b2:B {x = 5} a1:A {y = 10} b1:B {x = 3}

a1.b = a1.b.x =

slide-19
SLIDE 19

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)

slide-20
SLIDE 20

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

slide-21
SLIDE 21

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)

slide-22
SLIDE 22

Flattening Collections

Person Club * member * Federation * 1

f.club.member = f.club->collect(member) = f.club->collectNested(member) =

slide-23
SLIDE 23

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

slide-24
SLIDE 24

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

slide-25
SLIDE 25

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed

slide-26
SLIDE 26

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed)

slide-27
SLIDE 27

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() post: result = changed

slide-28
SLIDE 28

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() post: result = changed context Observable::hasChanged() body: changed

slide-29
SLIDE 29

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() post: result = changed context Observable::hasChanged() body: changed context Observable::addObservers(Observer o) post: observers = observers@pre->including(o)

slide-30
SLIDE 30

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() post: result = changed context Observable::hasChanged() body: changed context Observable::addObservers(Observer o) post: observers = observers@pre->including(o) context Observable::notifyObservers(Object arg) pre: changed post: observers->forAll( o | oˆupdate(self, arg)) and not(changed)

slide-31
SLIDE 31

Observer Pattern

Observable changed : bool addObserver(Observer o) hasChanged() : bool setChanged() clearChanged() notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::setChanged() post: changed context Observable::clearChanged() post: not(changed) context Observable::hasChanged() post: result = changed context Observable::hasChanged() body: changed context Observable::addObservers(Observer o) post: observers = observers@pre->including(o) context Observable::notifyObservers(Object arg) pre: changed post: observers->forAll( o | oˆupdate(self, arg)) and not(changed) context Observable::notifyObservers(Object arg) post: changed@pre implies (observers->forAll( o | oˆupdate(self, arg)) and not(changed))

slide-32
SLIDE 32

Observer Pattern Final

Observable changed : bool addObserver(Observer o) notifyObservers(Object arg) «Interface» Observer update(Observable o, Object arg) *

context Observable::addObservers(Observer o) post: observers = observers@pre->including(o) context Observable::notifyObservers(Object arg) post: changed@pre implies (observers->forAll( o | oˆupdate(self, arg)) and not(changed))

slide-33
SLIDE 33

Example Vending Machine

slide-34
SLIDE 34

Vending machine behaviour with OCL constraints

{def: itemDispensed(f:Fruit, oldCm:int) = dispensedItem = f and restMoney = oldCm - priceFor(f) and currentMoney = 0 and totalMoney = totalMoney + priceFor(f) } {inv: currentMoney >= 0 and totalMoney >= 0 and restMoney >= 0 } {pre: m > 0 post: if (selectedFruit <> null and enoughMoney(selectedFruit)) then itemDispensed(f,currentMoney@pre + m) else currentMoney = currentMoney@pre + m endif } {post: if enoughMoney(f) then itemDispensed(f,currentMoney@pre) else selectedFruit = f endif } {pre: (f = banana) or (f = apple) body: if (f = banana) then 5 else 3 } {post: currentMoney = 0 and restMoney = currentMoney@pre and selectedFruit->size() = 0 } {body: currentMoney >= priceFor(f)} {body: fruit->collect(f1 | f1 = f)->size() >= 1} {pre: enoughMoney(f) and hasFruit(f) post: itemDispensed(f,currentMoney@pre) } 0..1 selectedFruit 0..1 dispensedItem * fruit «enumeration» Fruit banana apple VendingMachine currentMoney: int totalMoney: int restMoney: int input(m:int) select(f:Fruit) cancel() enoughMoney(f:Fruit) {isQuery} hasFruit(f:Fruit) {isQuery} dispense(f:Fruit) priceFor(f:Fruit) {isQuery}

slide-35
SLIDE 35

Vending machine behaviour as life cycle state machine