Jesvin Jose
Jesvin Jose

Reputation: 23088

Why is this complex condition not working?

I am trying to detect conflicting periods in a timetable: if a teacher teaches in a Period (timeStart=1400,timeEnd=1500,dayOfWeek="Monday",class="c1"), he cannot teach Period(1305,1405,dayOfWeek="Monday",class="c2"), because he will have to be at two classes at once for a time interval (yes, it's constrived).

An example of one period and whether other periods conflict:

          ---------                left_period (timeStart=1400,timeEnd=1500)

 ---------                        right_period (1300,1400) NO conflict
  ---------                       right_period (1305,1405) conflict
                   ---------      right_period (1500,1600) NO conflict
                 ---------        right_period (1555,1555) NO conflict

So I tried detecting such periods based on timeStart and timeEnd values and asserting such conflicts as PeriodTimeConflict(left_period,right_period).

rule "insertPeriodTimeConflict"
    when
    $day_of_week : DayOfWeek()
    $left_period : Period(  $lp_id : id,
                dayOfWeek==$day_of_week,
                $lp_time_start : timeStart,
                $lp_time_end : timeEnd
                )
    $right_period : Period( id > $lp_id,
                dayOfWeek==$day_of_week,
                (   (timeStart>=$lp_time_start && timeStart<$lp_time_end)||
                    (timeEnd>$lp_time_start && timeEnd<=$lp_time_end)
                    )
                )
    then
    insertLogical(new PeriodTimeConflict($left_period,$right_period));
end

However, not even a single conflict is ever detected and Drools is silent on this matter. What is wrong with my rule?

Upvotes: 0

Views: 250

Answers (1)

mike9322
mike9322

Reputation: 634

Discover the joy of the Fusion temporal operators. Your case is a perfect example for their use.

First, you need to define a duration member on your Period class. Your constructor can calculate the duration from the start and end time, e.g.

private final int duration;
// ... other fields

public Period(int id, DayOfWeek dayOfWeek, Date timeStart, Date timeEnd) {
  // ... set other fields
  duration = timeEnd.getTime() - timeStart.getTime();
}

Now declare Period as an event in your DRL:

declare Period
  @role(event)
  @timestamp(startTime)
  @duration(duration)
end

Then your rule can easily determine whether two periods overlap:

rule "detect-overlap"
  when
    $left_period : Period( )
    $right_period : Period( this overlappedby $left_period )
  then
    ...
end

Upvotes: 1

Related Questions