Object Constraint Language (OCL) is a formal language that is widely used in the modelling community to complement the (UML) models with textual constraints that precisely define additional business rules for the system.
Despite the benefits of using OCL to create precise software specifications, writing the OCL rules themselves is a challenging task that may lead to a number of verification (are the OCL expressions correct?) and validation (are they the correct OCL expressions?) challenges. Formal methods techniques, such as smart bounded verification, are typically used for the verification part. But for the validation part, we need to be able to “execute” or “evaluate” the OCL expressions over different valid and invalid scenarios to make sure the expressions forbid the invalid ones and allow the valid ones.
Unfortunately, our search for an OCL interpreter able to run OCL expressions that was suitable to be integrated in the low-code low-modeling BESSER platform came up empty. Not really a surprise, as OCL is probably the only language that has less and less tool support every year. And the few OCL tools that exist (shoutout to USE and Eclipse OCL) are Java-based and by now you should already know that BESSER is Python-based. Two small Python-based exceptions exist: pyalaocl and pyecore-ocl but neither provides an OCL interpreter.
So, at the risk of reinventing the wheel, we decided to go ahead and add full OCL support to our modeling BESSER components, including a brand new OCL interpreter to evaluate OCL constraints on scenarios conforming to BESSER models.
OCL is widely used in modelling domain and a rich set of tools support OCL interpretation such as eclipse modeling framework. Unfortunately, the available tool sets are only available in java language.
Introducing the BESSER Object Constraint Language (B-OCL) Interpreter
The first-ever open source OCL interpreter in python language. B-OCL is accessible in two ways :
- Through the BESSER Web Modeling Editor: a browser-based environment requiring no installation or local setup, directly accessible via any standard web browser.
- As a standalone Python library via PyPI.
We also provide a template with different types of OCL constraints in the web modeling editor. This integration of structural modeling, OCL constraint specification, object-level validation, and code generation within a single online environment represents a meaningful step towards lowering the adoption barrier for OCL
B-OCL has three main capabilities, each corresponding to a stage in the workflow; which is also where the title comes from:
| Stage | What it does |
|---|---|
| ⟨/⟩ Parse it | Syntactically validates OCL constraints and builds an AST |
| ▶ Interpret it | Evaluates constraints against an object model |
| ⚙ Generate it | Translates constraints into executable validation code |
Each of which will be explained below
Parse It: Syntactic Validation
B-OCL constraints are defined directly on a B-UML structural model, either via the web modeling editor or programmatically. Each constraint is internally represented as an instance of the B-OCL metamodel. For instance, consider a simple constraint on Book class:
context Book inv book_nonneg_pages: self.pages > 0.
Produces the following AST where the root is OperationCallExpression node representing the > comparison, with three children: the pages property, the > infix operator, and the integer literal 0
If a constraint is syntactically incorrect, the parser immediately reports the nature and location of the issue. For instance, writing self.price => 0 instead of self.price >= 0 triggers a descriptive warning in the BESSER Web Modeling Editor as shown in the picture below
Important: this step can be used independently of the interpreter to verify constraint correctness early in the modeling process.
Interpret It: Evaluating Constraints at the Object Level
Once constraints have been parsed and syntactically validated, the B-OCL interpreter assesses whether a given set of B-UML object instances (BESSER Object diagram) satisfies them.
Internally, the interpreter transforms each constraint into a logical expression, populates it with values from the object model, and executes it. For example, if the value of pages attribute is set to 0, then the constraint self.pages > 0, when evaluated against a book instance with pages = 0, becomes 0 > 0, which evaluates to False. The interpreter reports results for each constraint individually, specifying whether it passed or failed, providing actionable feedback for targeted corrections as shown below:
Generate It: From OCL Constraints to Executable Code
Perhaps the most impactful capability of B-OCL is automated code generation. A constraint written once in OCL is enforced directly in the generated code, without needing to be re-implemented by hand for each target technology. The technology-agnostic AST produced by the parser is used by BESSER’s code generators to render constraint enforcement logic for each target platform. For example, the constraint for Book class is translated into Pydantic field validator as shown below:
class Book ( BaseModel ):
pages : int
title : str
@field_validator ( ‘ pages ‘)
@classmethod
def validate_pages_1 ( cls , v):
“”” OCL Constraint : book_positive_pages “””
if not (v > 0) :
raise ValueError ( ‘ pages must be > 0 ‘)
return v
Support is currently available for two generators, Pydantic and Django, with more generators joining the party soon!
What’s Next?
Several planned improvements are on the roadmap:
- Formal verification via an intermediate mapping from OCL to Alloy.
- Additional code generators targeting SQL and incremental constraint checking.
- Extended code generation for multi-property and complex constraints.
- and much more 🙂
Ready to give it a try? Check it out here Looking forward to your feedback and contributions!
Recent Comments