de.materna.jdec.drools.DroolsDebugger Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdec Show documentation
Show all versions of jdec Show documentation
🤔 Library that offers a unified interface to Drools and Java decisions
package de.materna.jdec.drools;
import de.materna.jdec.DecisionSession;
import de.materna.jdec.model.ModelContext;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.event.*;
import org.kie.dmn.core.ast.DMNFunctionDefinitionEvaluator;
import java.util.*;
public class DroolsDebugger {
private DecisionSession decisionSession;
private Map> decisions = new LinkedHashMap<>();
private Stack decisionStack = new Stack<>();
private List messages = new LinkedList<>();
private Stack contextStack;
private DMNRuntimeEventListener listener;
public DroolsDebugger(DecisionSession decisionSession) {
this.decisionSession = decisionSession;
}
public void start() {
listener = new DMNRuntimeEventListener() {
@Override
public void beforeEvaluateDecision(BeforeEvaluateDecisionEvent event) {
decisionStack.push(event.getDecision().getName());
decisions.put(decisionStack.peek(), new HashMap<>());
contextStack = new Stack<>();
}
@Override
public void beforeEvaluateContextEntry(BeforeEvaluateContextEntryEvent event) {
String variableName = event.getVariableName();
if (variableName.equals("__RESULT__")) {
//return;
}
// We create a context and put it on the stack.
// The name allows us to set the value to a higher context level.
ModelContext context = new ModelContext();
context.setName(variableName);
contextStack.push(context);
}
@Override
public void afterEvaluateContextEntry(AfterEvaluateContextEntryEvent event) {
String variableName = event.getVariableName();
if (variableName.equals("__RESULT__")) {
//return;
}
// When we leave the context, we remove it from the stack.
// If the value has not yet been set by a higher context level, we'll do it.
// Otherwise, we could overwrite context that we cannot see from this level.
ModelContext context = contextStack.pop();
if (context.getValue() == null) {
context.setValue(cleanResult(event.getExpressionResult()));
}
// When we have reached the bottom context, we attach it to the decision.
if (contextStack.size() == 0) {
decisions.get(decisionStack.peek()).put(context.getName(), context.getValue());
return;
}
// If we haven't reached the bottom context, we attach the context to the parent context.
ModelContext parentContext = contextStack.peek();
// If this is the first value, we'll create a map.
if (parentContext.getValue() == null) {
Map value = new HashMap<>();
value.put(context.getName(), context.getValue());
parentContext.setValue(value);
return;
}
Map parentContextValue = (Map) parentContext.getValue();
parentContextValue.put(context.getName(), context.getValue());
}
@Override
public void afterEvaluateDecision(AfterEvaluateDecisionEvent event) {
for (DMNMessage message : event.getResult().getMessages()) {
// noinspection deprecation
messages.add(message.getMessage());
}
decisionStack.pop();
}
};
decisionSession.getRuntime().addListener(listener);
}
public void stop() {
decisionSession.getRuntime().removeListener(listener);
}
/**
* We need to remove all functions because serializing them is not possible.
*/
private Object cleanResult(Object result) {
if (result instanceof Map) {
Map results = (Map) result;
Map cleanedResults = new LinkedHashMap<>();
for (Map.Entry entry : results.entrySet()) {
cleanedResults.put(entry.getKey(), cleanResult(entry.getValue()));
}
return cleanedResults;
}
if (result instanceof DMNFunctionDefinitionEvaluator.DMNFunction) {
return "__FUNCTION_DEFINITION__";
}
return result;
}
public Map> getDecisions() {
return decisions;
}
public List getMessages() {
return messages;
}
}