Search in sources :

Example 1 with DTDecisionRule

use of org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule 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;
}
Also used : InformationItem(org.kie.dmn.model.v1_1.InformationItem) DMNMessage(org.kie.dmn.api.core.DMNMessage) ContextEntry(org.kie.dmn.model.v1_1.ContextEntry) OutputClause(org.kie.dmn.model.v1_1.OutputClause) FunctionDefinition(org.kie.dmn.model.v1_1.FunctionDefinition) LoggerFactory(org.slf4j.LoggerFactory) LiteralExpression(org.kie.dmn.model.v1_1.LiteralExpression) DMNExpressionEvaluator(org.kie.dmn.core.api.DMNExpressionEvaluator) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) EvaluatorResult(org.kie.dmn.core.api.EvaluatorResult) Binding(org.kie.dmn.model.v1_1.Binding) UnaryTest(org.kie.dmn.feel.runtime.UnaryTest) DMNModelInstrumentedBase(org.kie.dmn.model.v1_1.DMNModelInstrumentedBase) BaseDMNTypeImpl(org.kie.dmn.core.impl.BaseDMNTypeImpl) DMNModelImpl(org.kie.dmn.core.impl.DMNModelImpl) DecisionTable(org.kie.dmn.model.v1_1.DecisionTable) DMNRelationEvaluator(org.kie.dmn.core.ast.DMNRelationEvaluator) Collectors(java.util.stream.Collectors) BusinessKnowledgeModelNode(org.kie.dmn.api.core.ast.BusinessKnowledgeModelNode) Context(org.kie.dmn.model.v1_1.Context) List(java.util.List) DMNDTExpressionEvaluator(org.kie.dmn.core.ast.DMNDTExpressionEvaluator) CompiledExpression(org.kie.dmn.feel.lang.CompiledExpression) Invocation(org.kie.dmn.model.v1_1.Invocation) Optional(java.util.Optional) QName(javax.xml.namespace.QName) DMNLiteralExpressionEvaluator(org.kie.dmn.core.ast.DMNLiteralExpressionEvaluator) BusinessKnowledgeModel(org.kie.dmn.model.v1_1.BusinessKnowledgeModel) DMNElement(org.kie.dmn.model.v1_1.DMNElement) FEEL(org.kie.dmn.feel.FEEL) MsgUtil(org.kie.dmn.core.util.MsgUtil) DMNType(org.kie.dmn.api.core.DMNType) DMNContextEvaluator(org.kie.dmn.core.ast.DMNContextEvaluator) DTOutputClause(org.kie.dmn.feel.runtime.decisiontables.DTOutputClause) EvaluatorResultImpl(org.kie.dmn.core.ast.EvaluatorResultImpl) DTInputClause(org.kie.dmn.feel.runtime.decisiontables.DTInputClause) ArrayList(java.util.ArrayList) HitPolicy(org.kie.dmn.model.v1_1.HitPolicy) Relation(org.kie.dmn.model.v1_1.Relation) DecisionNode(org.kie.dmn.api.core.ast.DecisionNode) FEELFunction(org.kie.dmn.feel.runtime.FEELFunction) DMNBaseNode(org.kie.dmn.core.ast.DMNBaseNode) DecisionRule(org.kie.dmn.model.v1_1.DecisionRule) UnaryTests(org.kie.dmn.model.v1_1.UnaryTests) Expression(org.kie.dmn.model.v1_1.Expression) DMNInvocationEvaluator(org.kie.dmn.core.ast.DMNInvocationEvaluator) Logger(org.slf4j.Logger) DMNListEvaluator(org.kie.dmn.core.ast.DMNListEvaluator) DTInvokerFunction(org.kie.dmn.feel.runtime.functions.DTInvokerFunction) Decision(org.kie.dmn.model.v1_1.Decision) Collectors.toList(java.util.stream.Collectors.toList) DMNFunctionDefinitionEvaluator(org.kie.dmn.core.ast.DMNFunctionDefinitionEvaluator) InputClause(org.kie.dmn.model.v1_1.InputClause) Msg(org.kie.dmn.core.util.Msg) DecisionTableImpl(org.kie.dmn.feel.runtime.decisiontables.DecisionTableImpl) Collections(java.util.Collections) BaseFEELFunction(org.kie.dmn.feel.runtime.functions.BaseFEELFunction) FEEL(org.kie.dmn.feel.FEEL) ArrayList(java.util.ArrayList) BusinessKnowledgeModelNode(org.kie.dmn.api.core.ast.BusinessKnowledgeModelNode) UnaryTest(org.kie.dmn.feel.runtime.UnaryTest) CompiledExpression(org.kie.dmn.feel.lang.CompiledExpression) ContextEntry(org.kie.dmn.model.v1_1.ContextEntry) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) DecisionRule(org.kie.dmn.model.v1_1.DecisionRule) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) DTInputClause(org.kie.dmn.feel.runtime.decisiontables.DTInputClause) DTInputClause(org.kie.dmn.feel.runtime.decisiontables.DTInputClause) InputClause(org.kie.dmn.model.v1_1.InputClause) QName(javax.xml.namespace.QName) DecisionTableImpl(org.kie.dmn.feel.runtime.decisiontables.DecisionTableImpl) LiteralExpression(org.kie.dmn.model.v1_1.LiteralExpression) DTOutputClause(org.kie.dmn.feel.runtime.decisiontables.DTOutputClause) DMNDTExpressionEvaluator(org.kie.dmn.core.ast.DMNDTExpressionEvaluator) BaseDMNTypeImpl(org.kie.dmn.core.impl.BaseDMNTypeImpl) Decision(org.kie.dmn.model.v1_1.Decision) OutputClause(org.kie.dmn.model.v1_1.OutputClause) DTOutputClause(org.kie.dmn.feel.runtime.decisiontables.DTOutputClause) BusinessKnowledgeModel(org.kie.dmn.model.v1_1.BusinessKnowledgeModel) DTInvokerFunction(org.kie.dmn.feel.runtime.functions.DTInvokerFunction) UnaryTests(org.kie.dmn.model.v1_1.UnaryTests)

