package com.sample;
import static org.junit.Assert.assertEquals;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.rule.FactHandle;
import org.junit.Test;
/**
- This is a sample class to launch a rule.
*/
public class DroolsTest {
List notCovered = new ArrayList();
List partiallyCovered = new ArrayList();
List totallyCovered = new ArrayList();
@Test
public void testExecute() throws Exception
{
// load up the knowledge base
KnowledgeBase kbase = readKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ksession.setGlobal("totallyCovered", totallyCovered);
ksession.setGlobal("partiallyCovered", partiallyCovered);
ksession.setGlobal("notCovered", notCovered);
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
// Staffing required at interval 100
IntervalRequirement ir100 = new IntervalRequirement(100, 2);
ksession.insert(ir100);
// Staffing required at interval 101
IntervalRequirement ir101 = new IntervalRequirement(101, 2);
ksession.insert(ir101);
// Staffing required at interval 102
IntervalRequirement ir102 = new IntervalRequirement(102, 2);
ksession.insert(ir102);
// Staffing required at interval 103
IntervalRequirement ir103 = new IntervalRequirement(103, 2);
ksession.insert(ir103);
ShiftAssignment sa = new ShiftAssignment();
sa.setShiftStartTime(100);
FactHandle saHandle = null;
// Covers 1 interval
clearGlobals();
sa.setShiftEndTime(101);
System.out.println("ShiftAssignment set from " + sa.getShiftStartTime() + " to " + sa.getShiftEndTime());
saHandle = ksession.insert(sa);
ksession.fireAllRules();
assertEquals("notCovered with " + sa, 3, notCovered.size());
assertEquals("totallyCovered with " + sa, 0, totallyCovered.size());
assertEquals("partiallyCovered with " + sa, 1, partiallyCovered.size());
// Covers 3 intervals
clearGlobals();
sa.setShiftEndTime(103);
System.out.println("ShiftAssignment set from " + sa.getShiftStartTime() + " to " + sa.getShiftEndTime());
ksession.update(saHandle, sa);
ksession.fireAllRules();
assertEquals("notCovered with " + sa, 1, notCovered.size());
assertEquals("totallyCovered with " + sa, 0, totallyCovered.size());
assertEquals("partiallyCovered with " + sa, 3, partiallyCovered.size());
// Covers 2 intervals
clearGlobals();
sa.setShiftEndTime(102);
System.out.println("ShiftAssignment set from " + sa.getShiftStartTime() + " to " + sa.getShiftEndTime());
ksession.update(saHandle, sa);
ksession.fireAllRules();
assertEquals("notCovered with " + sa, 2, notCovered.size());
assertEquals("totallyCovered with " + sa, 0, totallyCovered.size());
assertEquals("partiallyCovered with " + sa, 2, partiallyCovered.size());
// Covers 4 intervals
clearGlobals();
sa.setShiftEndTime(104);
System.out.println("ShiftAssignment set from " + sa.getShiftStartTime() + " to " + sa.getShiftEndTime());
ksession.update(saHandle, sa);
ksession.fireAllRules();
assertEquals("notCovered with " + sa, 0, notCovered.size());
assertEquals("totallyCovered with " + sa, 0, totallyCovered.size());
assertEquals("partiallyCovered with " + sa, 4, partiallyCovered.size());
// Covers 1 interval
clearGlobals();
sa.setShiftEndTime(101);
System.out.println("ShiftAssignment set from " + sa.getShiftStartTime() + " to " + sa.getShiftEndTime());
ksession.update(saHandle, sa);
ksession.fireAllRules();
assertEquals("notCovered with " + sa, 3, notCovered.size());
assertEquals("totallyCovered with " + sa, 0, totallyCovered.size());
assertEquals("partiallyCovered with " + sa, 1, partiallyCovered.size());
ksession.dispose();
logger.close();
}
private void clearGlobals()
{
totallyCovered.clear();
partiallyCovered.clear();
notCovered.clear();
}
private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
Reader drlSr = new StringReader(DRL);
kbuilder.add(ResourceFactory.newReaderResource(drlSr), ResourceType.DRL);
KnowledgeBuilderErrors errors = kbuilder.getErrors();
if (errors.size() > 0) {
for (KnowledgeBuilderError error: errors)
{
System.err.println(error);
}
throw new IllegalArgumentException("Could not parse knowledge: " + errors);
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
return kbase;
}
public class IntervalRequirement
{
private int interval;
private int staffingRequired;
public IntervalRequirement(int interval, int staffingRequired)
{
super();
this.interval = interval;
this.staffingRequired = staffingRequired;
}
public int getInterval()
{
return interval;
}
public int getStaffingRequired()
{
return staffingRequired;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName()).append(": ")
.append("interval: ").append(this.interval)
.append(", staffingRequired: ").append(this.staffingRequired)
;
return sb.toString();
}
}
public class ShiftAssignment
{
private int shiftStartTime = -1;
private int shiftEndTime = -1;
public ShiftAssignment() {
}
public int getShiftStartTime()
{
return this.shiftStartTime;
}
public int getShiftEndTime()
{
return this.shiftEndTime;
}
public void setShiftStartTime(int shiftStartTime)
{
this.shiftStartTime = shiftStartTime;
}
public void setShiftEndTime(int shiftEndTime)
{
this.shiftEndTime = shiftEndTime;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("ShiftAssignment: ")
.append(" ")
.append("st: ").append(this.shiftStartTime).append(" end: ").append(this.shiftEndTime);
return sb.toString();
}
}
private static final String DRL =
"package com.lfsoscience.planner.solver \n"
+ "dialect \"java\" \n"
+ " \n"
+ "import java.util.ArrayList; \n"
+ "import java.util.HashSet; \n"
+ " \n"
+ "import com.sample.DroolsTest.ShiftAssignment; \n"
+ "import com.sample.DroolsTest.IntervalRequirement; \n"
+ " \n"
+ "global java.util.List totallyCovered \n"
+ "global java.util.List notCovered \n"
+ "global java.util.List partiallyCovered \n"
+ " \n"
+ "rule \"intervalRequirementNotCovered\" \n"
+ " when \n"
+ " $intervalReq : IntervalRequirement($interval : interval) \n"
+ " not (ShiftAssignment(shiftStartTime <= $interval, shiftEndTime > $interval)) \n"
+ " then \n"
+ " #actions \n"
+ " notCovered.add($intervalReq); \n"
+ " System.out.println(\"intervalRequirementNotCovered -> \" + $intervalReq); \n"
+ "end \n"
+ " \n"
+ "rule \"intervalRequirementPartiallyCovered\" \n"
+ " when \n"
+ " $intervalReq : IntervalRequirement($interval : interval, $staffingRequired : staffingRequired) \n"
+ " $matchingShiftAssignmentsCount : Number(intValue() > 0, intValue() < $staffingRequired) from accumulate( \n"
+ " $matchingShiftAssignments : ShiftAssignment(shiftStartTime <= $interval, shiftEndTime > $interval) \n"
+ " , count($matchingShiftAssignments) \n"
+ " ) \n"
+ " then \n"
+ " #actions \n"
+ " partiallyCovered.add($intervalReq); \n"
+ " System.out.println(\"intervalRequirementPartiallyCovered -> \" + $intervalReq + \" covered by \" + $matchingShiftAssignmentsCount + \" ShiftAssignment(s)\"); \n"
+ "end \n"
+ " \n"
+ "rule \"intervalRequirementTotallyCovered\" \n"
+ " when \n"
+ " $intervalReq : IntervalRequirement($interval : interval, $staffingRequired : staffingRequired) \n"
+ " $matchingShiftAssignmentsCount : Number(intValue() > 0, intValue() >= $staffingRequired) from accumulate( \n"
+ " $matchingShiftAssignments : ShiftAssignment(shiftStartTime <= $interval, shiftEndTime > $interval) \n"
+ " , count($matchingShiftAssignments) \n"
+ " ) \n"
+ " then \n"
+ " #actions \n"
+ " totallyCovered.add($intervalReq); \n"
+ " System.out.println(\"intervalRequirementTotallyCovered -> \" + $intervalReq + \" covered by \" + $matchingShiftAssignmentsCount + \" ShiftAssignment(s)\"); \n"
+ "end \n"
+ " \n"
;
}