ניתוח ועיצוב מערכות תוכנהאביב 2012 שפת אילוצי העצמיםObject Constraints Language (OCL)
Outline • What is OCL • Types of constraints • Constraints structure • OCL expressions • Examples • Textbook: Jos Warmer and AnnekeKleppe,“The Object Constraint Language”Available on Google Books
What is OCL • It is intended for the specification of additional requirements (constrains) which cannot or be expressed graphically. • To specify invariants on classes and types in the class model. • To describe pre- and post- conditions on operations. • To describe guards. • To specify target (sets) for messages and actions. • To specify constraints on operations. • To specify derivation rules for attributes for any expression over a UML model.
Types of Constraints • An invariant is a constraint that states a condition that must always be met by all instances of the class, type, or interface. • An invariant is described using an expression that evaluates to true if the invariant is met. • Invariants must be true all the time (Class diagram). • A precondition to an operation is a restriction that must be true at the moment that the operation is going to be executed. • The obligations are specified by post conditions (Sequential diagram). • A postcondition to an operation is a restriction that must be true at the moment that the operation has just ended its execution (Sequential diagram). • A guard is a constraint that must be true before a state transition fires (State machine diagram).
Constraints Structure contextTypenamec_type[name]: <OCL–expression> • The context is keyword introduces the context for the expression. Each OCL expression is written in the context of an instance of a specific type. • Typename is the name of the type or the class for which the invariant constrain applies. • c_type is the type of the constrain: • invariant, pre/post-condition, guard. • [name] – optional, the names of the constraint. • OCL - expression should accept value “true” for all instances of Typename. • For example: • Context Packagename1::class1 inv : … • Context class2 inv : …
Basic Data Types • Operations above basic types of data (Boolean, Integer, Real, String);
Collections • set : the mathematical set. • It is not ordered and does not contain duplicate elements. • bag : A container. • It is not ordered and contain duplicate elements. • sequence : An container. • It is ordered and contain duplicate elements. collection asSet() : can be used to convert any collection into a set (remove duplicates).
implies operator, operator • Implies: • • Operations on collections. • Do not mix ‘’ with ‘implies’ as in logical notation!
Collection Operations • <collection> → … → isEmpty( ) → notEmpty ( ) → exists ( e:T | <b.e.>) isUnique(e:T | <v.e>) Boolean: → forAll ( e:T* | <b.e.>) forAll(e:T1,f;T2|<b.e.>) → excludes ( object ) → includes ( object ) → includesAll ( collection ) → count ( object ) Numeral: → size ( ) → sum ( ) → select ( e:T | <b.e.>) asSet() Collections:→ reject ( e:T | <b.e.>) including(object), excluding(object) → collect ( e:T | <v.e.>) includingAll(collection), excludingAll(collection) Generic:→ iterate ( e:T1; r:T2 = <v.e.> | <v.e.>) • b.e. stands for: boolean expression • v.e. stands for: value expression (as seen in the Structural Modeling, Part B lecture (slides 59-60)).
Collection Operations - Select select ( e:T | <b.e.>): SQL-like select, returning a sub-collection of the original. animals select(a:Animal | a.family == “Reptile”) reject ( e:T | <b.e.>) is select’s complementary operation. From a collection of animals – to a <= collection of animals! • e stands for iterator expression, • T stands for type. • b.e. stands for: boolean expression • v.e. stands for: value expression
Collection Operations - Collect collect ( e:T | <v.e.>): from every member of the collection, take something. Thus this operation might return a collection of different type than the original! animals collect(a:Animal | a.name) From a collection of animals– to a collection of strings! Shorthand Notation:students.studentCard – only in ‘collect’!!! Alice Bob Carol DaveEve Mallory Peggy VictorTrent Trudy Walter Paul
OCL – expression • Operations above objects: <class>.<attribute> <class>.<role>.<attribute> (preferred) <class>.<class name>.<attribute> • context Employee inv: self.age>17 andself.age<=100 • context Employee inv: self.age>30 orself.workplace.number<5 • context Department inv: self.number<5 orself.employee select(age<=30)size()=0 • context Department inv: self.employeeexist(job=“manager”) andself.company.year<=self.year • context Company inv: self.department.employeeforAll(age<=67) • Operations above collections: <collection>→<operation> • דוגמאות: • גיל העובדים חייב להיות בין 18 ל- 100 • גיל מינימלי של העובדים במחלקות 5 ומעלה חייב להיות לפחות 31. • לכל מחלקה חייב להיות "מנהל" ושנת הקמת המחלקה לא מוקדם משנת הקמת החברה • פנסיונרים לא מועסקים בחברה
Example 1: treating collections as instances, enumerations • If a person has a wife, she must be female and the person must be male. • context Person inv: WifenotEmpty() implies (wife.gender=Gender::female and self.gender=Gender::male) //note: after a collection has been validated to be of size 1, it can be treated as an instance! • If a person has a husband, he must be male and the person must be female. • context Person inv: HusbandnotEmpty() implies (husband.gender=Gender::male and self.gender=Gender::female)
Example 1 (Cont.) • If a person is male he can't have pink car • context Person inv: (self.gender==Gender::male) implies (self.ownsselect(c|c.color==‘pink’)size()=0) • If a person is unemployed he can't own cars in value of more then 500,000$ • context Person inv: (self.unemployed) implies (self.owns collect(c | c.value) sum()<= 500000) • A person can’t have cars in more then 3 different colors • context Person inv: self.owns collect(c|c.color) asSet() size()<=3 (אם האדם מובטל אז) (יוצר אוסף של ערכי הרכבים שברשותו) (חשב סכום ערכי הרכבים תבדוק שהוא קטן מ-500000) (יוצר אוסף של צבעי הרכבים שברשותו) (הפוך את האוסף ל set - השאר אחד מכל צבע) (ספירת כמות צבעים ובדיקה שאין יותר מ 3 צבעים)
Example 1 (Cont.) • A person between the age of 0 to 18 can’t own a yellow car while person between the age of 18 and 21 can own one yellow car at most and a person older then 21 can own as many yellow cars as he like. • context Person inv: let amountOfYellowCars : Integer = self.ownsselect(c:Car | c.color = “yellow”)size() in if (self.age < 18) then(amountOfYellowCars = 0) else if (self.age < 21) then (amountOfYellowCars <= 1) else true endif endif
Example 2 • The sum of the values of all securities must be at least 20% more than the amount of the credit. • context Credit invsufficientSecurities: securities.Value sum()>self.Amount * 1.2 • A credit of a given customer can only be secured by securities that are owned by the given customer. (הלוואה של לקוח נתון מאובטחת רק ע"י ערבויות ששייכות לאותו הלקוח ) • context Credit invonlyOwnedSecurities: securities.ownerforAll(aa:Customer|aa = self.customer) • aa is instance of owner!!!!
Instance and Type Operations • Instances have the following operations: self.oclIsTypeOf(T) returns true iff self is of type T self.oclIsKindOf(T) returns true iff (self is of type T) V (self’s subtype of T) Self.oclAsType(T) used for casting (for instance, from Abstract class to Subclass). • Types have the ‘allInstances’ member: T.allInstances returns a collection of all T instances. Example: “At least 1 animal has to eat meat”: Animals.allInstances exists(a:Animal|a.eats == “Meat”) In reality, this is usually frowned upon (we’ll see it later!)
Example 3: allInstances, type checks, recursion • All people should be married • context Person inv: Person.allInstancesforAll(p:Person | p.married) • In a Class all the Attributes have different names. • context Class inv: self.features select(f|f.oclIsTypeOf(Attribute))isUnique(a:Attribute|a.name) (collection of Attributes) (collection of Features)
Association Class * • Navigate to an association class: • If the context is Teacher, you could navigate to the association class with the expression: self.Room. • This expression would result in a collection of all the room assignments for all the courses to which the teacher is assigned. • Navigate from an association class to either end of the association: • Starting with a context of the Room class, the expressions: self.instructor self.course is valid. • Navigating from an association class always results in a single object.
Example 4 - Train • All trains must own at least one wagon • context Train invatLeastOneWagon:self.wagon size() >= 1 • A wagon and its successor wagon should belong to the same train • context Wagon invbelongToTheSameTrain:self.succ notEmpty() implies self.succ.train = self.train • All the trains will have the same number of wagons • context Train invsameNumberOfWagons:Train.allInstances forAll(x:Train,y:Train | x.wagonsize() = y.wagonsize() )
Example 4 - Train • There do not exists two different wagons directly linked to each other in a cyclic way • not necessary : consider two wagon instances w1,w2. • If these two instances are linked with an ‘Order’ link, one has to assume the role of ‘succ’ and the second must assume the role of ‘pred’ – two can’t close a cycle! • But how do you prevent a cycle of > 2 wagons? • Context Train invNoCycles: Wagoncollect(w | w.succ)size() = Wagon.size()-1 Will this work?
Advanced Topics in OCL • Types and Subtypes via oclIsTypeOf and oclIsKindOf
Advanced Topics in OCL • Preconditions, Postconditions, Operations (sic, p.155) • Navigation into class method using ‘::’ • post : result = participants This is how we define the result! • Keywords: <attribute>@pre , pre , post , result .
Advanced Topics in OCL • Avoid allInstances (Warmer and Kleppe, p.67) “A Person has no more than 2 parents:” context Person Inv: parents size() <= 2 context Person Inv: Person.allInstancesforAll(p:Person|p.parentssize()<= 2) “The use of allInstances is discouraged, because it makes the invariant more complex [even to the point of hiding it.]... “In most systems... It is difficult to find all instances of a class. Unless an explicit tracking device keeps a record of all instances of a certain class as they are created and deleted, there is no way to find them. Thus, there is no way to implement the invariant using a programming language equivalent to the allInstances operation.
Advanced Topics in OCL And this is just the beginning... • Handling message-passing between objects • Tuples and Tuple Types • Unvefined Values: the OclVoid type • Retyping or Casting Unfortunately, these along with many other OCL features are out of the scope of our course.