Example 2 with DTDecisionRule

use of org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule in project drools by kiegroup.

the class DecisionTableFunction method invoke.

/**
 *     @param inputExpressionList a list of the N>=0 input expressions in display order
 *     @param inputValuesList * a list of N input values, corresponding to the input expressions. Each
 *     list element is a unary tests literal (see below).
 *     @param outputs * a name (a string matching grammar rule 27) or a list of M>0 names
 *     @param outputValues * if outputs is a list, then output values is a list of lists of values, one list
 *     per output; else output values is a list of values for the one output.
 *     Each value is a string.
 *     @param ruleList a list of R>0 rules. A rule is a list of N input entries followed by M
 *     output entries. An input entry is a unary tests literal. An output entry is
 *     an expression represented as a string.
 *     @param hitPolicy * one of: "U", "A", “P”, “F”, "R", "O", "C", "C+", "C#", "C<", “C>”
 *     (default is "U")
 *     @param defaultOutputValue * if outputs is a list, then default output value is a context with entries
 *     composed of outputs and output values; else default output value is one
 *     of the output values.
 */
public Object invoke(@ParameterName("ctx") EvaluationContext ctx, @ParameterName("outputs") Object outputs, @ParameterName("input expression list") Object inputExpressionList, @ParameterName("input values list") List<?> inputValuesList, @ParameterName("output values") Object outputValues, @ParameterName("rule list") List<List> ruleList, @ParameterName("hit policy") String hitPolicy, @ParameterName("default output value") Object defaultOutputValue) {
    // input expression list can have a single element or be a list
    // TODO isn't ^ conflicting with the specs page 136 "input expression list: a LIST of the"
    List<String> inputExpressions = inputExpressionList instanceof List ? (List) inputExpressionList : Collections.singletonList((String) inputExpressionList);
    List<DTInputClause> inputs;
    if (inputValuesList != null) {
        List<UnaryTest> inputValues = inputValuesList.stream().map(o -> toUnaryTest(ctx, o)).collect(Collectors.toList());
        if (inputValues.size() != inputExpressions.size()) {
        // TODO handle compilation error
        }
        // zip inputExpression with its inputValue
        inputs = IntStream.range(0, inputExpressions.size()).mapToObj(i -> new DTInputClause(inputExpressions.get(i), inputValuesList.toString(), Collections.singletonList(inputValues.get(i)), null)).collect(Collectors.toList());
    } else {
        inputs = inputExpressions.stream().map(ie -> new DTInputClause(ie, null, null, null)).collect(Collectors.toList());
    }
    List<String> parseOutputs = outputs instanceof List ? (List) outputs : Collections.singletonList((String) outputs);
    List<DTOutputClause> outputClauses;
    if (outputValues != null) {
        if (parseOutputs.size() == 1) {
            outputClauses = new ArrayList<>();
            List<UnaryTest> outputValuesCompiled = objectToUnaryTestList(ctx, Collections.singletonList((List<Object>) outputValues)).get(0);
            outputClauses.add(new DTOutputClause(parseOutputs.get(0), outputValuesCompiled));
        } else {
            List<List<UnaryTest>> listOfList = objectToUnaryTestList(ctx, (List<List<Object>>) outputValues);
            // zip inputExpression with its inputValue
            outputClauses = IntStream.range(0, parseOutputs.size()).mapToObj(i -> new DTOutputClause(parseOutputs.get(i), listOfList.get(i))).collect(Collectors.toList());
        }
    } else {
        outputClauses = parseOutputs.stream().map(out -> new DTOutputClause(out, null)).collect(Collectors.toList());
    }
    // TODO parse default output value.
    FEEL feel = FEEL.newInstance();
    List<DTDecisionRule> decisionRules = IntStream.range(0, ruleList.size()).mapToObj(index -> toDecisionRule(ctx, feel, index, ruleList.get(index), inputExpressions.size())).collect(Collectors.toList());
    // TODO is there a way to avoid UUID and get from _evaluation_ ctx the name of the wrapping context?
    // TODO also in this case it is using an ad-hoc created FEEL instance instead of the "hosted" one.
    DecisionTableImpl dti = new DecisionTableImpl(UUID.randomUUID().toString(), inputExpressions, inputs, outputClauses, decisionRules, HitPolicy.fromString(hitPolicy), FEEL.newInstance());
    return new DTInvokerFunction(dti);
}
Also used : IntStream(java.util.stream.IntStream) FEEL(org.kie.dmn.feel.FEEL) FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) FEELEventListener(org.kie.dmn.api.feel.runtime.events.FEELEventListener) UnaryTest(org.kie.dmn.feel.runtime.UnaryTest) Logger(org.slf4j.Logger) DTOutputClause(org.kie.dmn.feel.runtime.decisiontables.DTOutputClause) HitPolicy(org.kie.dmn.feel.runtime.decisiontables.HitPolicy) LoggerFactory(org.slf4j.LoggerFactory) DTInputClause(org.kie.dmn.feel.runtime.decisiontables.DTInputClause) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) Range(org.kie.dmn.feel.runtime.Range) ArrayList(java.util.ArrayList) List(java.util.List) CompiledExpression(org.kie.dmn.feel.lang.CompiledExpression) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent) EvaluationContext(org.kie.dmn.feel.lang.EvaluationContext) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) Msg(org.kie.dmn.feel.util.Msg) DecisionTableImpl(org.kie.dmn.feel.runtime.decisiontables.DecisionTableImpl) Collections(java.util.Collections) FEEL(org.kie.dmn.feel.FEEL) DecisionTableImpl(org.kie.dmn.feel.runtime.decisiontables.DecisionTableImpl) DTOutputClause(org.kie.dmn.feel.runtime.decisiontables.DTOutputClause) UnaryTest(org.kie.dmn.feel.runtime.UnaryTest) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) DTInputClause(org.kie.dmn.feel.runtime.decisiontables.DTInputClause) ArrayList(java.util.ArrayList) List(java.util.List)

