Пример #1
0
        /// <summary>
        /// Evaluates the output expressions for  positive rules and stores generates the table execution results ( (rule, output)-&gt;temp variable with result)
        /// </summary>
        /// <param name="context">Engine execution context</param>
        /// <param name="executionId">Identifier of the execution run</param>
        /// <param name="positiveRules">List of positive rules</param>
        /// <returns>Table execution results</returns>
        private DmnDecisionTableRuleExecutionResults EvaluateOutputsForPositiveRulesParallel(DmnExecutionContext context, string executionId, IEnumerable <DmnDecisionTableRule> positiveRules)
        {
            Logger.InfoCorr(executionId, $"Evaluating decision table {Name} positive rules outputs...");
            var results         = new DmnDecisionTableRuleExecutionResultsParallel();
            var rulesAndOutputs = positiveRules.SelectMany(
                r => r.Outputs,
                (rule, output) => new { rule, output });

            Parallel.ForEach(rulesAndOutputs, ruleAndOutput =>


            {
                var positiveRule = ruleAndOutput.rule;
                var ruleOutput   = ruleAndOutput.output;

                if (string.IsNullOrWhiteSpace(ruleOutput.Expression))
                {
                    results.SetResult(positiveRule, ruleOutput, null);
                }
                else
                {
                    var result = context.EvalExpression(ruleOutput.Expression,
                                                        ruleOutput.Output.Variable.Type ?? typeof(object),
                                                        executionId);

                    // check allowed output values
                    var allowedValues = ruleOutput.Output.AllowedValues;
                    if (allowedValues != null && allowedValues.Length > 0 &&
                        !string.IsNullOrWhiteSpace(result?.ToString()))
                    {
                        if (!ruleOutput.Output.AllowedValues.Contains(result.ToString()))
                        {
                            throw Logger.ErrorCorr <DmnExecutorException>(
                                executionId,
                                $"Decision table {Name}, rule {positiveRule}: Output value '{result}' is not in allowed values list ({string.Join(",", allowedValues)})");
                        }
                    }

                    var output = new DmnExecutionVariable(ruleOutput.Output.Variable)
                    {
                        Value = result
                    };
                    results.SetResult(positiveRule, ruleOutput, output);
                    if (Logger.IsTraceEnabled)
                    {
                        Logger.TraceCorr(executionId,
                                         $"Positive decision table {Name} rule {positiveRule}: output {output.Name}, value {output.Value}");
                    }
                }
            });

            Logger.InfoCorr(executionId, $"Evaluated decision table {Name} positive rules outputs");
            return(results.FinalizeConcurrentResults());
        }
Пример #2
0
        /// <summary>
        /// Evaluates the decision.
        /// </summary>
        /// <param name="context">DMN Engine execution context</param>
        /// <param name="correlationId">Optional correlation ID used while logging</param>
        /// <returns>Decision result</returns>
        /// <exception cref="ArgumentNullException"><paramref name="context"/> is nul</exception>
        protected override DmnDecisionResult Evaluate(DmnExecutionContext context, string correlationId = null)
        {
            if (context == null)
            {
                throw Logger.FatalCorr <ArgumentNullException>(correlationId, $"{nameof(context)} is null");
            }

            Logger.InfoCorr(correlationId, $"Evaluating expressiong decision {Name} with expression {Expression}...");
            var result = context.EvalExpression(Expression, Output.Type);

            Logger.InfoCorr(correlationId, $"Evaluated expressiong decision {Name} with expression {Expression}");
            var outVariable = context.GetVariable(Output);

            outVariable.Value = result;
            return(new DmnDecisionResult() + (new DmnDecisionSingleResult() + outVariable.Clone()));
        }
        /// <summary>
        /// Evaluates the output expressions for  positive rules and stores generates the table execution results ( (rule, output)-&gt;temp variable with result)
        /// </summary>
        /// <param name="context">Engine execution context</param>
        /// <param name="correlationId">Correlation ID used for logging</param>
        /// <param name="positiveRules">List of positive rules</param>
        /// <returns>Table execution results</returns>
        private DmnDecisionTableRuleExecutionResults EvaluateOutputsForPositiveRules(DmnExecutionContext context, string correlationId, IEnumerable <DmnDecisionTableRule> positiveRules)
        {
            Logger.InfoCorr(correlationId, $"Evaluating decision table {Name} positive rules outputs...");
            var results = new DmnDecisionTableRuleExecutionResults();

            foreach (var positiveRule in positiveRules)
            {
                //outputs
                foreach (var ruleOutput in positiveRule.Outputs)
                {
                    if (string.IsNullOrWhiteSpace(ruleOutput.Expression))
                    {
                        results.SetResult(positiveRule, ruleOutput, null);
                        continue;
                    }

                    var result = context.EvalExpression(ruleOutput.Expression, ruleOutput.Output.Variable.Type ?? typeof(object));

                    // check allowed output values
                    var allowedValues = ruleOutput.Output.AllowedValues;
                    if (allowedValues != null && allowedValues.Count > 0 &&
                        !string.IsNullOrWhiteSpace(result?.ToString()))
                    {
                        if (!ruleOutput.Output.AllowedValues.Contains(result.ToString()))
                        {
                            throw Logger.ErrorCorr <DmnExecutorException>(
                                      correlationId,
                                      $"Decision table {Name}, rule {positiveRule}: Output value '{result}' is not in allowed values list ({string.Join(",", allowedValues)})");
                        }
                    }

                    var output = new DmnExecutionVariable(ruleOutput.Output.Variable)
                    {
                        Value = result
                    };
                    results.SetResult(positiveRule, ruleOutput, output);
                    if (Logger.IsTraceEnabled)
                    {
                        Logger.TraceCorr(correlationId,
                                         $"Positive decision table {Name} rule {positiveRule}: output {output.Name}, value {output.Value}");
                    }
                }
            }

            Logger.InfoCorr(correlationId, $"Evaluated decision table {Name} positive rules outputs");
            return(results);
        }
        protected override DmnDecisionResult Evaluate(DmnExecutionContext context, string executionId)
        {
            //Get execution variable value - use it here as sample to get input1 (the input2 will be directly referenced "by name" in the expression)
            var i1Bool = bool.TryParse(context.GetVariable(InputVar1).Value?.ToString() ?? "false", out var tmpOp) &&
                         tmpOp;


            //Build and evaluate an expression
            var expr   = $"{(Negate ? "!" : "")}({i1Bool.ToString().ToLower()} && {InputVar2.Name})";
            var result = context.EvalExpression <int>(expr, executionId);

            //Set execution variable value
            context.GetVariable(OutputVar).Value = result;

            //Build the decision result
            return(new DmnDecisionResult(new DmnDecisionSingleResult(context.GetVariable(OutputVar))));
        }
        /// <summary>
        /// Evaluates the rules and return the list of positive rules (rules that match the input)
        /// </summary>
        /// <remarks>
        /// Decision table defines the set of rules - "when the input values matches all input conditions, provide defined outputs".
        /// The input data are compared with corresponding rule expressions and when all match (comparison is true), the rule is evaluated
        /// as positive.
        /// Technically, when there is a negative comparison result, the rule is evaluates as negative and the rest of inputs is not evaluated.
        /// It's possible to omit all input expressions, so the rule will be always evaluated as positive match.
        /// </remarks>
        /// <param name="context">Engine execution context</param>
        /// <param name="correlationId">Correlation ID used for logging</param>
        /// <returns>List of positive rules (rules that match the input)</returns>
        /// <exception cref="ArgumentNullException"><paramref name="context"/> is nul</exception>
        private List <DmnDecisionTableRule> EvaluateRules(DmnExecutionContext context, string correlationId)
        {
            if (context == null)
            {
                throw Logger.FatalCorr <ArgumentNullException>(correlationId, $"{nameof(context)} is null");
            }

            var positiveRules = new List <DmnDecisionTableRule>();

            //EVALUATE RULES
            Logger.InfoCorr(correlationId, $"Evaluating decision table {Name} rules...");
            foreach (var rule in Rules)
            {
                var match = true;
                foreach (var ruleInput in rule.Inputs)
                {
                    //check allowed input values
                    var allowedValues = ruleInput.Input.AllowedValues;
                    if (allowedValues != null && allowedValues.Count > 0)
                    {
                        string value = null;
                        if (!string.IsNullOrWhiteSpace(ruleInput.Input.Expression))
                        {
                            //input is mapped to expression, so evaluate it to ger the value
                            var valueObj = context.EvalExpression <object>(ruleInput.Input.Expression);
                            if (valueObj != null)
                            {
                                value = valueObj.ToString();
                            }
                        }
                        else
                        {
                            //input is mapped to variable
                            value = context.GetVariable(ruleInput.Input.Variable).Value?.ToString();
                        }
                        if (!allowedValues.Contains(value))
                        {
                            throw Logger.ErrorCorr <DmnExecutorException>(
                                      correlationId,
                                      $"Decision table {Name}, rule #{rule.Index}: Input value '{value}' is not in allowed values list ({string.Join(",", allowedValues)})");
                        }
                    }
                    if (Logger.IsTraceEnabled)
                    {
                        Logger.TraceCorr(correlationId, $"Evaluating decision table {Name} rule {rule} input #{ruleInput.Input.Index}: {ruleInput.Expression}... ");
                    }
                    var result =
                        context.EvalExpression <bool>(ruleInput.Expression); //TODO ?pre-parse and use the inputs as parameters?
                    if (Logger.IsTraceEnabled)
                    {
                        Logger.TraceCorr(correlationId, $"Evaluated decision table {Name} rule {rule} input #{ruleInput.Input.Index}: {ruleInput.Expression} with result {result}");
                    }

                    // ReSharper disable once InvertIf
                    if (!result)
                    {
                        match = false;
                        break;
                    }
                }

                Logger.InfoCorr(correlationId,
                                $"Evaluated decision table {Name} rule: {(match ? "POSITIVE" : "NEGATIVE")} - {rule}");
                if (match)
                {
                    positiveRules.Add(rule);
                }
            }

            Logger.InfoCorr(correlationId, $"Evaluated decision table {Name} rules");
            return(positiveRules);
        }