Features · Business Rules in OCL

Business Rules modeling in BESSER.

Define, validate and enforce Object Constraint Language constraints directly on your B-UML models. Write an invariant or pre/post condition once; B-OCL parses it, checks it against your object model, and propagates it into every generated artifact automatically.

editor.besser-pearl.org — OCL constraints
BESSER OCL constraint editor
See it in action

One constraint. Multiple outputs.

The same OCL invariant, defined once at the B-UML structural model level, rendered as executable enforcement logic for Pydantic (left) and Django (right).

Pydantic
pydantic.py
class Book(BaseModel):
    release: date
    genre: Genre
    price: float
    pages: int
    title: str
    stock: int
    id: int  # id created
    authors: List[int]  # N:M Relationship
    library: List[int]  # N:M Relationship

    @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
Django
django.py

class Book(models.Model):
    """
    Represents a book in the system.
    """
    title = models.CharField(max_length=255)
    pages = models.IntegerField()
    stock = models.IntegerField()
    price =  models.FloatField()
    release = models.DateField()
    genre = models.CharField(max_length=255, choices=Genre.choices)
    authors = models.ManyToManyField(
        'Author', related_name='books')
    library = models.ManyToManyField(
        'Library', related_name='books')

    class Meta:
        verbose_name = "Book"
        verbose_name_plural = "Books"

    def __str__(self):
        """
        Returns a string representation of the book.
        """
        return str(self.title)

    def clean(self):
        """
        Validates the OCL constraints defined on Book.
        """
        super().clean()
        errors = {}
        if not (self.pages > 0):
            errors.setdefault('pages', []).append('pages must be > 0')
        if errors:
            raise ValidationError(errors)
Capabilities

Everything you need to model, validate and enforce OCL constraints.

Walkthrough

Watch it end to end

Write an OCL constraint on a class diagram, trigger the Quality Check to validate it against an object model.

editor.besser-pearl.org — define → validate

Full OCL metamodel

Every OCL constraint written in BESSER is internally represented as an instance of the OCL metamodel; a set of Python classes that mirrors the OCL standard. This metamodel-backed representation decouples constraint definition from any specific target technology, enabling the same constraint to be interpreted, validated, and rendered for multiple output frameworks without rewriting.

  • Constraints stored as OCL metamodel instances
  • Decoupled from any target technology
  • Shared AST reused across interpreter and all code generators
Read the docs

ANTLR-based parser

The B-OCL parser is built with ANTLR, a widely used parser generator for language recognition. The generated lexer first tokenizes the OCL expression; the parser then constructs a parse tree from those tokens according to the OCL grammar. A visitor traverses the parse tree and populates an abstract syntax tree whose nodes are instances of the OCL metamodel, preserving the full structure and semantics of the original expression.

  • ANTLR-generated lexer, parser and visitor
  • Produces a typed AST conforming to the OCL metamodel
  • Supports invariants, pre/post conditions and collection operations

Live syntactic validation

Syntactic validation can be triggered in two ways: through the dedicated Quality Check button in the BESSER Web Modeling Editor, or programmatically via the Python API. When an error is detected (e.g., an incorrect comparison operator) the parser reports a descriptive warning message pinpointing the nature and location of the issue, enabling the user to correct the constraint before proceeding to interpretation or code generation.

  • Quality Check button triggers validation in the web editor
  • Python API for programmatic validation
  • Descriptive messages with error location

Object-level interpretation

Once constraints are defined and syntactically validated, the interpreter takes two inputs: (1) the AST produced by the parser and (2) a B-UML object model. It evaluates whether the instantiated objects satisfy every constraint. For each constraint, the interpreter builds one or more logical expressions, populates them with values from the object model, and executes them. Results are reported per constraint, giving actionable feedback that enables targeted correction of the model or the instance under test.

  • Evaluates constraints against B-UML object instances
  • Per-constraint pass/fail results
  • Supports invariants and collection operations (ForAll, exists, select, reject)

Automated code generation

The B-OCL code generators use the same technology-agnostic AST produced by the parser and render it for each target framework. The Pydantic generator produces a field_validator decorator that raises a ValueError at object creation time whenever a constraint is violated. The Django generator produces a clean() method that reports violations through ValidationError. Because both generators share the same AST, adding a new target framework requires only a new rendering layer.

  • Pydantic: field_validator raising ValueError on violation
  • Django: clean() method reporting ValidationError