OCL specification¶
We have added support for defining OCL constraints (e.g. to specify invariants or business rules) on the B-UML models. OCL expressions can be written in plain text and then automatically parsed to create the abstract syntax tree (AST) for expression according to the OCL metamodel shown below.
Note
The classes highlighted in green originate from the structural metamodel.
BOCL supports four constraint kinds. Each has its own header shape — the
parser routes on the keyword that follows context:
Kind |
Header form (and a one-line example) |
|---|---|
|
|
|
|
|
|
|
|
Invariants attach to the DomainModel’s constraint set. Preconditions
and postconditions attach to a specific Method via add_pre /
add_post (see below). Initialisation constraints attach to a specific
attribute.
Note
B-OCL Interpreter is available at https://github.com/BESSER-PEARL/B-OCL-Interpreter. With this interpreter you can validate your OCL constraints defined on B-UML models.
Anchoring preconditions and postconditions on a method (Python API)¶
Preconditions and postconditions are first-class fields on Method —
method.pre and method.post. Use add_pre / add_post to attach
parsed OCL constraints to the operation they govern, instead of relying on
naming conventions:
from besser.BUML.metamodel.structural import (
DomainModel, Class, Property, Method, Parameter, IntegerType, BooleanType,
)
from besser.BUML.notations.ocl.api import parse_ocl
account = Class("Account", attributes={
Property("balance", IntegerType),
Property("is_active", BooleanType),
})
model = DomainModel("BankingModel", types={account})
deposit = Method(
name="deposit",
parameters=[Parameter("amount", IntegerType)],
type=IntegerType,
)
pre = parse_ocl(
"context Account::deposit(amount: Integer) pre: self.is_active and amount > 0",
model, context_class=account,
)
post = parse_ocl(
"context Account::deposit(amount: Integer) post: self.balance >= 0",
model, context_class=account,
)
pre.name, post.name = "deposit_pre_active_and_positive", "deposit_post_nonneg"
deposit.add_pre(pre)
deposit.add_post(post)
Note
parse_ocl’s auto-detect regex only matches the simple context Class
inv|pre|post|init shape, not Class::method(...), so when parsing pre /
post / init you must pass context_class explicitly (as above).
Working with parsed constraints¶
If you are writing a tool that walks the OCL AST — to evaluate constraints, encode them into another formalism, or transform them — the following sub-pages cover the public surface:
For a runnable end-to-end example, see Object Constraint Language (OCL).
Supported notations¶
To create an object model, you can use any of these notations: