Skip to content

Commit

Permalink
add rule engine meta data to once_after match
Browse files Browse the repository at this point in the history
  • Loading branch information
mariofusco committed May 30, 2023
1 parent ef8b49e commit d95f9f0
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.drools.ansible.rulebook.integration.api.domain.temporal;

import java.util.List;

import org.drools.model.Index;
import org.drools.model.PrototypeDSL;
import org.drools.model.PrototypeVariable;

import java.util.List;

import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.SYNTHETIC_PROTOTYPE_NAME;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.getPrototype;
import static org.drools.model.PrototypeDSL.protoPattern;
Expand All @@ -22,6 +22,8 @@ public abstract class OnceAbstractTimeConstraint implements TimeConstraint {

protected PrototypeDSL.PrototypePatternDef guardedPattern;

private PrototypeVariable controlVariable;

public OnceAbstractTimeConstraint(TimeAmount timeAmount, List<String> groupByAttributes) {
this.timeAmount = timeAmount;
this.groupByAttributes = groupByAttributes;
Expand All @@ -31,12 +33,17 @@ protected PrototypeVariable getPatternVariable() {
return (PrototypeVariable) guardedPattern.getFirstVariable();
}

protected PrototypeVariable getControlVariable() {
return controlVariable;
}

protected PrototypeDSL.PrototypePatternDef createControlPattern() {
PrototypeDSL.PrototypePatternDef controlPattern = protoPattern(variable(getPrototype(SYNTHETIC_PROTOTYPE_NAME)));
for (String unique : groupByAttributes) {
controlPattern.expr( prototypeField(unique), Index.ConstraintType.EQUAL, getPatternVariable(), prototypeField(unique) );
}
controlPattern.expr( prototypeField("drools_rule_name"), Index.ConstraintType.EQUAL, fixedValue(ruleName) );
this.controlVariable = (PrototypeVariable) controlPattern.getFirstVariable();
return controlPattern;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.drools.core.facttemplates.Event;
import org.drools.core.facttemplates.Fact;
import org.drools.model.Drools;
import org.drools.model.DroolsEntryPoint;
import org.drools.model.Index;
import org.drools.model.Prototype;
import org.drools.model.PrototypeDSL;
Expand All @@ -21,14 +20,17 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;
import static org.drools.ansible.rulebook.integration.api.domain.temporal.TimeAmount.parseTimeAmount;
import static org.drools.ansible.rulebook.integration.api.rulesengine.RegisterOnlyAgendaFilter.RULE_TYPE_TAG;
import static org.drools.ansible.rulebook.integration.api.rulesengine.RegisterOnlyAgendaFilter.SYNTHETIC_RULE_TAG;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.SYNTHETIC_PROTOTYPE_NAME;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.getPrototype;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.RulesModelUtil.writeMetaDataOnEvent;
import static org.drools.model.DSL.accFunction;
import static org.drools.model.DSL.accumulate;
import static org.drools.model.DSL.declarationOf;
Expand Down Expand Up @@ -121,16 +123,23 @@ private static Match transformOnceAfterMatch(Match match) {
EmptyMatchDecorator rewrittenMatch = new EmptyMatchDecorator(match);
Collection<Fact> results = ((Collection<Fact>) match.getDeclarationValue("results"));
if (results.size() == 1) {
rewrittenMatch.withBoundObject("m", results.iterator().next().get("event"));
rewrittenMatch.withBoundObject("m", controlFact2Event(results.iterator().next()));
} else {
int i = 0;
for (Fact fact : results) {
rewrittenMatch.withBoundObject("m_" + i++, fact.get("event"));
rewrittenMatch.withBoundObject("m_" + i++, controlFact2Event(fact));
}
}
return rewrittenMatch;
}

private static Object controlFact2Event(Fact fact) {
Map ruleEngineMeta = new HashMap();
ruleEngineMeta.put("once_after_time_window", fact.get("once_after_time_window"));
ruleEngineMeta.put("events_in_window", fact.get("events_in_window"));
return writeMetaDataOnEvent((Fact) fact.get("event"), ruleEngineMeta);
}

public OnceAfterDefinition(TimeAmount timeAmount, List<String> groupByAttributes) {
super(timeAmount, groupByAttributes);
}
Expand Down Expand Up @@ -190,6 +199,8 @@ public List<Rule> getControlRules(RuleGenerationContext ruleContext) {
}
controlEvent.set("drools_rule_name", ruleName);
controlEvent.set( "event", event );
controlEvent.set( "once_after_time_window", timeAmount.toString() );
controlEvent.set( "events_in_window", 1 );
drools.insert(controlEvent);
drools.delete(event);
})
Expand Down Expand Up @@ -223,7 +234,10 @@ public List<Rule> getControlRules(RuleGenerationContext ruleContext) {
.build(
guardedPattern,
createControlPattern(),
on(getPatternVariable()).execute(DroolsEntryPoint::delete)
on(getPatternVariable(), getControlVariable()).execute((drools, event, control) -> {
control.set( "events_in_window", ((int) control.get("events_in_window")) + 1 );
drools.delete(event);
})
)
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package org.drools.ansible.rulebook.integration.api.domain.temporal;

import java.util.Collections;
import java.util.List;

import org.drools.ansible.rulebook.integration.api.domain.RuleGenerationContext;
import org.drools.core.facttemplates.Event;
import org.drools.core.facttemplates.Fact;
Expand All @@ -14,11 +11,17 @@
import org.drools.model.view.CombinedExprViewItem;
import org.drools.model.view.ViewItem;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;
import static org.drools.ansible.rulebook.integration.api.domain.temporal.TimeAmount.parseTimeAmount;
import static org.drools.ansible.rulebook.integration.api.rulesengine.RegisterOnlyAgendaFilter.SYNTHETIC_RULE_TAG;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.SYNTHETIC_PROTOTYPE_NAME;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.getPrototype;
import static org.drools.ansible.rulebook.integration.api.rulesmodel.RulesModelUtil.writeMetaDataOnEvent;
import static org.drools.model.DSL.not;
import static org.drools.model.DSL.on;
import static org.drools.model.PatternDSL.rule;
Expand Down Expand Up @@ -92,6 +95,10 @@ public void executeTimeConstraintConsequence(Drools drools, Object... facts) {
controlEvent.set("drools_rule_name", ruleName);
drools.insert(controlEvent);
drools.delete(fact);

Map ruleEngineMeta = new HashMap();
ruleEngineMeta.put("once_within_time_window", timeAmount.toString());
writeMetaDataOnEvent(fact, ruleEngineMeta);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public TimeUnit getTimeUnit() {

@Override
public String toString() {
return "TimeAmount{ " + amount + " " + timeUnit + " }";
return amount + " " + timeUnit;
}

public static TimeAmount parseTimeAmount(String timeAmount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.drools.core.facttemplates.Fact;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import static org.drools.ansible.rulebook.integration.api.rulesmodel.PrototypeFactory.DEFAULT_PROTOTYPE_NAME;
Expand All @@ -13,6 +14,8 @@
public class RulesModelUtil {

public static final String ORIGINAL_MAP_FIELD = "$_ORIGINAL_$_MAP_$_FIELD_$";
public static final String META_FIELD = "meta";
public static final String RULE_ENGINE_META_FIELD = "rule_engine";

private RulesModelUtil() { }

Expand Down Expand Up @@ -51,4 +54,11 @@ private static Map<String, Object> factToMap(Map<String, Object> factMap) {
public static Map<String, Object> asFactMap(String json) {
return new JSONObject(json).toMap();
}

public static Fact writeMetaDataOnEvent(Fact event, Map ruleEngineMeta) {
Map map = (Map) event.get(ORIGINAL_MAP_FIELD);
Map meta = (Map) map.computeIfAbsent(META_FIELD, x -> new HashMap<>());
meta.put(RULE_ENGINE_META_FIELD, ruleEngineMeta);
return event;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.drools.ansible.rulebook.integration.api;

import org.drools.ansible.rulebook.integration.api.domain.temporal.TimeAmount;
import org.drools.ansible.rulebook.integration.api.rulesmodel.RulesModelUtil;
import org.drools.core.facttemplates.Fact;
import org.junit.Test;
import org.kie.api.runtime.rule.Match;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -97,6 +100,11 @@ public void testOnceAfterWithOr() {
assertTrue( host.equals( "h1" ) || host.equals( "h2" ) );
String level = fact.get("alert.level").toString();
assertTrue( level.equals( "error" ) || level.equals( "warning" ) );

Map map = (Map) fact.get(RulesModelUtil.ORIGINAL_MAP_FIELD);
Map ruleEngineMeta = (Map) ((Map)map.get(RulesModelUtil.META_FIELD)).get(RulesModelUtil.RULE_ENGINE_META_FIELD);
assertEquals( new TimeAmount(10, TimeUnit.SECONDS).toString(), ruleEngineMeta.get("once_after_time_window") );
assertEquals( i == 0 ? 2 : 1, ruleEngineMeta.get("events_in_window") );
}

for (int i = 0; i < 2; i++) {
Expand All @@ -112,6 +120,11 @@ public void testOnceAfterWithOr() {
assertTrue(host.equals("h1"));
String level = fact.get("alert.level").toString();
assertTrue(level.equals("warning"));

Map map = (Map) fact.get(RulesModelUtil.ORIGINAL_MAP_FIELD);
Map ruleEngineMeta = (Map) ((Map)map.get(RulesModelUtil.META_FIELD)).get(RulesModelUtil.RULE_ENGINE_META_FIELD);
assertEquals( new TimeAmount(10, TimeUnit.SECONDS).toString(), ruleEngineMeta.get("once_after_time_window") );
assertEquals( 1, ruleEngineMeta.get("events_in_window") );
}

rulesExecutor.dispose();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package org.drools.ansible.rulebook.integration.api;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.drools.ansible.rulebook.integration.api.domain.temporal.TimeAmount;
import org.drools.ansible.rulebook.integration.api.rulesmodel.RulesModelUtil;
import org.drools.core.facttemplates.Fact;
import org.junit.Test;
import org.kie.api.runtime.rule.Match;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;

public class OnceWithinTest {
Expand Down Expand Up @@ -117,6 +121,11 @@ private void onceWithinTest(String json) {
List<Match> matchedRules = rulesExecutor.processEvents("{ \"sensu\": { \"process\": { \"type\":\"alert\" }, \"host\":\"h1\" } }").join();
assertEquals(1, matchedRules.size());

Fact fact = (Fact) matchedRules.get(0).getDeclarationValue("singleton");
Map map = (Map) fact.get(RulesModelUtil.ORIGINAL_MAP_FIELD);
Map ruleEngineMeta = (Map) ((Map)map.get(RulesModelUtil.META_FIELD)).get(RulesModelUtil.RULE_ENGINE_META_FIELD);
assertEquals( new TimeAmount(10, TimeUnit.SECONDS).toString(), ruleEngineMeta.get("once_within_time_window") );

rulesExecutor.advanceTime(3, TimeUnit.SECONDS);

matchedRules = rulesExecutor.processEvents("{ \"sensu\": { \"process\": { \"type\":\"alert\" }, \"host\":\"h1\" } }").join();
Expand Down

0 comments on commit d95f9f0

Please sign in to comment.