Upload
tosca
View
38
Download
0
Tags:
Embed Size (px)
DESCRIPTION
The Object Constraint Language (OCL). Jacques Robin. Outline. What is OCL? Uses of OCL for Model-Driven Development Motivating examples The OCL meta-model OCL Types OCL Expression Context OCL and Inheritance Primitive Type Operators Local Variables Collections and Tuples Messages - PowerPoint PPT Presentation
Citation preview
OntologiesReasoningComponentsAgentsSimulations
The Object Constraint Language The Object Constraint Language (OCL)(OCL)
Jacques Robin
OutlineOutline
What is OCL? Uses of OCL for Model-Driven Development Motivating examples The OCL meta-model OCL Types OCL Expression Context OCL and Inheritance Primitive Type Operators Local Variables Collections and Tuples Messages Packages OCL Constraints vs. UML Constraints OCL Formal Semantics OCL vs. Java
What is OCL?What is OCL?
A textual specification language to adorn UML diagrams and make a UML model far more semantically precise, detailed and thus productive (i.e., subject to automated processing leading to code).
Characteristics: Formal language with well-defined semantics based on set theory and first-
order predicate logic, yet free of mathematical notation and thus friendly to mainstream programmers
Object-oriented functional language: constructors syntactically combined using functional nesting and object-oriented navigation in expressions that take objects and/or object collections as parameters and evaluates to an object and/or an object collection as return value
Strongly typed language where all expression and sub-expression has a well-defined type that can be an UML primitive data type, a UML model classifier or a collection of these
Semantics of an expression defined by its type mapping Declarative language that specifies what properties the software under
construction must satisfy, not how it shall satisfy them Side effect free language that cannot alter model elements, but only specify
relations between them (some possibly new but not created by OCL expressions)
Pure specification language that cannot alone execute nor program models but only describe them
Both a constraint and query language for UML models
Uses of OCL for Model-Driven Uses of OCL for Model-Driven Development: Formalizing StructureDevelopment: Formalizing Structure
Adorn a class diagram in UML structural models or MOF meta-models to make them formally precise
Specify complex constraints (value, multiplicity, type, etc) between multiple attributes and associations
Disambiguate association cycles Specifying rules that define derived attributes, associations and
classes Specify query operation bodies Specify operation pre and post conditions for design by
contract and automated test generation
Uses of OCL for Model-Driven Uses of OCL for Model-Driven Development: Formalizing BehaviorDevelopment: Formalizing Behavior
Adorn an interaction diagrams (associated to a class diagram) Specify objects Specify message expressions including guards, iteration and condition
clauses, return value signature Specify guards on lifelines of alternates fragments
Adorn a state machine (associated to a class diagram): Specify trigger and deferred events, guards, state activities Specify object target and parameter values of transition action, state entry
action, state exit action Specify constraints between the state of an object and its other features
(attributes, association ends) Adorn an activity diagram (associated to a class diagram):
Specify transition guards Specify object host and parameter values of actions Specify objects in object flows and their states
Adorn a use case diagram (associated to a class diagram): Specify the pre and post conditions of each use case
OCL: Motivating ExamplesOCL: Motivating Examples
Diagram 1 allows Flight with unlimited number of passengers
No way using UML only to express restriction that the number of passengers is limited to the number of seats of the Airplane used for the Flight
Similarly, diagram 2 allows: A Person to Mortgage the house of
another Person A Mortgage start date to be after
its end date Two Persons to share same social
security number A Person with insufficient income to
Mortgage a house
1
2
OCL: Motivating ExamplesOCL: Motivating Examples
1
2
context Flightinv: passengers -> size() <= plane.numberOfSeats
context Mortgage inv: security.owner = borrowerinv: startDate < endDate
context Personinv: Person::allInstances() -> isUnique(socSecNr)
context Person::getMortgage(sum:Money,security:House)pre: self.mortgages.monthlyPayment -> sum() <= self.salary * 0.3
OCL Expression ContextOCL Expression Context
Operation
Specifying Initial Property ValuesSpecifying Initial Property Valuesand Query Operationsand Query Operations
Initial values: context LoyaltyAccount::points : integer
init: 0 context LoyaltyAccount::transactions
: Set(Transaction) init: Set{}
Query operations: context
LoyaltyAccount::getCustomerName() : Stringbody: Membership.card.owner.name
context LoyaltyProgram::getServices(): Set(Services)body: partner.deliveredServices -> asSet()
Defining New AttributesDefining New Attributesand Operationsand Operations
New attribute: context Customer
def: initial:String = name.substring(1.1)
New operation: context CustomerCard
def: getTotalPoints(d:Date):Integer = transactions -> select(date.isAfter(d)) .points -> sum()
Dot operatorDot operator
Association navigation: context Transaction
def getCustomer():Customer = self.card.owner
Attribute access: context Transaction
def getCustomerName():String = self.card.owner.name
Abbreviation of collect operator that creates new collection from existing one, for example result of navigating association with plural multiplicity:
context LoyaltyAccount inv: transactions -> collect(points) -> exists(p:Integer | p=500)
context LoyaltyAccount inv: transactions.points -> exists(p:Integer | p=500)
Call UML model and OCL built-in operations
Association NavigationAssociation Navigation
Use target class name to navigate roleless association: context LoyaltyProgram inv: levels -> includesAll(Membership.currentLevel)
Identify navigation qualifier between []: context LoyaltyProgram inv: self.levels[1].name = ‘basic’
Generalization NavigationGeneralization Navigation
OCL constraint to limit points earned from single service to 10,000 Cannot be correctly specified using association navigation: context ProgramPartner inv totalPoints: deliveredServices.transactions .points -> sum() < 10,000adds both Earning and Burning points Operator oclIsTypeOf allows hybrid navigation following associations and specialization linkscontext ProgramPartner inv totalPoints: deliveredServices.transactions -> select(oclIsTypeOf(Earning)) .points -> sum() < 10,000
Specifying Invariants on AttributesSpecifying Invariants on Attributes
The context of an invariant constraint is a class
When it occurs as navigation path prefix, the self keyword can be omitted:
context Customer inv: self.name = ‘Edward’
context Customer inv: name = ‘Edward’
Invariants can be named: context Customer inv myInvariant23:
self.name = ‘Edward’ context LoyaltyAccount
inv oneOwner: transaction.card.owner -> asSet() -> size() = 1
In some context self keyword is required: context Membership
inv: participants.cards.Membership.includes(self)
Specifying Derivation Rules Specifying Derivation Rules for Attributesfor Attributes
context CustomerCard::printedName derive: owner.title.concat(‘
‘).concat(owner.name) context TransactionReportLine: String
derive self.date = transaction.date ... context TransactionReport
inv dates: lines.date -> forAll(d | d.isBefore(until) and d.isAfter(from))
...
Design by Contract: Pre and Design by Contract: Pre and Postconditions on OperationsPostconditions on Operations
A class or interface offers services to other classes through a set of typed public operations
This service can be designed by contract through the specification of the pre-condition and post-condition of each operation
The contract states that: Whenever a client class invokes an operation in way that satisfies
its specified preconditions The server class or interface guarantees that the execution of the
operation will result in the satisfaction of its specified post-conditions
The preconditions thus specify the rights of the server while the post-conditions specify its obligations
Specifying Contractual InterfacesSpecifying Contractual Interfaces
context LoyaltyAccount::isEmpty(): Booleanpre: -- nonepost: result = (points = 0)
Keyword @pre used to refer in post-condition to the value of a property before the execution of the operation:
context LoyaltyProgram::enroll(c:Customer)pre: c.name <> ‘ ‘post: participants = participants@pre -> including(c)
Keyword oclIsNew used to specify creation of a new instance (objects or primitive data):
context LoyaltyProgram::enrollAndCreateCustomer(n:String,d:Date):Customerpost: result.oclIsNew() and result.name = n and result.dateOfBirth = d and participant -> includes(result)
oclIsNew only specifies that the operation created the new instance, but not how it did it which cannot be expressed in OCL
Disambiguating Association Cycles, Disambiguating Association Cycles, Optional Multiplicity and Or Optional Multiplicity and Or
ConstraintsConstraints Cycles of association with plural multiplicity are
often underconstrained by class diagrams, thus not reflecting actual modeled domain semantics
In the real world a person cannot use the house of another person as security for a mortgage
context Personinv: mortgages.security.owner -> forall(onwner:Person | owner = self)
UML ‘or’ constraint can mean: either that a Person can either manage a Project or
perform a Project but not both or that a Project is managed by one Person or
performed by one Person but not both
OCL invariant disambiguating between these two interpretations:
context Personinv: managedProject -> isEmpty() or performedProject -> isEmpty()
context Projectinv: projectLeader -> isEmpty() or projectMember -> isEmpty()
The OCL meta-modelThe OCL meta-model
OCL TypesOCL TypesStructuralFeature Classifier
OclMessageType OclModelElementType DataType VoidType
TupleType Primitive CollectionType
SetType SequenceType BagType
OrderedSetType
OperationSignal
+elementType
1
+collectionTypes
0..4
0..*
+type
1
+referredSignal0..1 +referredOperation0..1
OCL TypesOCL Types
Value Types: UML primitive types (including user-defined enumerations) OCL collection types (even of user-defined classifiers ?) Their instances never change value
ex, Integer instance 1 cannot be changed to instance 2, nor can string instance “Lew Alcindor” be changed to string instance “Kareem Abdul-Jabbar”, nor can enumeration Grade instance A can be changed to enumeration instance C.
Object types: UML classifiers Their instances can change value, i.e., the Person instance p1 can
have its name attribute “Lew Alcindor” changed to “Kareem Abdul-Jabbar” yet remain the same instance p1
OclAny: Most generic OCL type, subsuming all others General reflective operations are defined for this type and
inherited by all other OCL types
OCL TypesOCL Types
Primitive data types (from UML): boolean, string, integer
Type conformance rules: t1 conforms to t2 if t1 <= t2 in type hierarchy
t1 = collection(t2) conforms to t3 = collection(t4) if t2 conforms to t4
integer <= real
Type casting: Operation oclAsType(s) can be invoked on an expression of type g
to recast it as a type s s must conform to g
OclVoid: Undefined value (similar to null values of SQL) Tested by oclIsUndefined operation of OclAny type
Links BetweenLinks BetweenOCL and UML Meta-ModelsOCL and UML Meta-Models
ModelElement
Classifier
Constraint
Expression
ExpressionInOcl OclExpression
0..1
+body1
+bodyExpression
1
+constrainedElement
0..*
+constraint
0..*
Inheritance and EncapsulationInheritance and Encapsulation
By default, OCL expressions ignore attribute visibility i.e., an expression that access a
private attribute from another class is not syntactically rejected
OCL constraints are inherited down the classifier hierarchy
OCL constraints redefined down the classifier hierarchy must follow substituability principle Invariants and post-condition
can only become more restrictive
Preconditions can only become less restrictive
context Stove inv: temperature <= 200
context ElectricStove inv: temperature <= 300
context Stove::open()pre: status = StoveState::offpost: status = StoveState::off and
isOpen
context ElectricStove::open()pre: status = StoveState::off and
temperature <= 100post: isOpen
Local VariablesLocal Variables
Let constructor allows creation of aliases for recurring sub-expressions
context CustomerCardinv: let correctDate : Boolean =
validFrom.isBefore(Date::now) and goodThru.isAfter(Date::now)
in if correctDate then valid = true else valid = false endif
Syntactic sugar that improves constraint legibility
Generic OperatorsGeneric Operators
Operators that apply to expressions of any type
Defined at the top-level of OclAny
Primitive Type OperatorsPrimitive Type Operators
Boolean: host, parameter and return type boolean Unary: not Binary: or, and, xor, =, <>, implies Ternary: if-then-else
Arithmetic: host and parameters integer or real Comparison (return type boolean): =, <>, <, > <=, >=, Operations (return type integer or real): +, -, *, /, mod, div, abs,
max, min, round, floor
String: host string Comparison (return type boolean): =, <> Operation: concat(String), size(), toLower(), toUpper(),
substring(n:integer,m:integer)
CollectionsCollections
Collection constants can be specified in extension: Set{1, 2, 5, 88}, Set{‘apple’, ‘orange’, ‘strawberry’} OrderedSet{‘black’, ‘brown’, ‘red’, ‘orange’, ‘yellow’, ‘green’, ‘blue’,
‘purple’} Sequence{1, 3, 45, 2, 3}, Bag{1, 3, 4, 3, 5}
Sequence of consecutive integers can be specified in intension: Sequence{1..4} = Sequence{1,2,3,4}
Collection operations are called using -> instead of . Collection operations have value types:
They do not alter their input only output a new collection which may contain copies of some input elements
Most collections operations return flattened collections ex, flatten{Set{1,2},Set{3,Set{4,5}}} = Set{1,2,3,4,5}
Operation collectNested must be used to preserve embedded sub-structures
Navigating through several associations with plural multiplicity results in a bag
Specialized Collection OperatorsSpecialized Collection Operators
Generic Collection OperatorsGeneric Collection Operators
Syntax of Loop OperatorsSyntax of Loop Operators
Loop operators (aka. iterator operations, aka. iterators) Common characteristics:
They are all hosted by an OCL expression of type collection They all take an OCL expression as input parameter (called the
body of the loop) They optionally take as second parameter an iterator variable The return type of the body expression and the type of the iterator
variable must conform to the type of the host collection’s elements Loop operators iterate over the elements of the host collection,
applying the body expression to each one of them Distinguishing characteristics:
How they combine the body expression application into a new result collection
Example of OCL Expressions Example of OCL Expressions with Loop Operatorswith Loop Operators
context LoyaltyProgram inv self.Membership.account -> isUnique(acc: LoyaltyAccount | acc.number) context LoyaltyProgram inv Membership.account -> isUnique(acc | acc.number) context LoyaltyProgram inv Membership.account -> isUnique(number) Iterator variable clarifies that number refers to the number attribute of each collection element and not to the number of elements in the collection Loop expressions with reference to the iterator requires an iterator variable: context ProgramPartner inv: self.programs.partners -> select(p:ProgramPartner | p.self)
TuplesTuples
Values can be composed in tuples of types fields of heterogeneous types
Tuple {<fieldName>: <TypeExpression> = <ValueExpression>, ...}
Tuple {name: String = ‘John’, age: Integer = 10} Tuple {a: Collection(Integer) = Set{1,2,7}, b: String = ‘foo’}
Tuple types can be specified using same syntax without value expression:
TupleType {<fieldName>: <TypeExpression>, ...} TupleType {name: String, age = Integer} Convenient to express constraints on data layers using
relational model
MessagesMessages
isSent ^ operator in an operation post-condition, specifies which messages (operation calls or signals) must be sent by the execution of the operation
context Subject::hasChanged() post: observer^update(12,14) ? can be used to specify unknown messages of a given type context Subject::hasChanged()
post: observer^update(? :integer, ? :integer) In addition to their base types, all messages sent are also instances of
the special type OclMessage Message operator ^^ allows performing pattern matching on sent
messages context Subject::hasChanged()
post: let messages: Sequence(OclMessage) = observers -> collect(o | o^^update(? :integer, ? :integer)) in messages -> notEmpty()
Other message operators: Booleans isSignalSent(), isOperationCall(), hasReturned() result() returns type of called operation
PackagesPackages
OCL expressions can be structured in packages and sub-packages
Package can be specified inside a context specification: context P::S::C inv ... context P::S::C::op() pre: ... post: ...
Or with keyword pair package, endpackage surrounding set of expressions: package P::S context X inv: ... context X::op pre: ... post: ... endpackage
OCL Constraints OCL Constraints vs.vs. UML Constraints UML Constraints
context ElectricGuitar inv: strings -> forAll(s \ s.oclIsType(MetalStrings))
context: ClassicalGuitar inv: strings-> forAll(s | s.oclIsType(plasticStrings))
context ElectricGuitar inv: strings -> forAll(type = StringType::metal)
context ClassicGuitar inv: strings -> forAll(type = StringType::plastic)
context Guitar inv: type = GuitarType::classic implies strings -> forAll(type = StringType::plasticinv: type = GuitarType::classic implies strings -> forAll(type = StringType::plastic
OCL Formal SemanticsOCL Formal Semantics
Set theoretic Semantic domain for each OCL type defined by its set of
possible values Semantics of an OCL expression defined by the mathematical
function mapping the semantic domains of its host and input parameters to its return value
OCL OCL vs.vs. Java Java Declarative specification of operation post-conditions in OCL is far more concise
than corresponding implementation in mainstream imperative OO language such as Java
This is due mainly to OCL’s powerful collection operators Example: OCL expression
self.partners -> select(deliveredServices -> forAll(pointsEarned = 0)) Corresponding Java code:1. Iterator it = this.getPartners().iterator();2. Set selectResult = new HashSet(); 3. while( it.hasNext() ){ 4. ProgramPartner p = (ProgramPartner) it.next(); 5. Iterator services = p.getDeliveredServices().iterator(); 6. boolean forAllresult = true; 7. while( services.hasNext() ){ 8. Service s = (Service) services.next(); 9. forAllResult = forAllResult && (s.getPointsEarned() == 0); 10. } 11. if ( forAllResult ){ 12. selectResult.add(p); 13. } 14. } 15. return result;