Example 3 with DTDecisionRule

use of org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule in project drools by kiegroup.

the class DecisionTableFunction method toDecisionRule.

/**
 * Convert row to DTDecisionRule
 * @param mainCtx the main context is used to identify the hosted FEELEventManager
 * @param embeddedFEEL a possibly cached embedded FEEL to compile the output expression, error will be reported up to the mainCtx
 * @param index
 * @param rule
 * @param inputSize
 * @return
 */
private static DTDecisionRule toDecisionRule(EvaluationContext mainCtx, FEEL embeddedFEEL, int index, List<?> rule, int inputSize) {
    // TODO should be check indeed block of inputSize n inputs, followed by block of outputs.
    DTDecisionRule dr = new DTDecisionRule(index);
    for (int i = 0; i < rule.size(); i++) {
        Object o = rule.get(i);
        if (i < inputSize) {
            dr.getInputEntry().add(toUnaryTest(mainCtx, o));
        } else {
            FEELEventListener ruleListener = event -> mainCtx.notifyEvt(() -> new FEELEventBase(event.getSeverity(), Msg.createMessage(Msg.ERROR_COMPILE_EXPR_DT_FUNCTION_RULE_IDX, index + 1, event.getMessage()), event.getSourceException()));
            embeddedFEEL.addListener(ruleListener);
            CompiledExpression compiledExpression = embeddedFEEL.compile((String) o, embeddedFEEL.newCompilerContext());
            dr.getOutputEntry().add(compiledExpression);
            embeddedFEEL.removeListener(ruleListener);
        }
    }
    return dr;
}
Also used : IntStream(java.util.stream.IntStream) FEEL(org.kie.dmn.feel.FEEL) FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) FEELEventListener(org.kie.dmn.api.feel.runtime.events.FEELEventListener) UnaryTest(org.kie.dmn.feel.runtime.UnaryTest) Logger(org.slf4j.Logger) DTOutputClause(org.kie.dmn.feel.runtime.decisiontables.DTOutputClause) HitPolicy(org.kie.dmn.feel.runtime.decisiontables.HitPolicy) LoggerFactory(org.slf4j.LoggerFactory) DTInputClause(org.kie.dmn.feel.runtime.decisiontables.DTInputClause) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) Range(org.kie.dmn.feel.runtime.Range) ArrayList(java.util.ArrayList) List(java.util.List) CompiledExpression(org.kie.dmn.feel.lang.CompiledExpression) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent) EvaluationContext(org.kie.dmn.feel.lang.EvaluationContext) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) Msg(org.kie.dmn.feel.util.Msg) DecisionTableImpl(org.kie.dmn.feel.runtime.decisiontables.DecisionTableImpl) Collections(java.util.Collections) FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) DTDecisionRule(org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule) FEELEventListener(org.kie.dmn.api.feel.runtime.events.FEELEventListener) CompiledExpression(org.kie.dmn.feel.lang.CompiledExpression)

