I’d like to get some hints to improve the rules
of my simple planning system.
My simple planning system is derived from the
HelloWorld Drools Project. The job of my planning system is to calculate startTime
and endTime as function of duration and predecessors for each task. Each task
has the fields
long duration;
Set<Task>
predesessors;
long startTime;
long endTime;
For each task the rule (endTime = startTime +
duration) should hold. If a task has no predecessors, then its startTime should
be 0. If a task has predecessors, then is should start at the latest endTime of
all predecessors.
These are my DRL-rules:
rule "Calc EndTime"
no-loop true
when
$t : Task()
then
$t.setEndTime(
$t.getStartTime() + $t.getDuration() );
System.out.println(
"Drools: Set " + $t.getName() + ".EndTime to " +
$t.getEndTime() );
update( $t );
end
rule "Calc StartTime without
predecessors"
lock-on-active true
when
$t : Task(predecessorCount ==
0)
then
$t.setStartTime( 0
);
System.out.println(
"Drools: " + $t.toString() + " can start immediately" );
update( $t );
end
rule "Calc StartTime with
predecessors"
when
$t : Task(predecessorCount > 0,
$predecessors : predecessors )
# Checking EndTime > 0 for all
predecessors means that all EndTimes are
# initialy calculated. This is not
what we realy want. Actually we'd like
# to recalculate the successors
EndTime, when ever it is needed.
forall (
$succTask
: Task( this == $t )
$predTask
: Task( this memberOf $predecessors, endTime > 0 )
)
$endTime : Number()
from accumulate(
$p : Task() from $predecessors,
max($p.getEndTime()) )
then
$t.setStartTime(
$endTime.longValue() );
System.out.println(
"Drools: " + $t.toString() + " has new StartTime" );
# !!!! If we did an
update($t); here, we would get an infinite recursion.
end
My TestClass creates three tasks: task0, task1 and
task2. Each task has an initial duration and (task0, task1) are predecessors of
task2. It is important that this example has no circular dependencies;
otherwise the rules, mentioned above, couldn’t be applied.
After fireAllRuels() the endTime of task2 is
calculated wrong, so obviously the rule "Calc EndTime" should be
activated. Is the rule-attribute (no-loop = true) not the right solution to
avoid circularity here?
Then the duration of task0 is updated outside of the
rule engine. After a second fireAllRuels() the endTime of task0 is recalculated,
but task2 is not recalculated at all. How can I tell the rule engine, that a
task depends on its predecessors?
I'd appreciate any input that could help me making
this example work and if it works very efficient on a big number of tasks
it’s brilliant. If anybody is interested in my TestClass, to run this
example with some logging, please tell me.
Ralph Ammon