4. Student Plans
String name
Plan plan
Student
String code
Student owner
List<Exam> exams
Plan
Plan plan
String course
String code
List<Grade> exams
Exam
Exam exam
int attempt
String value
Grade
1
1
1
0..1
1 0..1
5. Student Plans
public class Student {
private String name;
private Plan plan;
}
public class Plan {
private String code;
private Student owner;
private List<Exam> exams;
}
public class Exam {
private String code;
private String course;
private Plan plan;
private List<Grade> grades;
}
public class Grade {
private String value;
private int attempt;
private Exam exam;
}
6. Student Plans
public static Student student(String studentName, String planCode, Exam... exams) {
Student student = new Student(studentName);
Plan plan = new Plan(student, planCode);
student.setPlan( plan );
plan.setOwner( student );
for ( Exam exam : exams ) {
exam.setPlan( plan );
plan.getExams().add ( exam );
}
return student;
}
public static Exam exam( String course, String... grades) {
Exam exam = new Exam( course );
int attempt = 1;
for ( String letter : grades) {
exam.getGrades().add(new Grade(exam, letter, attempt));
attempt++;
}
return exam;
}
8. Student Plans
private static final String A = "A";
private static final String B = "B";
private static final String C = "C";
private static final String D = "D";
private static final String E = "E";
private static final String F = "F";
9. Student Plans
private static final String A = "A";
private static final String B = "B";
private static final String C = "C";
private static final String D = "D";
private static final String E = "E";
private static final String F = "F";
public void create(KieSession ksession) {
Student darth = student( "Darth", "dp2015",
exam( "dpe01", "Jedi Studies", A),
exam( "dpe02", "Force", B ),
exam( "dpe03", "Meditation", D, C) );
Student yoda = student( "Yoda", "yp2015",
exam( "ype01", "Jedi Studies", A),
exam( "ype02", "Force", A ),
exam( "ype03", "Meditation", A) );
Student luke = student( "Luke", "lp2015",
exam( "lpe01", "Jedi Studies", C, B),
exam( "lpe02", "Force", B ),
exam( "lpe03", "Meditation", F, C) );
}
10. Student Plans
private static final String A = "A";
private static final String B = "B";
private static final String C = "C";
private static final String D = "D";
private static final String E = "E";
private static final String F = "F";
public void create(KieSession ksession) {
Student darth = student( "Darth", "dp2015",
exam( "dpe01", "Jedi Studies", A),
exam( "dpe02", "Force", B ),
exam( "dpe03", "Meditation", D, C) );
Student yoda = student( "Yoda", "yp2015",
exam( "ype01", "Jedi Studies", A),
exam( "ype02", "Force", A ),
exam( "ype03", "Meditation", A) );
Student luke = student( "Luke", "lp2015",
exam( "lpe01", "Jedi Studies", C, B),
exam( "lpe02", "Force", B ),
exam( "lpe03", "Meditation", F, C) );
ksession.insert( darth );
ksession.insert( yoda );
ksession.insert( luke );
}
12. The Problem
• The information provided is Object Oriented which is a form
of graph and uses references.
• Traditional Production Rule Systems are relational, they
cannot see or use references.
• Users must then map their model to a relational one.
13. Student Plans
public class Student {
private String name;
private String plan;
}
public class Plan {
private String code;
private String owner;
}
14. Student Plans
public class Student {
private String name;
private String plan;
}
public class Plan {
private String code;
private String owner;
}
public class Student {
private String name;
private Plan plan;
}
public class Plan {
private String code;
private Student owner;
private List<Exam> exams;
}
15. Student Plans
public class Grade {
private String value;
private int attempt;
private String exam;
}
public class Exam {
private String code;
private String course;
private String plan;
}
16. Student Plans
public class Grade {
private String value;
private int attempt;
private String exam;
}
public class Exam {
private String code;
private String course;
private String plan;
}
public class Exam {
private String code;
private String course;
private Plan plan;
private List<Grade> grades;
}
public class Grade {
private String value;
private int attempt;
private Exam exam;
}
17. Student Plans
• Email all the “Big Data” people their grades.
rule R1 when
$student : Student ()
$plan : Plan ( owner == $student.name )
$exam : Exam( plan == $plan.code, course == ”Big Data” )
$grade : Grade( exam == $exam.code )
then
// RHS
end
26. Requirements
• Functionality
• Access child objects via references
• React to child objects
• List comprehension
• Iterate one to many relations
• Support reactive and passive operations
• Implementation
• Syntax Extensions
• Rete Extensions
• Object integration
27. From
• Implementation
• Introduces one new keyword “from”.
• Requires new Rete node.
• Requires expression evaluation sub system.
• Uses dot ‘.’ as reference accessor.
• with type safe javascript like syntax (MVEL).
• Functionality
• Allows access to nested objects.
• Dot ‘.’ accessor is access and return only.
• It does not provide list comprehension.
• List comprehension is performed by the node on the return result.
• Is passive only, no reactivity.
rule R2 when
$student : Student ( $plan : plan )
$exam: Exam( course == ”Big Data” ) from $plan.exams
$grade: Grade() from $exam.grades
then
/∗ RHS ∗/
end
28. From
rule R2 when
$student : Student ( $plan : plan )
$exam: Exam( course == ”Big Data” ) from $plan.exams
$grade: Grade() from $exam.grades
then
/∗ RHS ∗/
end
From
From
OTN
Root
Student
RTN
$student : Student ( $plan : plan ) // “from” the Working Memory
$exam: Exam( course == ”Big Data” ) from $plan.exams
$grade: Grade() from $exam.grades
29. From
public void propagateLeft(Tuple tuple) {
leftMemory.addTuple(tuple);
for ( Object object : rightMemory.getObjects() ) {
if ( expr.eval(tuple, object) ) {
childNode.propagateLeft(new Tuple(tuple, object));
}
}
}
30. From
public void propagateLeftInsert(Tuple tuple) {
leftMemory.addTuple(tuple);
Object result = expr.equals( tuple.get(index));
if ( result instanceof Collection) {
for ( Object o : ((Collection)result)) {
propagateLeftIfAllowed(tuple, o);
}
} else {
propagateLeftIfAllowed(tuple, result);
}
}
private void propagateLeftIfAllowed(Tuple tuple, Object o) {
if ( isAllowed( tuple, o ) ) {
childNode.propagateLeftInsert(new Tuple(tuple, o));
}
}
public void propagateLeftInsert(Tuple tuple) {
leftMemory.addTuple(tuple);
for ( Object object : rightMemory.getObjects() ) {
if ( expr.eval(tuple, object) ) {
childNode.propagateLeft(new Tuple(tuple, object));
}
}
}
31. From
public class FromNode extends Node {
private LeftMemory leftMemory;
private CompiledExpression expr;
private int index;
public void propagateLeftInsert(Tuple tuple) {
leftMemory.addTuple(tuple);
Object result = expr.equals( tuple.get(index));
if ( result instanceof Collection) {
for ( Object o : ((Collection)result)) {
propagateLeftIfAllowed(tuple, o);
}
} else {
propagateLeftIfAllowed(tuple, result);
}
}
private void propagateLeftIfAllowed(Tuple tuple, Object o) {
if ( isAllowed( tuple, o ) ) {
childNode.propagateLeftInsert(new Tuple(tuple, o));
}
}
public void propagateRightInsert(Object object) {
// From has no right propagation
}
}
32. Passive OOPath
• Implementation
• Re-use ‘from’ node
• Introduces no Rete changes.
• Requires expression evaluation sub system.
• Uses forward slash ‘/’ as reference accessor.
• Introduce XPath inspired syntax
• Syntax change must be added to Patterns
• Functionality
• Allows access to nested objects.
• forward slash ‘/’ accessor performs list comprehension
for each visited reference.
• List comprehension is also performed by the node on the return result.
• Is passive only, no reactivity.
rule R3 when
Student( $grade: /plan/exams{course == ”Big Data”}/grades )
then
/∗ RHS ∗/
end
33. R1, R2, R3
rule R1 when
$student : Student ()
$plan : Plan ( owner == $student.name )
$exam : Exam( plan == $plan.code, course == ”Big Data” )
$grade : Grade( exam == $exam.code )
then
// RHS
end
rule R2 when
$student : Student ( $plan : plan )
$exam: Exam( course == ”Big Data” ) from $plan.exams
$grade: Grade() from $exam.grades
then
/∗ RHS ∗/
end
rule R3 when
Student( $grade: /plan/exams{course == ”Big Data”}/grades )
then
/∗ RHS ∗/
end
34. OOPath Syntax
• Access by index
• Inline cast for type safety
• Indexed back reference
• Variable back reference
• Back tracking
• Out of Pattern use
Student( $grade : /plan/exams[0]{ course == ”Big Data”}/grades )
Student( $grade : /plan/exams{ #PracticalExam, lab == ”hazard safe”,
course == ”Material Explosions”}/grades )
A( $var: /b/c/d{ f1 == ../../f2}/e ) // the ../../ back references to the ‘b’ field access
A( $var: /$b : b/c/d{ f1 == $b.f2}/e ) // the $b is inline bound for later use
A( $var: /$b : b/c/d{ f1 == $b.f2}/$b/f2 ) // $var is bound to results of the f2 access
$student : Student()
$grade : /$student/plan/exams{course == ”Big Data”}/grades;
35. Advanced OOPath Usage
• Use existing Drools syntax and functionality
• Colon ‘:’ provides Pattern and field binding
• Colon with equals ‘:=‘ provides unification
• POSL-like support for position and slotted
• Arguments can be named or positional.
• Positional arguments must come first and be delimited
with a semi colon ‘;’ at the end.
• Positional arguments are always unified, compared to
named arguments which can be bound ’:’ or unified ’:=’.
36. Advanced OOPath Usage
• Transitive closure
query isContainedIn ( Thing $x , Thing $y )
/$y/$x := children ;
or
/$y/$z := children; and isContainedIn($x, $z;) )
end
37. Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
query isContainedIn ( Thing $x , Thing $y )
/$y/$x := children ;
or
/$y/$z := children; and isContainedIn($x, $z;) )
end
query isNotContainedIn ( Thing $x , Thing $y )
not( isContainedIn( $x, $y; ) )
end
38. Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
• Accumulation
query isContainedIn ( Thing $x , Thing $y )
/$y/$x := children ;
or
/$y/$z := children; and isContainedIn($x, $z;) )
end
query isNotContainedIn ( Thing $x , Thing $y )
not( isContainedIn( $x, $y; ) )
end
query countItems ( Thing $y)
acc( isContainedIn( $x, $y; );
count( $x ); )
end
39. Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
• Accumulation
• Structural Control
query isContainedIn ( Thing $x , Thing $y )
/$y/$x := children ;
or
/$y/$z := children; and isContainedIn($x, $z;) )
end
query isNotContainedIn ( Thing $x , Thing $y )
not( isContainedIn( $x, $y; ) )
end
query countItems ( Thing $y)
acc( isContainedIn( $x, $y; );
count( $x ); )
end
query childrenOrderedByEdgeCount( Parent $x, Child $c0, int index )
/$x/$c1 : children[index]{children.size <= $c0.children. size };
childrenOrderedByEdgeCount ( $x , $c1 , index + 1; )
end
40. Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
• Accumulation
• Structural Control
• Combined Graph and Relational
query isContainedIn ( Thing $x , Thing $y )
/$y/$x := children ;
or
/$y/$z := children; and isContainedIn($x, $z;) )
end
query isNotContainedIn ( Thing $x , Thing $y )
not( isContainedIn( $x, $y; ) )
end
query countItems ( Thing $y)
acc( isContainedIn( $x, $y; );
count( $x ); )
end
query childrenOrderedByEdgeCount( Parent $x, Child $c0, int index )
/$x/$c1 : children[index]{children.size <= $c0.children. size };
childrenOrderedByEdgeCount ( $x , $c1 , index + 1; )
end
query findChildrenWithMatchingEdgeCounts( Parent $x, Child $c0, int index )
/$x/$c := children[index];
// relational search
exists( Thing( children . size == $c. children . size ) )
findChildrenWithMatchingEdgeCounts( $x , $c1 , index + 1;)
end
41. Reactive OOPath
• Implementation
• New reactive ‘from’ node.
• ReactiveObject Object integration.
• List integration.
• Functionality
• Uses the OOPath syntax, but now all ‘/‘ are reactive.
42. Reactive OOPathpublic class ReactiveFromNode extends Node {
private LeftMemory leftMemory;
private CompiledExpression expr;
private int index;
public void propagateLeftInsert(Tuple tuple) {
leftMemory.addTuple(tuple);
Object result = expr.equals( tuple.get(index) );
if ( result instanceof ObservableList) {
ObservableList list = (ObservableList) result;
ListObserver observer = new ListObserver(tuple);
tuple.setObserver(observer);
list.addObserver( observer );
for ( Object o : list ) {
propagateLeftIfAllowed(tuple, o);
}
} else {
propagateLeftIfAllowed(tuple, result);
}
}
public void propagateLeftIfAllowed(Tuple tuple, Object o) {
ReactiveObject r = getReactiveObject(o);
r.addTuple(tuple);
if ( isAllowed( tuple, o ) ) {
childNode.propagateLeftInsert(new Tuple(tuple, o));
}
}
public void propagateChildLeftTupleDelete(Tuple tuple) {
tuple.unlink();
childNode.propagateLeftDelete(tuple);
}
43. ReactiveObject
public class ReactiveObject {
private List<Tuple> tuples = new ArrayList<Tuple>();
private Object object;
public ReactiveObject(Object object) {
this.object = object;
}
public void addTuple(Tuple tuple) {
tuples.add(tuple);
}
public void removeTuple(Tuple tuple) {
tuples.remove(tuple);
}
protected void notifyUpdate() {
for ( Tuple tuple : tuples ) {
ReactiveFromNode node = (ReactiveFromNode) tuple.getNode();
for ( Tuple childTuple : tuple.getChildren() ) {
if ( childTuple.getObject() == object ) {
node.propagateChildLeftTupleDelete(childTuple);
node.propagateLeftIfAllowed(tuple, object);
break;
}
}
}
}
}
44. ReactiveObject
public class MyClass {
private String name;
private ReactiveObject delegate = new ReactiveObject(this);
protected void setName(String name) {
this.name = name;
delegate.notifyUpdate()
}
}
public class MyClass extends ReactiveObject {
private String name;
public void MyClass() {
super(name);
}
protected void setName(String name) {
this.name = name;
notifyUpdate()
}
}
45. Benchmark
rule R1 when
$student : Student ()
$plan : Plan ( owner == $student.name )
$exam : Exam( plan == $plan.code, course == ”Big Data” )
$grade : Grade( exam == $exam.code )
then
// RHS
end
rule R2 when
$student : Student ( $plan : plan )
$exam: Exam( course == ”Big Data” ) from $plan.exams
$grade: Grade() from $exam.grades
then
/∗ RHS ∗/
end
rule R3 when
Student( $grade: /plan/exams{course == ”Big Data”}/grades )
then
/∗ RHS ∗/
end
49. Conclusion and Future Work
• Integrated bytecode weavers for ReactiveObject
• Externalise ReactiveObject
• Use PropertyChangeListener
• Make work with PropertyReactive