Aggregations

ArrayList (java.util.ArrayList)3 Collections (java.util.Collections)3 List (java.util.List)3 Collectors (java.util.stream.Collectors)3 FEEL (org.kie.dmn.feel.FEEL)3 CompiledExpression (org.kie.dmn.feel.lang.CompiledExpression)3 UnaryTest (org.kie.dmn.feel.runtime.UnaryTest)3 DTDecisionRule (org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule)3 DTInputClause (org.kie.dmn.feel.runtime.decisiontables.DTInputClause)3 DTOutputClause (org.kie.dmn.feel.runtime.decisiontables.DTOutputClause)3 DecisionTableImpl (org.kie.dmn.feel.runtime.decisiontables.DecisionTableImpl)3 UUID (java.util.UUID)2 IntStream (java.util.stream.IntStream)2 FEELEvent (org.kie.dmn.api.feel.runtime.events.FEELEvent)2 FEELEventListener (org.kie.dmn.api.feel.runtime.events.FEELEventListener)2 EvaluationContext (org.kie.dmn.feel.lang.EvaluationContext)2 Range (org.kie.dmn.feel.runtime.Range)2 HitPolicy (org.kie.dmn.feel.runtime.decisiontables.HitPolicy)2 FEELEventBase (org.kie.dmn.feel.runtime.events.FEELEventBase)2 Msg (org.kie.dmn.feel.util.Msg)2