/// <summary> /// creates a new <see cref="AssignStateNode"/> /// </summary> /// <param name="node">node of which to assign result</param> /// <param name="variableName">name of variable to assign result to</param> /// <param name="variableoperation">operation to use when assigning variable</param> /// <param name="compiler">compiler to use to compile variable operation</param> public AssignStateNode(IInstanceNode node, string variableName, VariableOperation variableoperation, IScriptCompiler compiler) { this.node = node; VariableName = variableName; if (variableoperation != VariableOperation.Assign) { operation = compiler.CompileCode($"$lhs{variableoperation.ToOperatorString()}$rhs", ScriptLanguage.NCScript); } }
/// <summary> /// creates a new <see cref="SuspendState"/> /// </summary> /// <param name="workflow">suspended workflow</param> /// <param name="node">suspended node</param> /// <param name="variables">variables of executing workflow</param> /// <param name="language">default language of workflow</param> /// <param name="profiling">determines whether profiling is enabled</param> /// <param name="subflow">suspended sub workflow (optional)</param> public SuspendState(WorkflowIdentifier workflow, IInstanceNode node, StateVariableProvider variables, ScriptLanguage?language, bool profiling, SuspendState subflow = null) { Variables = variables; Node = node; Subflow = subflow; Language = language; Profiling = profiling; Workflow = workflow; }
/// <inheritdoc /> public async Task <WorkflowInstance> BuildWorkflow(WorkflowDetails workflow) { WorkflowInstance instance = cacheservice.GetObject <WorkflowInstance, long>(workflow.Id, workflow.Revision); if (instance != null) { return(instance); } logger.LogInformation("Rebuilding workflow '{name}'", workflow.Name); int startcount = workflow.Nodes.Count(n => n.Type == NodeType.Start); if (startcount == 0) { throw new ArgumentException("Workflow has no start node"); } if (startcount > 1) { throw new ArgumentException("Workflow has more than one start node"); } StartNode startnode = null; Dictionary <Guid, IInstanceNode> nodes = new Dictionary <Guid, IInstanceNode>(); foreach (NodeDetails node in workflow.Nodes) { IInstanceNode nodeinstance = await BuildNode(workflow.Language, node, node.Id); nodes[node.Id] = nodeinstance; if (nodeinstance is StartNode startinstance) { startnode = startinstance; } } foreach (TransitionData transition in workflow.Transitions) { await BuildTransition(workflow, transition.OriginId, transition.TargetId, transition, id => nodes[id]); } instance = new WorkflowInstance { Id = workflow.Id, Revision = workflow.Revision, Name = workflow.Name, Language = workflow.Language, StartNode = startnode }; cacheservice.StoreObject(workflow.Id, workflow.Revision, instance); return(instance); }
private void Initialize(AddressSpaceCompiler addressSpaceCompiler, IInstanceNode node, XmlQualifiedName nodeID, bool isInstanceDeclaration, int?parentAddressSpaceIndex) { Debug.Assert(node != null, "Parameter error at AddressSpaceNode creator: node cannot be null"); Debug.Assert(nodeID != null, "NodeID cannot be null"); ErrorList = new List <Diagnostics>(); m_References = new InstanceReferencesCollection(this); m_Compiler = addressSpaceCompiler; m_IsInstanceDeclaration = isInstanceDeclaration; m_ParentAddressSpaceIndex = parentAddressSpaceIndex; m_Node = node; m_NodeID = nodeID; AddressSpaceIndex = m_Compiler.AddNode2AddressSpace(this, m_NodeID.ToString()); InstanceWrapper = m_Node.DerivePropertyValuesFrom(null); }
/// <summary> /// Adds the <see cref="IInstanceNode" /> to the collection of a type children with goal to build inheritance chain and override the attributes of the base type by the derived type. /// </summary> /// <param name="childItem">The child item of the <paramref name="modelParentNode" />.</param> /// <param name="modelParentNode">The model parent node - the node, which type is processed and <paramref name="childItem" /> added.</param> /// <param name="typeParentID">The parent identifier of the type provisioning instance declarations - prefix to the relative reference path.</param> void IInstanceNodesCollection.Add(IInstanceNode childItem, IInstanceNodeContext modelParentNode, XmlQualifiedName typeParentID) { XmlQualifiedName _itemNodeID = InstanceIdentifier.AddSuffix(modelParentNode.NodeID, childItem.SymbolicName.Name); string _stringItemNodeID = InstanceIdentifier.NodeId(_itemNodeID); if (this.m_dictionary.ContainsKey(_stringItemNodeID)) { this.m_dictionary[_stringItemNodeID].AddInstanceDeclarationOf(childItem, typeParentID); } else { this.Add(_stringItemNodeID, childItem, _itemNodeID, modelParentNode.AddressSpaceIndex, true); } }
void IInstanceNodesCollection.Add(IInstanceNode childItem, XmlQualifiedName parentNodeID, int parentAddressSpaceIndex, bool isInstanceDeclaration) { XmlQualifiedName _itemNodeID = InstanceIdentifier.AddSuffix(parentNodeID, childItem.SymbolicName.Name); string _stringItemNodeId = InstanceIdentifier.NodeId(_itemNodeID); if (!this.m_dictionary.ContainsKey(_stringItemNodeId)) { this.Add(_stringItemNodeId, childItem, _itemNodeID, parentAddressSpaceIndex, isInstanceDeclaration); } else { string _msg = String.Format("The node {0} is declared twice and has been removed from the model", childItem.SymbolicName.ToString()); m_compiler.Assert(false, parentAddressSpaceIndex, _msg); } }
/// <inheritdoc /> public async Task <WorkflowInstance> BuildWorkflow(WorkflowStructure workflow) { logger.LogInformation("Building workflow '{name}'", workflow.Name); int startcount = workflow.Nodes.Count(n => n.Type == NodeType.Start); if (startcount == 0) { throw new ArgumentException("Workflow has no start node"); } if (startcount > 1) { throw new ArgumentException("Workflow has more than one start node"); } StartNode startnode = null; List <IInstanceNode> nodes = new List <IInstanceNode>(); foreach (NodeData node in workflow.Nodes) { IInstanceNode nodeinstance = await BuildNode(workflow.Language, node); nodes.Add(nodeinstance); if (nodeinstance is StartNode startinstance) { startnode = startinstance; } } foreach (IndexTransition transition in workflow.Transitions) { await BuildTransition(workflow, transition.OriginIndex, transition.TargetIndex, transition, i => nodes[i]); } return(new WorkflowInstance { Name = workflow.Name, StartNode = startnode, Language = workflow.Language }); }
async Task <InstanceTransition> EvaluateTransitions(IInstanceNode current, WorkableLogger tasklogger, IVariableProvider variableprovider, List <InstanceTransition> transitions, CancellationToken token) { if (transitions == null) { return(null); } InstanceTransition transition = null; foreach (InstanceTransition conditionaltransition in transitions.Where(c => c.Condition != null)) { if (await conditionaltransition.Condition.ExecuteAsync <bool>(variableprovider, token)) { transition = conditionaltransition; break; } } if (transition == null) { InstanceTransition[] defaulttransitions = transitions.Where(t => t.Condition == null).ToArray(); if (defaulttransitions.Length > 1) { throw new InvalidOperationException($"More than one default transition defined for '{current.NodeName}'."); } transition = defaulttransitions.FirstOrDefault(); } if (transition?.Log != null) { try { tasklogger.Info(await transition.Log.ExecuteAsync <string>(variableprovider, token)); } catch (Exception e) { tasklogger.Error($"Error executing transition log of '{current.NodeName}'->'{transition.Target?.NodeName}'", e); throw; } } return(transition); }
/// <summary> /// Adds an information model instance node <paramref name="node" /> to address space. /// It is used to register an existing node. /// </summary> /// <param name="node">The node to be added to the address space.</param> void IAddressSpaceCreator.AddNode2AddressSpace(IInstanceNode node) { new InstanceNodeContext(this, node); }
/// <summary> /// Adds the instance declaration of. /// </summary> /// <param name="node">The node to be duplicated by deriving from the instance declaration.</param> /// <param name="typeParentID">The parent identifier of the type provisioning instance declarations - prefix to the relative reference path.</param> void IInstanceNodeContext.AddInstanceDeclarationOf(IInstanceNode node, XmlQualifiedName typeParentID) { InstanceWrapper = InstanceWrapper.DerivePropertyValuesFrom((IInstanceDesign)node.Wrapper4PropertyGrid); node.AddAllReferences4InstanceDeclaration(m_References, typeParentID); }
/// <summary> /// Initializes a new instance of the <see cref="InstanceNodeContext"/> class that represents an instance that is on top of inheritance chain. /// </summary> /// <param name="addressSpaceCompiler">The address space compiler.</param> /// <param name="node">The node.</param> internal InstanceNodeContext(AddressSpaceCompiler addressSpaceCompiler, IInstanceNode node) { Initialize(addressSpaceCompiler, node, node.SymbolicName, false, new Nullable <int>()); this.RegisterInstanceNodeInAddressSpace(); }
/// <summary> /// Initializes a new instance of the <see cref="InstanceDeclaration"/> class it represents existing child or an instance of instance declarations. /// </summary> /// <param name="space">The address space.</param> /// <param name="node">The node to be represented by the instance of this class.</param> /// <param name="nodeID">The node unique identifier - key in the directory created as the browse path.</param> /// <param name="parentAddressSpaceIndex">Index of the parent in the address space if exist.</param> /// <param name="isInstanceDeclaration">If set to <c>true</c> object of this type represents an instance declaration.</param> /// <param name="modelParent">The model parent.</param> internal InstanceNodeContext(AddressSpaceCompiler addressSpaceCompiler, IInstanceNode node, XmlQualifiedName nodeID, int?parentAddressSpaceIndex, bool isInstanceDeclaration) { Initialize(addressSpaceCompiler, node, nodeID, isInstanceDeclaration, parentAddressSpaceIndex); }
async Task <object> Execute(WorkflowInstanceState state, CancellationToken token, IInstanceNode current, object lastresult = null) { while (current != null) { try { if (state.Profiling) { Stopwatch stopwatch = Stopwatch.StartNew(); lastresult = await current.Execute(state, token); state.Logger.Performance(state.Workflow, current.NodeId, current.NodeName, stopwatch.Elapsed); } else { lastresult = await current.Execute(state, token); } if (token.IsCancellationRequested) { throw new TaskCanceledException(); } // used for workflow suspension if (lastresult is SuspendState) { return(lastresult); } } catch (Exception e) { state.Logger.Warning($"Error while executing node '{current.NodeName}'", e.Message); InstanceTransition next = await EvaluateTransitions(current, state.Logger, new VariableProvider(state.Variables, new Variable("error", e)), current.ErrorTransitions, token); if (next == null) { throw; } current = next.Target; continue; } try { InstanceTransition transition; if (lastresult is LoopCommand) { if (current.LoopTransitions.Count == 0) { throw new InvalidOperationException("Iterator node without any loop transitions detected."); } transition = await EvaluateTransitions(current, state.Logger, state.Variables, current.LoopTransitions, token); current = transition?.Target ?? current; } else { transition = await EvaluateTransitions(current, state.Logger, state.Variables, current.Transitions, token); current = transition?.Target; } } catch (Exception e) { state.Logger.Warning($"Error while evaluating transitions of node '{current?.NodeName}'", e.Message); InstanceTransition next = await EvaluateTransitions(current, state.Logger, new VariableProvider(state.Variables, new Variable("error", e)), current?.ErrorTransitions, token); if (next == null) { throw; } current = next.Target; } } return(lastresult); }
private void Add(string nodeId, IInstanceNode node, XmlQualifiedName nodeID, int parentAddressSpaceIndex, bool isInstanceDeclaration) { this.m_dictionary.Add(nodeId, new InstanceNodeContext(m_compiler, node, nodeID, parentAddressSpaceIndex, isInstanceDeclaration)); }
public static Task <object> Execute(IInstanceNode node, IDictionary <string, object> variables = null) { variables ??= new Dictionary <string, object>(); return(node.Execute(new WorkflowInstanceState(new WorkflowIdentifier(), new WorkableLogger(new NullLogger <NodeTest>(), new WorkableTask()), new StateVariableProvider(variables), s => null, null, null, false), CancellationToken.None)); }