JBoss.orgCommunity Documentation
When the field of a fact is a collection it is possible to bind and reason over
all the items in that collection on by one using the from
keyword.
Nevertheless, when it is required to browse a graph of object the extensive use of the
from
conditional element may result in a verbose and cubersome syntax
like in the following example:
Example 10.1. Browsing a graph of objects with from
rule "Find all grades for Big Data exam" when
$student: Student( $plan: plan )
$exam: Exam( course == "Big Data" ) from $plan.exams
$grade: Grade() from $exam.grades
then /* RHS */ end
In this example it has been assumed to use a domain model consisting of a
Student
who has a Plan
of study: a Plan
can have zero or more Exam
s and an Exam
zero or more
Grade
s. Note that only the root object of the graph (the Student
in this case) needs to be in the working memory in order to make this works.
By borrowing ideas from XPath, this syntax can be made more succinct, as XPath has a
compact notation for navigating through related elements while handling collections and
filtering constraints. This XPath-inspired notation has been called OOPath
since it is explictly intended to browse graph of objects. Using this notation the former
example can be rewritten as it follows:
Example 10.2. Browsing a graph of objects with OOPath
rule "Find all grades for Big Data exam" when
Student( $grade: /plan/exams{course == "Big Data"}/grades )
then /* RHS */ end
Formally, the core grammar of an OOPath
expression can be defined in EBNF notation in this way.
OOPExpr = "/" OOPSegment { ( "/" | "." ) OOPSegment } ;
OOPSegment = [ID ( ":" | ":=" )] ID ["[" Number "]"] ["{" Constraints "}"];
In practice an OOPath
expression has the following features.
It has to start with /
.
It can dereference a single property of an object with the .
operator
It can dereference a multiple property of an object using the /
operator.
If a collection is returned, it will iterate over the values in the collection
While traversing referenced objects it can filter away those not satisfying one or more constraints, written as predicate expressions between curly brackets like in:
Student( $grade: /plan/exams{course == "Big Data"}/grades )
Items can also be accessed by their index by putting it between square brackets like in:
Student( $grade: /plan/exams[0]/grades )
To adhere to Java convention OOPath indexes are 0-based, compared to XPath 1-based
At the moment Drools is not able to react to updates involving a deeply nested traversed
during the evaluation of an OOPath
expression. To make these objects reactive
to changes at the moment it is necessary to make them extend the class
org.drools.core.phreak.ReactiveObject
. It is planned to overcome this
limitation by implementing a mechanism that automatically instruments the classes belonging
to a specific domain model.
Having extendend that class, the domain objects can notify the engine when one of
its field has been updated by invoking the inherited method notifyModification
as in the following example:
Example 10.3. Notifying the engine that an exam has been moved to a different course
public void setCourse(String course) {
this.course = course;
notifyModification(this);
}
In this way if an exam is moved to a different course, the rule is re-triggered and the list of grades matching the rule recomputed.