use of org.kie.dmn.core.ast.DMNBaseNode in project drools by kiegroup.
the class DMNEvaluatorCompiler method compileDecisionTable.
private DMNExpressionEvaluator compileDecisionTable(DMNCompilerContext ctx, DMNModelImpl model, DMNBaseNode node, String dtName, DecisionTable dt) {
java.util.List<DTInputClause> inputs = new ArrayList<>();
int index = 0;
for (InputClause ic : dt.getInput()) {
index++;
String inputExpressionText = ic.getInputExpression().getText();
String inputValuesText = Optional.ofNullable(ic.getInputValues()).map(UnaryTests::getText).orElse(null);
java.util.List<UnaryTest> inputValues = null;
if (inputValuesText != null) {
inputValues = textToUnaryTestList(ctx, inputValuesText, model, ic, Msg.ERR_COMPILING_FEEL_EXPR_ON_DT_INPUT_CLAUSE_IDX, inputValuesText, node.getIdentifierString(), index);
} else if (ic.getInputExpression().getTypeRef() != null) {
QName inputExpressionTypeRef = ic.getInputExpression().getTypeRef();
BaseDMNTypeImpl typeRef = (BaseDMNTypeImpl) model.getTypeRegistry().resolveType(resolveNamespaceForTypeRef(inputExpressionTypeRef, ic.getInputExpression()), inputExpressionTypeRef.getLocalPart());
inputValues = typeRef.getAllowedValuesFEEL();
}
CompiledExpression compiledInput = feel.compileFeelExpression(ctx, inputExpressionText, model, dt, Msg.ERR_COMPILING_FEEL_EXPR_ON_DT_INPUT_CLAUSE_IDX, inputExpressionText, dtName, index);
inputs.add(new DTInputClause(inputExpressionText, inputValuesText, inputValues, compiledInput));
}
java.util.List<DTOutputClause> outputs = new ArrayList<>();
index = 0;
boolean hasOutputValues = false;
for (OutputClause oc : dt.getOutput()) {
String outputName = oc.getName();
if (outputName != null) {
DMNCompilerHelper.checkVariableName(model, node.getSource(), outputName);
}
String id = oc.getId();
String outputValuesText = Optional.ofNullable(oc.getOutputValues()).map(UnaryTests::getText).orElse(null);
String defaultValue = oc.getDefaultOutputEntry() != null ? oc.getDefaultOutputEntry().getText() : null;
BaseDMNTypeImpl typeRef = (BaseDMNTypeImpl) DMNTypeRegistry.UNKNOWN;
java.util.List<UnaryTest> outputValues = null;
if (oc.getTypeRef() != null) {
QName outputExpressionTypeRef = oc.getTypeRef();
typeRef = (BaseDMNTypeImpl) model.getTypeRegistry().resolveType(resolveNamespaceForTypeRef(outputExpressionTypeRef, oc), outputExpressionTypeRef.getLocalPart());
if (typeRef == null) {
typeRef = (BaseDMNTypeImpl) DMNTypeRegistry.UNKNOWN;
}
} else if (dt.getOutput().size() == 1 && (dt.getParent() instanceof Decision || dt.getParent() instanceof BusinessKnowledgeModel || dt.getParent() instanceof ContextEntry)) {
QName inferredTypeRef = recurseUpToInferTypeRef(model, oc, dt);
// if inferredTypeRef is null, a std err will have been reported
if (inferredTypeRef != null) {
typeRef = (BaseDMNTypeImpl) model.getTypeRegistry().resolveType(resolveNamespaceForTypeRef(inferredTypeRef, oc), inferredTypeRef.getLocalPart());
}
}
if (outputValuesText != null) {
outputValues = textToUnaryTestList(ctx, outputValuesText, model, oc, Msg.ERR_COMPILING_FEEL_EXPR_ON_DT_OUTPUT_CLAUSE_IDX, outputValuesText, node.getIdentifierString(), ++index);
} else if (typeRef != DMNTypeRegistry.UNKNOWN) {
outputValues = typeRef.getAllowedValuesFEEL();
}
if (outputValues != null && !outputValues.isEmpty()) {
hasOutputValues = true;
}
outputs.add(new DTOutputClause(outputName, id, outputValues, defaultValue, typeRef.getFeelType(), typeRef.isCollection()));
}
if (dt.getHitPolicy().equals(HitPolicy.PRIORITY) && !hasOutputValues) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, dt.getParent(), model, null, null, Msg.MISSING_OUTPUT_VALUES, dt.getParent());
}
java.util.List<DTDecisionRule> rules = new ArrayList<>();
index = 0;
for (DecisionRule dr : dt.getRule()) {
DTDecisionRule rule = new DTDecisionRule(index);
for (UnaryTests ut : dr.getInputEntry()) {
final java.util.List<UnaryTest> tests;
if (ut == null || ut.getText() == null || ut.getText().isEmpty()) {
tests = Collections.emptyList();
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, ut, model, null, null, Msg.DTABLE_EMPTY_ENTRY, dt.getRule().indexOf(dr) + 1, dr.getInputEntry().indexOf(ut) + 1, dt.getParentDRDElement().getIdentifierString());
} else {
tests = textToUnaryTestList(ctx, ut.getText(), model, dr, Msg.ERR_COMPILING_FEEL_EXPR_ON_DT_RULE_IDX, ut.getText(), node.getIdentifierString(), index + 1);
}
rule.getInputEntry().add((c, x) -> tests.stream().anyMatch(t -> {
Boolean result = t.apply(c, x);
return result != null && result == true;
}));
}
for (LiteralExpression le : dr.getOutputEntry()) {
String expressionText = le.getText();
CompiledExpression compiledExpression = feel.compileFeelExpression(ctx, expressionText, model, dr, Msg.ERR_COMPILING_FEEL_EXPR_ON_DT_RULE_IDX, expressionText, dtName, index + 1);
rule.getOutputEntry().add(compiledExpression);
}
rules.add(rule);
index++;
}
String policy = dt.getHitPolicy().value() + (dt.getAggregation() != null ? " " + dt.getAggregation().value() : "");
org.kie.dmn.feel.runtime.decisiontables.HitPolicy hp = org.kie.dmn.feel.runtime.decisiontables.HitPolicy.fromString(policy);
java.util.List<String> parameterNames = new ArrayList<>();
if (node instanceof BusinessKnowledgeModelNode) {
// need to break this statement down and check for nulls
parameterNames.addAll(((BusinessKnowledgeModelNode) node).getBusinessKnowledModel().getEncapsulatedLogic().getFormalParameter().stream().map(f -> f.getName()).collect(toList()));
} else {
parameterNames.addAll(node.getDependencies().keySet());
}
// creates a FEEL instance which will be used by the invoker/impl (s)
FEEL feelInstance = feel.newFEELInstance();
DecisionTableImpl dti = new DecisionTableImpl(dtName, parameterNames, inputs, outputs, rules, hp, feelInstance);
DTInvokerFunction dtf = new DTInvokerFunction(dti);
DMNDTExpressionEvaluator dtee = new DMNDTExpressionEvaluator(node, feelInstance, dtf);
return dtee;
}
use of org.kie.dmn.core.ast.DMNBaseNode in project drools by kiegroup.
the class DMNRuntimeImpl method evaluateBKM.
private void evaluateBKM(DMNContext context, DMNResultImpl result, BusinessKnowledgeModelNode b, boolean typeCheck) {
BusinessKnowledgeModelNodeImpl bkm = (BusinessKnowledgeModelNodeImpl) b;
if (isNodeValueDefined(result, bkm)) {
// TODO: do we need to check if the defined variable is a function as it should?
return;
}
// TODO: do we need to check/resolve dependencies?
if (bkm.getEvaluator() == null) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.WARN, bkm.getSource(), result, null, null, Msg.MISSING_EXPRESSION_FOR_BKM, getIdentifier(bkm));
return;
}
try {
DMNRuntimeEventManagerUtils.fireBeforeEvaluateBKM(eventManager, bkm, result);
for (DMNNode dep : bkm.getDependencies().values()) {
if (typeCheck && !checkDependencyValueIsValid(dep, result)) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, ((DMNBaseNode) dep).getSource(), result, null, null, Msg.ERROR_EVAL_NODE_DEP_WRONG_TYPE, getIdentifier(bkm), getIdentifier(dep), MsgUtil.clipString(result.getContext().get(dep.getName()).toString(), 50), ((DMNBaseNode) dep).getType());
return;
}
if (!isNodeValueDefined(result, dep)) {
if (dep instanceof BusinessKnowledgeModelNode) {
evaluateBKM(context, result, (BusinessKnowledgeModelNode) dep, typeCheck);
} else {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, bkm.getSource(), result, null, null, Msg.REQ_DEP_NOT_FOUND_FOR_NODE, getIdentifier(dep), getIdentifier(bkm));
return;
}
}
}
EvaluatorResult er = bkm.getEvaluator().evaluate(this, result);
if (er.getResultType() == EvaluatorResult.ResultType.SUCCESS) {
FEELFunction resultFn = (FEELFunction) er.getResult();
if (bkm.getModelNamespace().equals(result.getModel().getNamespace())) {
// TODO check of the return type will need calculation/inference of function return type.
result.getContext().set(bkm.getBusinessKnowledModel().getVariable().getName(), resultFn);
} else {
DMNModelImpl model = (DMNModelImpl) result.getModel();
Optional<String> importAlias = model.getImportAliasFor(bkm.getModelNamespace(), bkm.getModelName());
Map<String, Object> aliasContext = (Map) result.getContext().getAll().computeIfAbsent(importAlias.get(), x -> new LinkedHashMap<>());
aliasContext.put(bkm.getBusinessKnowledModel().getVariable().getName(), resultFn);
}
}
} catch (Throwable t) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, bkm.getSource(), result, t, null, Msg.ERROR_EVAL_BKM_NODE, getIdentifier(bkm), t.getMessage());
} finally {
DMNRuntimeEventManagerUtils.fireAfterEvaluateBKM(eventManager, bkm, result);
}
}
use of org.kie.dmn.core.ast.DMNBaseNode in project drools by kiegroup.
the class DMNEvaluatorCompiler method compileFunctionDefinition.
private DMNExpressionEvaluator compileFunctionDefinition(DMNCompilerContext ctx, DMNModelImpl model, DMNBaseNode node, String functionName, FunctionDefinition expression) {
FunctionDefinition funcDef = expression;
String kindStr = funcDef.getAdditionalAttributes().get(FunctionDefinition.KIND_QNAME);
FunctionDefinition.Kind kind = kindStr != null ? FunctionDefinition.Kind.determineFromString(kindStr) : FunctionDefinition.Kind.FEEL;
if (kind == null) {
// unknown function kind
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, funcDef, model, null, null, Msg.FUNC_DEF_INVALID_KIND, kindStr, node.getIdentifierString());
return new DMNFunctionDefinitionEvaluator(node.getName(), funcDef);
} else if (kind.equals(FunctionDefinition.Kind.FEEL)) {
ctx.enterFrame();
try {
DMNFunctionDefinitionEvaluator func = new DMNFunctionDefinitionEvaluator(node.getName(), funcDef);
for (InformationItem p : funcDef.getFormalParameter()) {
DMNCompilerHelper.checkVariableName(model, p, p.getName());
DMNType dmnType = compiler.resolveTypeRef(model, node, p, p, p.getTypeRef());
func.addParameter(p.getName(), dmnType);
ctx.setVariable(p.getName(), dmnType);
}
DMNExpressionEvaluator eval = compileExpression(ctx, model, node, functionName, funcDef.getExpression());
if (eval instanceof DMNLiteralExpressionEvaluator && ((DMNLiteralExpressionEvaluator) eval).isFunctionDefinition()) {
// we need to resolve the function and eliminate the indirection
CompiledExpression fexpr = ((DMNLiteralExpressionEvaluator) eval).getExpression();
FEELFunction feelFunction = feel.evaluateFunctionDef(ctx, fexpr, model, funcDef, Msg.FUNC_DEF_COMPILATION_ERR, functionName, node.getIdentifierString());
DMNInvocationEvaluator invoker = new DMNInvocationEvaluator(node.getName(), node.getSource(), functionName, new Invocation(), (fctx, fname) -> feelFunction, // feel can be null as anyway is hardcoded to `feelFunction`
null);
for (InformationItem p : funcDef.getFormalParameter()) {
invoker.addParameter(p.getName(), func.getParameterType(p.getName()), (em, dr) -> new EvaluatorResultImpl(dr.getContext().get(p.getName()), EvaluatorResult.ResultType.SUCCESS));
}
eval = invoker;
}
func.setEvaluator(eval);
return func;
} finally {
ctx.exitFrame();
}
} else if (kind.equals(FunctionDefinition.Kind.JAVA)) {
if (funcDef.getExpression() instanceof Context) {
// proceed
Context context = (Context) funcDef.getExpression();
String clazz = null;
String method = null;
for (ContextEntry ce : context.getContextEntry()) {
if (ce.getVariable() != null && ce.getVariable().getName() != null && ce.getExpression() != null && ce.getExpression() instanceof LiteralExpression) {
if (ce.getVariable().getName().equals("class")) {
clazz = stripQuotes(((LiteralExpression) ce.getExpression()).getText().trim());
} else if (ce.getVariable().getName().equals("method signature")) {
method = stripQuotes(((LiteralExpression) ce.getExpression()).getText().trim());
}
}
}
if (clazz != null && method != null) {
String params = funcDef.getFormalParameter().stream().map(p -> p.getName()).collect(Collectors.joining(","));
String expr = String.format("function(%s) external { java: { class: \"%s\", method signature: \"%s\" }}", params, clazz, method);
try {
FEELFunction feelFunction = feel.evaluateFunctionDef(ctx, expr, model, funcDef, Msg.FUNC_DEF_COMPILATION_ERR, functionName, node.getIdentifierString());
if (feelFunction != null) {
((BaseFEELFunction) feelFunction).setName(functionName);
}
DMNInvocationEvaluator invoker = new DMNInvocationEvaluator(node.getName(), node.getSource(), functionName, new Invocation(), (fctx, fname) -> feelFunction, // feel can be null as anyway is hardcoded to `feelFunction`
null);
DMNFunctionDefinitionEvaluator func = new DMNFunctionDefinitionEvaluator(node.getName(), funcDef);
for (InformationItem p : funcDef.getFormalParameter()) {
DMNCompilerHelper.checkVariableName(model, p, p.getName());
DMNType dmnType = compiler.resolveTypeRef(model, node, p, p, p.getTypeRef());
func.addParameter(p.getName(), dmnType);
invoker.addParameter(p.getName(), dmnType, (em, dr) -> new EvaluatorResultImpl(dr.getContext().get(p.getName()), EvaluatorResult.ResultType.SUCCESS));
}
func.setEvaluator(invoker);
return func;
} catch (Throwable e) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, expression, model, e, null, Msg.FUNC_DEF_COMPILATION_ERR, functionName, node.getIdentifierString(), "Exception raised: " + e.getClass().getSimpleName());
}
} else {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, expression, model, null, null, Msg.FUNC_DEF_MISSING_ENTRY, functionName, node.getIdentifierString());
}
} else {
// error, java function definitions require a context
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, funcDef, model, null, null, Msg.FUNC_DEF_BODY_NOT_CONTEXT, node.getIdentifierString());
}
} else if (kind.equals(FunctionDefinition.Kind.PMML)) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.WARN, funcDef, model, null, null, Msg.FUNC_DEF_PMML_NOT_SUPPORTED, node.getIdentifierString());
} else {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, funcDef, model, null, null, Msg.FUNC_DEF_INVALID_KIND, kindStr, node.getIdentifierString());
}
return new DMNFunctionDefinitionEvaluator(node.getName(), funcDef);
}
use of org.kie.dmn.core.ast.DMNBaseNode in project drools by kiegroup.
the class DMNRuntimeImpl method evaluateDecision.
private boolean evaluateDecision(DMNContext context, DMNResultImpl result, DecisionNode d, boolean typeCheck) {
DecisionNodeImpl decision = (DecisionNodeImpl) d;
if (result.getContext().isDefined(decision.getName())) {
// already resolved
return true;
} else {
// check if the decision was already evaluated before and returned error
DMNDecisionResult.DecisionEvaluationStatus status = result.getDecisionResultById(decision.getId()).getEvaluationStatus();
if (FAILED == status || SKIPPED == status || EVALUATING == status) {
return false;
}
}
try {
DMNRuntimeEventManagerUtils.fireBeforeEvaluateDecision(eventManager, decision, result);
boolean missingInput = false;
DMNDecisionResultImpl dr = (DMNDecisionResultImpl) result.getDecisionResultById(decision.getId());
dr.setEvaluationStatus(DMNDecisionResult.DecisionEvaluationStatus.EVALUATING);
for (DMNNode dep : decision.getDependencies().values()) {
try {
if (typeCheck && !checkDependencyValueIsValid(dep, result)) {
missingInput = true;
DMNMessage message = MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, ((DMNBaseNode) dep).getSource(), result, null, null, Msg.ERROR_EVAL_NODE_DEP_WRONG_TYPE, getIdentifier(decision), getIdentifier(dep), MsgUtil.clipString(result.getContext().get(dep.getName()).toString(), 50), ((DMNBaseNode) dep).getType());
reportFailure(dr, message, DMNDecisionResult.DecisionEvaluationStatus.SKIPPED);
}
} catch (Exception e) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, ((DMNBaseNode) dep).getSource(), result, e, null, Msg.ERROR_CHECKING_ALLOWED_VALUES, getIdentifier(dep), e.getMessage());
}
if (!result.getContext().isDefined(dep.getName())) {
if (dep instanceof DecisionNode) {
if (!evaluateDecision(context, result, (DecisionNode) dep, typeCheck)) {
missingInput = true;
DMNMessage message = MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, decision.getSource(), result, null, null, Msg.UNABLE_TO_EVALUATE_DECISION_REQ_DEP, getIdentifier(decision), getIdentifier(dep));
reportFailure(dr, message, DMNDecisionResult.DecisionEvaluationStatus.SKIPPED);
}
} else if (dep instanceof BusinessKnowledgeModelNode) {
evaluateBKM(context, result, (BusinessKnowledgeModelNode) dep, typeCheck);
} else {
missingInput = true;
DMNMessage message = MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, decision.getSource(), result, null, null, Msg.REQ_DEP_NOT_FOUND_FOR_NODE, getIdentifier(dep), getIdentifier(decision));
reportFailure(dr, message, DMNDecisionResult.DecisionEvaluationStatus.SKIPPED);
}
}
}
if (missingInput) {
return false;
}
if (decision.getEvaluator() == null) {
DMNMessage message = MsgUtil.reportMessage(logger, DMNMessage.Severity.WARN, decision.getSource(), result, null, null, Msg.MISSING_EXPRESSION_FOR_DECISION, getIdentifier(decision));
reportFailure(dr, message, DMNDecisionResult.DecisionEvaluationStatus.SKIPPED);
return false;
}
try {
EvaluatorResult er = decision.getEvaluator().evaluate(this, result);
if (er.getResultType() == EvaluatorResult.ResultType.SUCCESS) {
Object value = er.getResult();
if (!decision.getResultType().isCollection() && value instanceof Collection && ((Collection) value).size() == 1) {
// spec defines that "a=[a]", i.e., singleton collections should be treated as the single element
// and vice-versa
value = ((Collection) value).toArray()[0];
}
try {
if (typeCheck && !d.getResultType().isAssignableValue(value)) {
DMNMessage message = MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, decision.getSource(), result, null, null, Msg.ERROR_EVAL_NODE_RESULT_WRONG_TYPE, getIdentifier(decision), decision.getResultType(), value);
reportFailure(dr, message, DMNDecisionResult.DecisionEvaluationStatus.FAILED);
return false;
}
} catch (Exception e) {
MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, decision.getSource(), result, e, null, Msg.ERROR_CHECKING_ALLOWED_VALUES, getIdentifier(decision), e.getMessage());
return false;
}
result.getContext().set(decision.getDecision().getVariable().getName(), value);
dr.setResult(value);
dr.setEvaluationStatus(DMNDecisionResult.DecisionEvaluationStatus.SUCCEEDED);
} else {
dr.setEvaluationStatus(DMNDecisionResult.DecisionEvaluationStatus.FAILED);
return false;
}
} catch (Throwable t) {
DMNMessage message = MsgUtil.reportMessage(logger, DMNMessage.Severity.ERROR, decision.getSource(), result, t, null, Msg.ERROR_EVAL_DECISION_NODE, getIdentifier(decision), t.getMessage());
reportFailure(dr, message, DMNDecisionResult.DecisionEvaluationStatus.FAILED);
}
return true;
} finally {
DMNRuntimeEventManagerUtils.fireAfterEvaluateDecision(eventManager, decision, result);
}
}
Aggregations