Skip to content

Instantly share code, notes, and snippets.

@cjmamo
Last active November 19, 2021 14:42
Show Gist options
  • Save cjmamo/50736b6ff70f75ae8bd7 to your computer and use it in GitHub Desktop.
Save cjmamo/50736b6ff70f75ae8bd7 to your computer and use it in GitHub Desktop.
package org.ossandme;
global org.ossandme.AlertDecision alertDecision;
rule "alert_0"
when
org.ossandme.event.OrderEvent(price > 5000.0 && customer == 'Widgets Inc.')
then
alertDecision.setDoAlert(Boolean.TRUE);
end
Rule highValueOrderRule = new Rule();
Condition highValueOrderCondition = new Condition();
highValueOrderCondition.setField("price");
highValueOrderCondition.setOperator(Condition.Operator.GREATER_THAN);
highValueOrderCondition.setValue(5000.0);
// In reality, you would have multiple rules for different types of events.
// The eventType property would be used to find rules relevant to the event
highValueOrderRule.setEventType(Rule.eventType.ORDER);
highValueOrderRule.setCondition(highValueOrderCondition);
Rule highValueOrderWidgetsIncRule = new Rule();
Condition highValueOrderCondition = new Condition();
highValueOrderCondition.setField("price");
highValueOrderCondition.setOperator(Condition.Operator.GREATER_THAN);
highValueOrderCondition.setValue(5000.0);
Condition widgetsIncCustomerCondition = new Condition();
widgetsIncCustomerCondition.setField("customer");
widgetsIncCustomerCondition.setOperator(Condition.Operator.EQUAL_TO);
widgetsIncCustomerCondition.setValue("Widgets Inc.");
// In reality, you would have multiple rules for different types of events.
// The eventType property would be used to find rules relevant to the event
highValueOrderWidgetsIncRule.setEventType(Rule.eventType.ORDER);
highValueOrderWidgetsIncRule.setConditions(Arrays.asList(highValueOrderCondition, widgetsIncCustomerCondition));
package org.ossandme;
import org.drools.template.ObjectDataCompiler;
...
public final class Program {
...
// Event parameter is an interface and OrderEvent implements it
static private String applyRuleTemplate(Event event, Rule rule) throws Exception {
Map<String, Object> data = new HashMap<String, Object>();
ObjectDataCompiler objectDataCompiler = new ObjectDataCompiler();
data.put("rule", rule);
data.put("eventType", event.getClass().getName());
return objectDataCompiler.compile(Arrays.asList(data), Thread.currentThread().getContextClassLoader().getResourceAsStream("template.drl"));
}
}
package org.ossandme;
...
public final class Program {
...
static private AlertDecision evaluate(String drl, Event event) throws Exception {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.write("src/main/resources/rule.drl", drl);
kieServices.newKieBuilder(kieFileSystem).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
StatelessKieSession statelessKieSession = kieContainer.getKieBase().newStatelessKieSession();
AlertDecision alertDecision = new AlertDecision();
statelessKieSession.getGlobals().set("alertDecision", alertDecision);
statelessKieSession.execute(event);
return alertDecision;
}
...
}
package org.ossandme;
...
public final class Program {
static public void main(String[] args) throws Exception {
// Create an event that will be tested against the rule.
// Realistically, the event would be read from some external source.
OrderEvent orderEvent = new OrderEvent();
orderEvent.setPrice(5000.1);
orderEvent.setCustomer("Widgets Inc.");
// Create rule
Rule highValueOrderWidgetsIncRule = new Rule();
// Create condition
Condition highValueOrderCondition = new Condition();
highValueOrderCondition.setField("price");
highValueOrderCondition.setOperator(Condition.Operator.GREATER_THAN);
highValueOrderCondition.setValue(5000.0);
// Create another condition
Condition widgetsIncCustomerCondition = new Condition();
widgetsIncCustomerCondition.setField("customer");
widgetsIncCustomerCondition.setOperator(Condition.Operator.EQUAL_TO);
widgetsIncCustomerCondition.setValue("Widgets Inc.");
// In reality, you would have multiple rules for different types of events.
// The eventType property would be used to find rules relevant to the event
highValueOrderWidgetsIncRule.setEventType(Rule.eventType.ORDER);
// Add conditions to rule
highValueOrderWidgetsIncRule.setConditions(Arrays.asList(highValueOrderCondition, widgetsIncCustomerCondition));
String drl = applyRuleTemplate(orderEvent, highValueOrderWidgetsIncRule);
AlertDecision alertDecision = evaluate(drl, orderEvent);
System.out.println(alertDecision.getDoAlert());
// doAlert is false by default
if (alertDecision.getDoAlert()) {
// do notification
// ...
}
}
// OrderEvent implements Event interface
static private AlertDecision evaluate(String drl, Event event) throws Exception {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.write("src/main/resources/rule.drl", drl);
kieServices.newKieBuilder(kieFileSystem).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
StatelessKieSession statelessKieSession = kieContainer.getKieBase().newStatelessKieSession();
AlertDecision alertDecision = new AlertDecision();
statelessKieSession.getGlobals().set("alertDecision", alertDecision);
statelessKieSession.execute(event);
return alertDecision;
}
// Event parameter is an interface and OrderEvent implements it
static private String applyRuleTemplate(Event event, Rule rule) throws Exception {
Map<String, Object> data = new HashMap<String, Object>();
ObjectDataCompiler objectDataCompiler = new ObjectDataCompiler();
data.put("rule", rule);
data.put("eventType", event.getClass().getName());
return objectDataCompiler.compile(Arrays.asList(data), Thread.currentThread().getContextClassLoader().getResourceAsStream("rule-template.drl"));
}
}
package org.ossandme.rule;
...
public class Rule {
...
@Override
public String toString(){
StringBuilder statementBuilder = new StringBuilder();
for (Condition condition : getConditions()) {
String operator = null;
switch (condition.getOperator()) {
case EQUAL_TO:
operator = "==";
break;
case NOT_EQUAL_TO:
operator = "!=";
break;
case GREATER_THAN:
operator = ">";
break;
case LESS_THAN:
operator = "<";
break;
case GREATER_THAN_OR_EQUAL_TO:
operator = ">=";
break;
case LESS_THAN_OR_EQUAL_TO:
operator = "<=";
break;
}
statementBuilder.append(condition.getField()).append(" ").append(operator).append(" ");
if (condition.getValue() instanceof String) {
statementBuilder.append("'").append(condition.getValue()).append("'");
} else {
statementBuilder.append(condition.getValue());
}
statementBuilder.append(" && ");
}
String statement = statementBuilder.toString();
// remove trailing &&
return statement.substring(0, statement.length() - 4);
}
}
template header
rule
eventType
package org.ossandme;
global org.ossandme.AlertDecision alertDecision;
template "alert"
rule "alert_@{row.rowNumber}"
when
@{eventType}(@{rule})
then
alertDecision.setDoAlert(Boolean.TRUE);
end
end template
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment