/// <summary> /// CTOR - Validates the <paramref name="source"/> model and creates the <see cref="DmnDefinition"/> from <see cref="DmnModel"/> /// </summary> /// <param name="source">Source DMN Model parsed from XML</param> ///<exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception> protected DmnDefinitionFactory(DmnModel source) { if (source == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(source)} is null"); } //Process input data var inputDataById = new Dictionary <string, DmnVariableDefinition>(); if (source.InputData != null) //it's not common, but OK to have no input data { ProcessInputDataSource(source, inputDataById); } //Process decisions var decisionsById = new Dictionary <string, IDmnDecision>(); // ReSharper disable once InvertIf if (source.Decisions != null && source.Decisions.Count > 0) { foreach (var sourceDecision in source.Decisions) { ProcessDecision(sourceDecision, source.Decisions, decisionsById, inputDataById); } } else { throw Logger.Fatal <DmnParserException>($"No decision in DMN model."); } }
/// <summary> /// Validates the inputs of the <see cref="DmnModel"/> (<paramref name="source"/> and populates <see cref="InputData"/> and related <see cref="Variables"/> /// </summary> /// <param name="source">Source DMN Model parsed from XML</param> /// <param name="inputDataById">Temporary dictionary of input data (by ID) - input data are populated here</param> /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="inputDataById"/> is null.</exception> /// <exception cref="DmnParserException">Missing input id</exception> /// <exception cref="DmnParserException">Duplicate input data name</exception> protected void ProcessInputDataSource(DmnModel source, IDictionary <string, DmnVariableDefinition> inputDataById) { if (source == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(source)} is null"); } if (inputDataById == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(inputDataById)} is null"); } if (source.InputData == null || source.InputData.Count == 0) { return; //it's not common, but OK to have no input data } //TODO ?Input name in form varName:varType for (complex) input types foreach (var sourceInput in source.InputData) { if (string.IsNullOrWhiteSpace(sourceInput.Id)) { throw Logger.Fatal <DmnParserException>($"Missing input id"); } var inputName = !string.IsNullOrWhiteSpace(sourceInput.Name) ? sourceInput.Name : sourceInput.Id; var variableName = DmnVariableDefinition.NormalizeVariableName(inputName); if (InputData.ContainsKey(variableName)) { throw Logger.Fatal <DmnParserException>($"Duplicate input data name {variableName} (from {inputName})"); } var variable = new DmnVariableDefinition(variableName, inputName); InputData.Add(variableName, variable); Variables.Add(variableName, variable); inputDataById.Add(sourceInput.Id, variable); } }
/// <summary> /// Creates the execution context from <paramref name="sourceModel"/> /// </summary> /// <param name="sourceModel">Source model to create the execution context for</param> /// <returns><paramref name="sourceModel"/> execution context</returns> /// <exception cref="ArgumentNullException"><paramref name="sourceModel"/> is null</exception> public static DmnExecutionContext CreateExecutionContext(DmnModel sourceModel) { if (sourceModel == null) { throw new ArgumentNullException(nameof(sourceModel)); } var definition = DmnDefinitionFactory.CreateDmnDefinition(sourceModel); return(CreateExecutionContext(definition)); }
/// <summary> /// Validates the <paramref name="source"/> model and creates the <see cref="DmnDefinition"/> from <see cref="DmnModel"/> /// </summary> /// <param name="source">Source DMN Model parsed from XML</param> ///<exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception> /// <returns>DMN model definition that can be used to execute the decisions within the <see cref="runtime.DmnExecutionContext"/></returns> public static DmnDefinition CreateDmnDefinition(DmnModel source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } var factory = new DmnDefinitionFactory(source); return(new DmnDefinition(factory.Variables, factory.InputData, factory.Decisions)); }
/// <summary> /// Validates the inputs of the <see cref="DmnModel"/> (<paramref name="source"/> and populates <see cref="InputData"/> and related <see cref="Variables"/> /// </summary> /// <param name="source">Source DMN Model parsed from XML</param> /// <param name="inputDataById">Temporary dictionary of input data (by ID) - input data are populated here</param> ///<exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="inputDataById"/> is null.</exception> /// <exception cref="DmnParserException">Missing input id</exception> /// <exception cref="DmnParserException">Duplicate input data name</exception> protected void ProcessInputDataSource(DmnModel source, IDictionary <string, DmnVariableDefinition> inputDataById) { if (source == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(source)} is null"); } if (inputDataById == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(inputDataById)} is null"); } if (source.InputData == null || source.InputData.Count == 0) { return; //it's not common, but OK to have no input data } var inputExpressionTypeByNames = source.Decisions?.Where(d => d.DecisionTable?.Inputs != null).SelectMany(d => d.DecisionTable?.Inputs)? .ToDictionary(i => string.IsNullOrEmpty(i.InputExpression?.Text) ? i.Label : i.InputExpression.Text, i => i.InputExpression?.TypeRef) ?? new Dictionary <string, string>(); //TODO ?Input name in form varName:varType for (complex) input types //TODO ?Required input parameters check for null?? foreach (var sourceInput in source.InputData) { if (string.IsNullOrWhiteSpace(sourceInput.Id)) { throw Logger.Fatal <DmnParserException>($"Missing input id"); } var inputName = !string.IsNullOrWhiteSpace(sourceInput.Name) ? sourceInput.Name : sourceInput.Id; var variableName = NormalizeVariableName(inputName); if (InputData.ContainsKey(variableName)) { throw Logger.Fatal <DmnParserException>($"Duplicate input data name {variableName} (from {inputName})"); } var variable = new DmnVariableDefinition(variableName) { IsInputParameter = true, HasValueSetter = true }; // try to evaluate variable type from expression type if (inputExpressionTypeByNames.TryGetValue(variableName, out var expressionType)) { CheckAndUpdateVariableType(variable, expressionType); } variable.ValueSetters.Add($"Input: {inputName}"); InputData.Add(variableName, variable); Variables.Add(variableName, variable); inputDataById.Add(sourceInput.Id, variable); } }
/// <summary> /// Creates the execution context from <paramref name="sourceModel"/> /// </summary> /// <param name="sourceModel">Source model to create the execution context for</param> /// <param name="configure">Optional configuration action</param> /// <typeparam name="T">Type of the execution context to be created. Must be <see cref="DmnExecutionContext"/> or its descendant</typeparam> /// <returns><paramref name="sourceModel"/> execution context</returns> /// <exception cref="ArgumentNullException"><paramref name="sourceModel"/> is null</exception> public static DmnExecutionContext CreateCustomExecutionContext <T>( DmnModel sourceModel, Action <DmnExecutionContextOptions> configure = null) where T : DmnExecutionContext { if (sourceModel == null) { throw new ArgumentNullException(nameof(sourceModel)); } var definition = DmnDefinitionFactory.CreateDmnDefinition(sourceModel); return(CreateCustomExecutionContext <T>(definition, configure)); }
/// <summary> /// Validates the <paramref name="source"/> model and creates the <see cref="DmnDefinition"/> from <see cref="DmnModel"/> /// </summary> /// <param name="source">Source DMN Model parsed from XML</param> ///<exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception> /// <returns>DMN model definition that can be used to execute the decisions within the <see cref="runtime.DmnExecutionContext"/></returns> public static DmnDefinition CreateDmnDefinition(DmnModel source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } var factory = new DmnDefinitionFactory(source); return(new DmnDefinition( factory.Variables.ToDictionary( v => v.Key, v => (IDmnVariable)v.Value), factory.Decisions)); }
/// <summary> /// Creates the execution context from <paramref name="sourceModel"/> /// </summary> /// <param name="sourceModel">Source model to create the execution context for</param> /// <param name="configure">Optional configuration action</param> /// <returns><paramref name="sourceModel"/> execution context</returns> /// <exception cref="ArgumentNullException"><paramref name="sourceModel"/> is null</exception> public static DmnExecutionContext CreateExecutionContext( DmnModel sourceModel, Action <DmnExecutionContextOptions> configure = null) { return(CreateCustomExecutionContext <DmnExecutionContext>(sourceModel, configure)); }