This document describes the various concepts and models that are part of the Otter rules engine module. It serves as an introduction course before you can integrate it within your application following the rules engine implementation guide.
As covered in the package documentation, the rules engine is a client-based mechanism that evaluates a list of Rulesets to define actions to apply based on the application's context.
The Ruleset
object exposes a sorted list of rules to process one after the other.
It may include optional conditions to enable or disable the whole Ruleset based on simple triggers such as:
validityRange
: whether the date of execution of the Ruleset is part of the date range of executionlinkedComponents
: whether specific components are part of the page (see linked components)
If any of the rules belonging to the same ruleset fails due to an error, none of the resulting actions from any of these rules will be executed as they may be deeply linked.
Rulesets are described by the ruleset schema exposed in the @o3r/rules-engine package.
A Rule
contains a set of conditions that outputs a list of actions after processing.
These conditions and actions are referred to as blocks and follow a tree architecture:
a block can be an IfElseBlock
(branch of the tree) or an ActionBlock
(leaf of the tree).
The IfElseBlock
contains conditions to meet as well as the blocks to execute depending on the success or failure of
the condition.
The conditions can be linked via AND
and OR
expressions.
An IfElseBlock
can result in another IfElseBlock
or an ActionBlock
.
This allows for nested conditions as demonstrated by the nested condition Ruleset example.
Note
If no condition is defined in the IfElseBlock
, its successElements
will always be executed.
A Rule
also provides information on the variable it needs (also known as facts) in to optimize the reevaluation of its conditions:
inputRuntimeFacts
: the input runtime facts the rule is based onoutputRuntimeFacts
: the runtime facts that are updated/set by the rule
The default action types and their object structure definitions can be found in the structure definition file.
Note that each rule is identified by a unique id
.
Each condition in an IfElseBlock
can contain up to three different parts:
- a left operand (FACT, RUNTIME_FACT or LITERAL)
- an operator
- [optional] a right operand (FACT, RUNTIME_FACT or LITERAL)
The operator is a method that will evaluate whether a condition is met. It can take up to two operands.
While the Otter framework already provides a set of operators ready for use, it is also possible to use your own operator that will fit your needs. You can check on the custom operator documentation as well as the ruleset generation documentation if you want to generate metadata for your own operators.
The exhaustive list of exposed operators is available in the rules.operators.metadata.json
.
Note that this file is automatically generated via our extractors and matches the list of operators exposed
in the module,
which is why it is only available in the npm artifact.
Note
For the operators comparing a text variable to a pattern (such as matchesPattern
, oneMatches
, and allMatch
),
we support the ES RegExp /^myRegExp.*$/i
(containing the pattern and optional flags) or just the RegExp content ^myregexp.*$
.
The special characters used in the pattern should contain a double backslash (\\
).
For example, to check if a string contains a \t
, the pattern would need to include \\t
.
Also, to avoid the wrong detection of an ES RegExp instead of RegExp content, a content beginning with a slash /
character
(such as a path /path/to/file
) should be preceded by a double backslash \\
(for example \\/path/to/file
)
The ActionBlock defines the action to be executed. Each Action is identified by a unique ID, specifying the process to trigger and any associated payload.
The Otter framework provides a few built-in actions linked to Otter-specific features:
UPDATE_CONFIG
modifies the configuration of a configurable component (provided by @o3r/configuration)UPDATE_ASSET
overrides the path of an asset which uses theo3rDynamicContent
pipe (provided by @o3r/dynamic-content)UPDATE_LOCALISATION
substitutes the translation of a key with the one from another key. (@o3r/localization)UPDATE_PLACEHOLDER
injects HTML code in a specific placeholder (@o3r/components)
If you need your own specific action, follow the custom action guide.
Note
The actions handled by the rules engine need to be registered in your application to be recognized by the engine. This ensures you only import packages you actually need.
A fact is a stream of values.
During a rule execution, its conditions will be evaluated using the latest fact value(s).
Every fact can be identified by its id
property and exposes a value$
stream that will trigger a new evaluation
of the Ruleset it has been linked for every value it emits.
This allows a big optimization since the rules engine will react to a fact change in order to execute only the subset
of rules that relies on this fact.
Facts can be defined inside the code of the application, as described in the custom fact documentation, or can be defined by the ruleset itself.
In that case, we call it a runtime fact.
Warning
A rule depending on a fact will be re-evaluated whenever this fact is updated. If you use a fact that will be updated a lot in a short time frame, you may encounter performance issues.
You can avoid this by:
- disabling the ruleset if the component impacted by the rule is missing from the page (see linkedComponents)
- avoiding timer facts with a high frequency (1s for example)
A runtime fact is a temporary fact that is only available in the Ruleset it is used in. It can be the result of a rule
SET_FACT
action providing it has been declared in the rule outputRuntimeFacts
.
The runtime fact can then be used as an input for another rule condition provided it has been declared in the rule's
inputRuntimeFacts
.
You can follow the runtime-facts example to help you use it in your Ruleset.
Warning
The runtime fact is only accessible in the Ruleset where it has been defined. If you create two runtime facts in two different Rulesets, they will be two different entities isolated from each other. The runtime fact's value is reset between two executions of the Ruleset.
The Otter rules engine exposes its own o3rCurrentTime
fact which represents the current time.
It is provided by the rules engine since two operators (dateInNextMinutes
and dateNotInNextMinutes
) need it to
execute.
The o3rCurrentTime
fact implementation can be overridden at build time.
For more information, you can follow the documentation dedicated to built-in facts.