i am trying to implement serialization in drools. My problem is that drools fusion operators after, before,... are not serialized as expected.
My rules are working correctly if I don't use serialization and deserialization.
I attached a reproducer. Can anyone tell me what the problem is. I expect the rule to fire only once. It should fire once at 03:06:00 but it fires 3 times, once at 3:04:00 and 2 times at 3:06:00.
Event which is serialized:
package com.reproducer;
import java.io.Serializable;
import java.util.Date;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class EventA implements Serializable {
/**
*
*/
private static final long serialVersionUID = 8129243856721618942L;
private int value;
private Date timestamp;
public EventA(Date timestamp, int value) {
this.value = value;
this.timestamp = timestamp;
}
public Date getTimestamp() {
return timestamp;
}
public int getValue() {
return value;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("value", this.value)
.append("timestamp", this.getTimestamp()).toString();
}
}
Test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class Reproducer {
// date formatter for simulation data and tests
private static DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Configuration
static class ContextConfiguration {
}
private KieBase kieBase;
private static KieSession ksession;
private static SessionPseudoClock clock;
private KieSessionConfiguration sessionConfig;
public byte[] serializedSession;
@Test
public void ruleTest() {
List<EventA> events = getSimulationEvents();
startKnowledgeSession(events.get(0).getTimestamp(), false);
runSimulation(events);
}
private static Date parseDate(String input) {
Date d = null;
try {
d = dateFormatter.parse(input);
} catch (ParseException e) {
e.printStackTrace();
}
return d;
}
private void runSimulation(List<EventA> events) {
for (EventA current : events) {
KieSession ksession2 = kieBase.newKieSession(sessionConfig, null);
Marshaller marshaller = KieServices.Factory.get().getMarshallers().newMarshaller(kieBase);
try {
ByteArrayInputStream bais = new ByteArrayInputStream(serializedSession);
ksession2 = marshaller.unmarshall(bais, sessionConfig, null);
clock = ksession2.getSessionClock();
bais.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
long currTime = clock.getCurrentTime();
long nextTime = current.getTimestamp().getTime();
while (currTime <= (nextTime - 1000)) {
clock.advanceTime(1000, TimeUnit.MILLISECONDS);
ksession2.fireAllRules();
currTime += 1000;
}
long diff = nextTime - currTime;
if (diff > 0) {
clock.advanceTime(diff, TimeUnit.MILLISECONDS);
}
ksession2.insert(current);
ksession2.fireAllRules();
// serialize knowledge session
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshaller.marshall(baos, ksession2);
serializedSession = baos.toByteArray();
} catch (IOException e2) {
e2.printStackTrace();
}
ksession2.halt();
ksession2.dispose();
}
}
private List<EventA> getSimulationEvents() {
List<EventA> events = new ArrayList<EventA>();
events.add(new EventA(parseDate("2010-01-01 02:00:00"), 0));
events.add(new EventA(parseDate("2010-01-01 03:00:00"), 1));
events.add(new EventA(parseDate("2010-01-01 03:01:00"), 0));
events.add(new EventA(parseDate("2010-01-01 03:02:00"), 1));
events.add(new EventA(parseDate("2010-01-01 03:03:00"), 0));
events.add(new EventA(parseDate("2010-01-01 03:04:00"), 0));
events.add(new EventA(parseDate("2010-01-01 03:05:00"), 0));
events.add(new EventA(parseDate("2010-01-01 03:06:00"), 0));
events.add(new EventA(parseDate("2010-01-01 03:07:00"), 0));
return events;
}
private void startKnowledgeSession(Date startTime, boolean onHolidays) {
// create configuration
StringBuffer drlR1 = new StringBuffer();
drlR1.append("package test\n");
drlR1.append("dialect \"mvel\"\n");
drlR1.append("import com.reproducer.EventA\n");
drlR1.append("import java.util.Date\n");
drlR1.append("declare EventA\n");
drlR1.append(" @role(event)\n");
drlR1.append(" @timestamp(timestamp)\n");
drlR1.append("end\n");
drlR1.append("rule test\n");
drlR1.append(" when\n");
drlR1.append(" $event : EventA(getValue() == 1)\n");
drlR1.append(" not(EventA(getValue() == 1, this after [1ms,4m] $event))\n");
drlR1.append(" then\n");
drlR1.append(
" System.out.println(\"Fired \"+ new Date(drools.getWorkingMemory().getSessionClock().getCurrentTime()));\n");
drlR1.append("end\n");
kieBase = new KieHelper().addContent(drlR1.toString(), ResourceType.DRL).build(EventProcessingOption.STREAM);
sessionConfig = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
sessionConfig.setOption(ClockTypeOption.get(ClockType.PSEUDO_CLOCK.getId()));
sessionConfig.setOption(TimedRuleExecutionOption.YES);
sessionConfig.setOption(TimerJobFactoryOption.get("trackable"));
sessionConfig.setOption(ClockTypeOption.get("pseudo"));
ksession = kieBase.newKieSession(sessionConfig, null);
// set clock reference
clock = ksession.getSessionClock();
clock.advanceTime(startTime.getTime(), TimeUnit.MILLISECONDS);
sessionConfig = ksession.getSessionConfiguration();
// serialize knowledge session
try {
Marshaller marshaller = KieServices.Factory.get().getMarshallers().newMarshaller(kieBase);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshaller.marshall(baos, ksession);
serializedSession = baos.toByteArray();
} catch (IOException e2) {
e2.printStackTrace();
}
}
}
I opened a bug report for this problem at the JBOSS Developer Jira Bug Report. It was a bug in the drools core engine. It will be fixed with version 7.2.0Final.