private void DrainWorkflowRule(CodeBuilder result, TapestryDesignerWorkflowRule workflowRule) { /// INIT IEnumerable <TapestryDesignerWorkflowItem> startingItems = _context.TapestryDesignerWorkflowItems.Where(i => i.ParentSwimlane.ParentWorkflowRule.Id == workflowRule.Id && (i.TypeClass == "uiItem" || i.SymbolType == "circle-single" || i.SymbolType == "envelope-start" || i.SymbolType == "circle-event")); // swimlane has starting item if (startingItems.Count() != workflowRule.Swimlanes.Count || startingItems.Select(wfi => wfi.ParentSwimlaneId).Except(workflowRule.Swimlanes.Select(sw => sw.Id)).Any()) { throw new TapestrySyntacticOmniusException("Each swimlane requires one starting item!"); } // starting item should be the same TapestryDesignerWorkflowItem defaultStartingItem = startingItems.FirstOrDefault(); foreach (TapestryDesignerWorkflowItem item in startingItems) { if (item.SymbolType != defaultStartingItem.SymbolType || item.ComponentName != defaultStartingItem.ComponentName) { throw new TapestrySyntacticOmniusException("Starting items has to be same for WorkflowRule"); } } // method name _methodName = workflowRule.Name.ToUpper() == "INIT" ? Tapestry.MethodName(null) : Tapestry.MethodName(defaultStartingItem.ComponentName); /// start build result.AppendLine($"public {(_methodName == Tapestry.MethodName(null) ? "override " : "")}void {_methodName}(string[] userRoleNames, Action<int, Block> _symbolAction)"); result.StartBlock(); /// swimlanes bool firstSwimlane = true; foreach (TapestryDesignerSwimlane swimlane in workflowRule.Swimlanes) { // roles if (!firstSwimlane) { result.Append("else "); } result.AppendLine($"if ({(string.IsNullOrEmpty(swimlane.Roles) ? "true" : string.Join("||", swimlane.Roles.Split(',').Select(r => $"userRoleNames.Contains(\"{r}\")")))})"); result.StartBlock(); /// WF (var item, int count) = DrainBranch(result, startingItems.Single(si => si.ParentSwimlaneId == swimlane.Id), BranchType.Method); if (item != null || count != 0) { _progressHandler.Warning("WF ends too soon"); } result.EndBlock(); // end if - roles firstSwimlane = false; } // has no required role result.AppendLine("else"); result.AppendLine($" throw new TapestryAuthenticationOmniusException(\"Authentication error\", \"{string.Join(",", workflowRule.Swimlanes.Select(sw => sw.Roles))}\" , string.Join(\",\", userRoleNames));"); result.EndBlock(); // end method }
private string _dictToBuildString(TapestryDesignerWorkflowItem item, Dictionary <string, string> dictionary, MethodInfo method) { List <string> result = new List <string>(); foreach (var pair in dictionary) { string resultValue = ForInput(item, pair.Key, pair.Value, method); if (resultValue != null) { result.Add($"{{ {pair.Key}, {resultValue} }}"); } } return($"new Dictionary<string, object> {{ {string.Join(",", result)}"); }
public string ForInput(TapestryDesignerWorkflowItem item, string innerParamName, string paramName, MethodInfo method) { ParameterInfo originParam = method.GetParameters().SingleOrDefault(p => p.Name == innerParamName && !p.ParameterType.IsArray); if (originParam == null) { ParameterInfo arrayParam = method.GetParameters().SingleOrDefault(p => p.ParameterType.IsArray && Regex.Match(innerParamName, RegexIsArray(p.Name)).Success); if (arrayParam == null) { _progressHandler.Warning($"[Block:{_currentBlockCommit.Name},WF:{_currentWFRule.Name},WFItemId:{item?.Id},Label:{item?.Label}] Method[{method.Name}] has no param[{innerParamName}], skipping..."); return(null); } } return(ForInput(paramName, originParam?.ParameterType)); }
private bool checkBlockHasRights(TapestryDesignerWorkflowItem item) { List <TapestryDesignerWorkflowConnection> connections = item.SourceToConnection.ToList(); if (connections.Count < 2) { return(false); } TapestryDesignerSwimlane originalSwimlane = item.ParentSwimlane; foreach (var connection in connections) { if (connection.Target.ParentSwimlane != originalSwimlane) { return(true); } } return(false); }
private ActionRule createActionRule(TapestryDesignerWorkflowRule workflowRule, Block nonVirtualBlock, Block startBlock, TapestryDesignerWorkflowConnection connection, ref Dictionary <TapestryDesignerWorkflowItem, Block> blockMapping, Dictionary <Block, TapestryDesignerConditionGroup> conditionMapping, Dictionary <int, string> stateColumnMapping, HashSet <Block> blockHasRights, ref WorkFlow wf) { TapestryDesignerWorkflowItem item = connection.Target; // is there a button name? string init = item?.ComponentName; if (workflowRule.Name == "INIT" && nonVirtualBlock == startBlock) // initial ActionRule { init = "INIT"; } if (item?.TypeClass == "symbol" && (item?.SymbolType == "envelope-start" || item?.SymbolType == "circle-event")) // emailové workflow nebo socket listener { init = item?.Label; } if (item?.TypeClass == "symbol" && item?.SymbolType == "circle-single" && workflowRule.Name != "INIT") // REST ENDPOINT { init = workflowRule.Name; } string ActorName = (init != null ? "Manual" : "Auto"); ActionRule rule = new ActionRule { Actor = _context.Actors.Single(a => a.Name == ActorName), Name = $"{workflowRule.Name}: {startBlock.DisplayName} - {(_random.Next() % 1000000).ToString()}", ExecutedBy = init }; // condition if (conditionMapping.ContainsKey(startBlock)) { // branch true if (connection.SourceSlot == 0) { // copy condition to new db if (_masterContext != _context) { TapestryDesignerConditionGroup originConditionGroup = conditionMapping[startBlock]; // new conditionGroup TapestryDesignerConditionGroup conditionGroup = new TapestryDesignerConditionGroup { Application = _app, ResourceMappingPairId = originConditionGroup.ResourceMappingPairId }; rule.ConditionGroup = conditionGroup; // new conditionSet foreach (TapestryDesignerConditionSet originConditionSet in originConditionGroup.ConditionSets) { TapestryDesignerConditionSet conditionSet = new TapestryDesignerConditionSet { SetIndex = originConditionSet.SetIndex, SetRelation = originConditionSet.SetRelation }; conditionGroup.ConditionSets.Add(conditionSet); // new condition foreach (TapestryDesignerCondition originCondition in originConditionSet.Conditions) { TapestryDesignerCondition condition = new TapestryDesignerCondition { Index = originCondition.Index, Operator = originCondition.Operator, Relation = originCondition.Relation, Value = originCondition.Value, Variable = originCondition.Variable, }; conditionSet.Conditions.Add(condition); } } _context.TapestryDesignerConditionGroups.Add(conditionGroup); _context.SaveChanges(); } // same DB else { rule.ConditionGroup = conditionMapping[startBlock]; } } // branch false else { rule.isDefault = true; } } startBlock.SourceTo_ActionRules.Add(rule); // rights if (blockHasRights.Contains(startBlock) && item != null) { AddActionRuleRights(rule, item.ParentSwimlane); } TapestryDesignerWorkflowItem prevItem = null; while (item != null && // end WF (!blockMapping.ContainsKey(item) || // split || join (prevItem == null && connection.Source == connection.Target))) // split || join but starting action item { switch (item.TypeClass) { case "actionItem": //if (item.ActionId == 181) // noAction // break; string generatedInputVariables = ""; if (item.ActionId == 2005 || item.ActionId == 193) // Send mail, Send mail for each { foreach (var relatedConnections in workflowRule.Connections.Where(c => c.TargetId == item.Id)) { if (relatedConnections.Source.TypeClass == "templateItem") { generatedInputVariables = ";Template=s$" + relatedConnections.Source.Label; } } } if (item.ActionId == 3001 || item.ActionId == 3002 || item.ActionId == 3012) // Call SOAP, Call REST { foreach (var relatedConnections in workflowRule.Connections.Where(c => c.TargetId == item.Id)) { if (relatedConnections.Source.Label?.StartsWith("WS: ") ?? false) { generatedInputVariables = ";WSName=s$" + relatedConnections.Source.Label.Substring(4); } } } if (item.ActionId == 3004 || item.ActionId == 3005 || item.ActionId == 3006 || item.ActionId == 3007) // ExtDB Select / Insert / Update / Delete { foreach (var relatedConnections in workflowRule.Connections.Where(c => c.TargetId == item.Id)) { if (relatedConnections.Source.Label?.StartsWith("ExtDB: ") ?? false) { generatedInputVariables = ";dbName=s$" + relatedConnections.Source.Label.Substring(7); } } } if (item.ActionId == 3008) // Send to RabbitMQ { foreach (var relatedConnections in workflowRule.Connections.Where(c => c.TargetId == item.Id)) { if (relatedConnections.Source.Label?.StartsWith("RabbitMQ: ") ?? false) { generatedInputVariables = ";rabbitMQ=s$" + relatedConnections.Source.Label.Substring(10); } } } if (item.ActionId == 2007) // DataTable Response action { generatedInputVariables = ";BootstrapPageId=i$" + startBlock.BootstrapPageId; } ActionRule_Action result = new ActionRule_Action { ActionId = item.ActionId.Value, Order = rule.ActionRule_Actions.Any() ? rule.ActionRule_Actions.Max(aar => aar.Order) + 1 : 1, InputVariablesMapping = item.InputVariables + generatedInputVariables, OutputVariablesMapping = item.OutputVariables, VirtualParentId = item.ParentForeachId.HasValue ? item.ParentForeachId : null, IsForeachStart = item.IsForeachStart, IsForeachEnd = item.IsForeachEnd }; rule.ActionRule_Actions.Add(result); break; case "targetItem": if (_blockMapping.ContainsKey(item.Target)) { rule.TargetBlock = _blockMapping[item.Target]; } else { _progressHandler.Error($"Block [{item.Target.Name}] not found!"); } break; case "symbol": // No needed now //switch (item.SymbolType) //{ // case "gateway-x": // Block splitBlock = blockMapping[item]; // // if not already in conditionMapping // if (!conditionMapping.ContainsKey(splitBlock)) // conditionMapping.Add(splitBlock, item.Id); // break; //} break; case "circle-thick": break; case "attributeItem": break; case "templateItem": break; case "stateItem": if (stateColumnMapping.ContainsKey(item.StateId.Value)) { string stateColumn = stateColumnMapping[item.StateId.Value]; ActionRule_Action setStateAction = new ActionRule_Action { ActionId = 1029, Order = rule.ActionRule_Actions.Any() ? rule.ActionRule_Actions.Max(aar => aar.Order) + 1 : 1, InputVariablesMapping = $"ColumnName=s${stateColumn};StateId=i${item.StateId.Value}", OutputVariablesMapping = "" }; rule.ActionRule_Actions.Add(setStateAction); } break; case "circle-single": break; case "circle-single-dashed": break; case "uiItem": // DONE break; case "database": break; case "comment": break; case "virtualAction": switch (item.SymbolType) { case "foreach": HashSet <TapestryDesignerWorkflowConnection> todoConnections = new HashSet <TapestryDesignerWorkflowConnection>(); ActionRule_Action feResult = new ActionRule_Action { ActionId = -1, Order = rule.ActionRule_Actions.Any() ? rule.ActionRule_Actions.Max(aar => aar.Order) + 1 : 1, InputVariablesMapping = item.InputVariables, OutputVariablesMapping = item.OutputVariables, VirtualAction = "foreach", VirtualItemId = item.ParentForeachId }; rule.ActionRule_Actions.Add(feResult); // Uložíme akce uvnitř cyklu var splitItems = _masterContext.TapestryDesignerWorkflowItems.Where(i => i.ParentSwimlane.ParentWorkflowRule_Id == workflowRule.Id && i.TypeClass == "symbol" && _splitGateways.Contains(i.SymbolType) && i.ParentForeachId == item.ParentForeachId && i.Id != item.Id).ToList(); var joinItems = _masterContext.TapestryDesignerWorkflowItems.Where(i => i.ParentSwimlane.ParentWorkflowRule_Id == workflowRule.Id && (i.TargetToConnection.Count() > 1 || i.IsForeachStart == true) && i.ParentForeachId == item.ParentForeachId && i.Id != item.Id).ToList(); foreach (var splitItem in splitItems) { // block mapping int random = _random.Next() % 1000000; Block newBlock = new Block { Name = $"split_{nonVirtualBlock.Name}_{random}", DisplayName = $"split[{nonVirtualBlock.Name}_{random}]", ModelName = nonVirtualBlock.ModelName, IsVirtualForBlockId = nonVirtualBlock.Id }; wf.Blocks.Add(newBlock); blockMapping.Add(splitItem, newBlock); // conditions if (splitItem.SymbolType == "gateway-x") { try { conditionMapping.Add(newBlock, splitItem.ConditionGroups.Single()); } catch (InvalidOperationException ex) { throw new Exception("Gateway has no condition!", ex); } } // rights if (checkBlockHasRights(splitItem)) { blockHasRights.Add(newBlock); } // todo connection int connectionCount = splitItem.SourceToConnection.Count; if (connectionCount == 0) // wrong WF { throw new Exception($"Workflow ends with gateway - {nonVirtualBlock.Name}: {workflowRule.Name}"); } if (connectionCount == 1) // missing way - return to real Block { TapestryDesignerWorkflowConnection conn = splitItem.SourceToConnection.FirstOrDefault(); todoConnections.Add(conn); todoConnections.Add(new TapestryDesignerWorkflowConnection { SourceSlot = conn.SourceSlot == 0 ? 1 : 0, Source = splitItem }); } else // OK { foreach (TapestryDesignerWorkflowConnection conn in splitItem.SourceToConnection) { todoConnections.Add(conn); } } } foreach (var joinItem in joinItems) { if (blockMapping.ContainsKey(joinItem)) // split item & join item are same { continue; } // block mapping int random = _random.Next() % 1000000; Block newBlock = new Block { Name = $"join_{nonVirtualBlock.Name}_{random}", DisplayName = $"join[{nonVirtualBlock.Name}_{random}]", ModelName = nonVirtualBlock.ModelName, IsVirtualForBlockId = nonVirtualBlock.Id }; wf.Blocks.Add(newBlock); blockMapping.Add(joinItem, newBlock); // todo connection todoConnections.Add(new TapestryDesignerWorkflowConnection { Source = joinItem, Target = joinItem }); } foreach (TapestryDesignerWorkflowConnection conn in todoConnections) { createActionRule(workflowRule, nonVirtualBlock, blockMapping[conn.Source], conn, ref blockMapping, conditionMapping, stateColumnMapping, blockHasRights, ref wf); } break; default: break; } break; default: break; } // next item prevItem = item; item = workflowRule.Connections.FirstOrDefault(c => c.SourceId == item.Id)?.Target; } // real block not set (TargetItem) if (rule.TargetBlock == null) { // continue to next virtual Block if (item != null && blockMapping.ContainsKey(item)) { rule.TargetBlock = blockMapping[item]; } // return to origin real Block else { rule.TargetBlock = nonVirtualBlock; } } return(rule); }
private void saveWFRule(TapestryDesignerWorkflowRule workflowRule, Block block, WorkFlow wf, Dictionary <int, string> stateColumnMapping) { HashSet <TapestryDesignerWorkflowConnection> todoConnections = new HashSet <TapestryDesignerWorkflowConnection>(); Dictionary <TapestryDesignerWorkflowItem, Block> BlockMapping = new Dictionary <TapestryDesignerWorkflowItem, Block>(); Dictionary <Block, TapestryDesignerConditionGroup> conditionMapping = new Dictionary <Block, TapestryDesignerConditionGroup>(); HashSet <Block> blockHasRights = new HashSet <Block> { block }; // create virtual starting items TapestryDesignerWorkflowItem virtualBeginItem = new TapestryDesignerWorkflowItem(); BlockMapping.Add(virtualBeginItem, block); foreach (TapestryDesignerWorkflowItem item in _masterContext.TapestryDesignerWorkflowItems.Where(i => i.ParentSwimlane.ParentWorkflowRule.Id == workflowRule.Id && (i.TypeClass == "uiItem" || i.SymbolType == "circle-single" || i.SymbolType == "envelope-start" || i.SymbolType == "circle-event"))) { TapestryDesignerWorkflowConnection conn = new TapestryDesignerWorkflowConnection { Source = virtualBeginItem, Target = item }; todoConnections.Add(conn); } // var splitItems = _masterContext.TapestryDesignerWorkflowItems.Where(i => i.ParentSwimlane.ParentWorkflowRule_Id == workflowRule.Id && i.TypeClass == "symbol" && _splitGateways.Contains(i.SymbolType) && (i.ParentForeach == null || i.SymbolType == "foreach")).ToList(); var joinItems = _masterContext.TapestryDesignerWorkflowItems.Where(i => i.ParentSwimlane.ParentWorkflowRule_Id == workflowRule.Id && i.TargetToConnection.Count() > 1 && (i.ParentForeach == null || i.SymbolType == "foreach")).ToList(); foreach (var splitItem in splitItems) { // block mapping int random = _random.Next() % 1000000; Block newBlock = new Block { Name = $"split_{block.Name}_{random}", DisplayName = $"split[{block.Name}_{random}]", ModelName = block.ModelName, IsVirtualForBlockId = block.Id }; wf.Blocks.Add(newBlock); BlockMapping.Add(splitItem, newBlock); // conditions if (splitItem.SymbolType == "gateway-x") { try { conditionMapping.Add(newBlock, splitItem.ConditionGroups.Single()); } catch (InvalidOperationException ex) { throw new Exception("Gateway has no condition!", ex); } } // rights if (checkBlockHasRights(splitItem)) { blockHasRights.Add(newBlock); } // todo connection int connectionCount = splitItem.SourceToConnection.Count; if (connectionCount == 0) // wrong WF { throw new Exception($"Workflow ends with gateway - {block.Name}: {workflowRule.Name}"); } if (connectionCount == 1) // missing way - return to real Block { TapestryDesignerWorkflowConnection connection = splitItem.SourceToConnection.FirstOrDefault(); todoConnections.Add(connection); todoConnections.Add(new TapestryDesignerWorkflowConnection { SourceSlot = connection.SourceSlot == 0 ? 1 : 0, Source = splitItem }); } else // OK { foreach (TapestryDesignerWorkflowConnection connection in splitItem.SourceToConnection) { todoConnections.Add(connection); } } } foreach (var joinItem in joinItems) { if (BlockMapping.ContainsKey(joinItem)) // split item & join item are same { continue; } // block mapping int random = _random.Next() % 1000000; Block newBlock = new Block { Name = $"join_{block.Name}_{random}", DisplayName = $"join[{block.Name}_{random}]", ModelName = block.ModelName, IsVirtualForBlockId = block.Id }; wf.Blocks.Add(newBlock); BlockMapping.Add(joinItem, newBlock); // todo connection todoConnections.Add(new TapestryDesignerWorkflowConnection { Source = joinItem, Target = joinItem }); } //// ACTIONS //// foreach (TapestryDesignerWorkflowConnection connection in todoConnections) { createActionRule(workflowRule, block, BlockMapping[connection.Source], connection, ref BlockMapping, conditionMapping, stateColumnMapping, blockHasRights, ref wf); } }
private IEnumerable <string> transformInputParams(TapestryDesignerWorkflowItem item, string inputVariables, MethodInfo method) { /// parse Dictionary <string, string> pairs = new Dictionary <string, string>(); List <string> split = inputVariables.Trim().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List <string>(); foreach (string pair in split) { string[] splittedPair = pair.Split('='); if (splittedPair.Length != 2) { _progressHandler.Warning($"[Block:{_currentBlockCommit.Name},WF:{_currentWFRule.Name},WFItemId:{item.Id},Action:{method.Name}] WorkFlow item has incorrect InputVariables!"); continue; } string key = splittedPair[0]; string value = splittedPair[1]; /// dict if (value.Length > 1 && value[1] != '$' && value.Contains("::")) { var newDict = new Dictionary <string, string>(); var newPairs = value.Split(','); foreach (string newPair in newPairs) { var splitted = newPair.Split(':'); if (splitted.Length != 2) { _progressHandler.Warning($"[Block:{_currentBlockCommit.Name},WF:{_currentWFRule.Name},WFItemId:{item.Id},Action:{method.Name}] WorkFlow item has incorrect InputVariables for Dictionary!"); continue; } newDict.Add(splitted[0], splitted[1]); } // DBItem if (method.GetParameters().Single(p => p.Name == key).ParameterType == typeof(Entitron.DB.DBItem)) { value = $"new FSS.Omnius.Modules.Entitron.DB.DBItem(_core.Entitron, dict: {_dictToBuildString(item, newDict, method)})"; } else { value = _dictToBuildString(item, newDict, method); } } // key already exists if (pairs.ContainsKey(key)) { string realValue = ForInput(item, key, value, method); if (pairs[key] == realValue) { _progressHandler.Warning($"[Block:{_currentBlockCommit.Name},WF:{_currentWFRule.Name},WFItemId:{item.Id},Name:{item.Label}] Item has variable '{key}' defined multiple times"); continue; } else { throw new TapestrySyntacticOmniusException($"Single variable has multiple values - WFItem[Id:{item.Id}, Name:{item.Label}, Value1:{pairs[key]}, Value2:{realValue}]"); } } // skip empty string resultParam = ForInput(item, key, value, method); if (resultParam != null) { pairs.Add(key, resultParam); } } /// array // select params witch is array foreach (ParameterInfo param in method.GetParameters().Where(p => p.ParameterType.IsArray)) { // param items var currentMatches = pairs.ToDictionary(pair => pair, pair => Regex.Match(pair.Key, RegexIsArray(param.Name))).Where(pair => pair.Value.Success); // count string[] list = currentMatches.Any() ? new string[currentMatches.Max(p => Convert.ToInt32(p.Value.Groups[2].Value != "" ? p.Value.Groups[2].Value : "0") + 1)] : new string[0]; // fill list & remove from pairs foreach (var pair in currentMatches) { list[Convert.ToInt32(pair.Value.Groups[2].Value != "" ? pair.Value.Groups[2].Value : "0")] = pair.Key.Value; pairs.Remove(pair.Key.Key); } // add to pair pairs.Add(param.Name, $"new {param.ParameterType.Name} {{ {string.Join(",", list.Select(i => i != null ? (param.ParameterType.GetElementType() != typeof(object) ? $"Extend.ConvertTo<{_typeName(param.ParameterType.GetElementType())}>(_core, {i})" : i) : "null"))} }}"); } /// return return(pairs.Select(pair => $"{pair.Key}:{pair.Value}")); }
private (TapestryDesignerWorkflowItem, int) DrainBranch(CodeBuilder result, TapestryDesignerWorkflowItem startItem, BranchType branchType) { /// INIT int branchGoesThrought = 1; TapestryDesignerWorkflowItem currentItem = startItem; /// foreach in branch while (currentItem != null) { try { // join int targetToCount = currentItem.TargetToConnection.Count(c => c.Source.TypeClass != "integrationItem" && c.Source.TypeClass != "templateItem"); if (targetToCount > branchGoesThrought) { return(currentItem, branchGoesThrought); } else { branchGoesThrought = 1; } // compile symbol result.AppendLine($"_symbolAction({currentItem.Id}, this);"); // lock if (currentItem.HasParallelLock) { result.AppendLine($"lock (_core.Lock({currentItem.Id}))"); result.StartBlock(); } string inputVariables = currentItem.InputVariables ?? ""; switch (currentItem.TypeClass) { // action // action with params case "actionItem": // params var paramItem = currentItem.TargetToConnection.SingleOrDefault(c => c.Source.TypeClass == "integrationItem" || c.Source.TypeClass == "templateItem")?.Source; if (paramItem != null) { switch (paramItem.TypeClass) { case "integrationItem": inputVariables = $"{currentItem.InputVariables.Trim().TrimEnd(';')};WSName=s${paramItem.Label.Substring(4)}"; // remove 'WS: ' from beginning break; case "templateItem": inputVariables = $"{currentItem.InputVariables.Trim().TrimEnd(';')};Template=s${paramItem.Label}"; break; default: throw new NotImplementedException(); } } // Action if (!ActionManager.All.ContainsKey(currentItem.ActionId.Value)) { throw new TapestrySyntacticOmniusException($"Action[Id:{currentItem.ActionId.Value},Name:{currentItem.Label}] not found"); } TapestryAction action = ActionManager.All[currentItem.ActionId.Value]; result.AppendLine($"{ForOutput(currentItem.OutputVariables?.Trim(), action)}{action.Repository}.{action.Method.Name}(_core{string.Join("", transformInputParams(currentItem, inputVariables, action.Method).Select(p => $",{p}"))});"); break; // target case "targetItem": result.AppendLine($"this.TargetName = \"{currentItem.Target.Name.RemoveDiacritics()}\";"); result.AppendLine("return;"); break; // gw x // gw + case "symbol": switch (currentItem.SymbolType) { case "gateway-x": branchGoesThrought--; // removes current result.AppendLine($"if ({currentItem.ConditionGroups.SingleOrDefault()?.ToString(this) ?? "true"})"); result.StartBlock(); (var joinItem, int returnedBranchCount) = DrainBranch(result, currentItem.SourceToConnection.SingleOrDefault(c => c.SourceSlot == 0)?.Target, branchType); branchGoesThrought += returnedBranchCount; // add if result.Else(); (currentItem, returnedBranchCount) = DrainBranch(result, currentItem.SourceToConnection.SingleOrDefault(c => c.SourceSlot == 1)?.Target, branchType); branchGoesThrought += returnedBranchCount; // add else result.EndBlock(); // wrong syntactic - branch has to meet, if it not end if (joinItem != null && currentItem != null && joinItem != currentItem) { throw new TapestrySyntacticOmniusException($"Gateway ends on different items[{joinItem.Id}:{joinItem.Label}, {currentItem.Id}:{currentItem.Label}]"); } // 'else' ends with return -> continue with 'if' if (currentItem == null) { currentItem = joinItem; } continue; case "gateway-plus": branchGoesThrought--; // removes current TapestryDesignerWorkflowItem gatewayItem = currentItem; result.AppendLine($"_ParallelRun({gatewayItem.Id}, () => ThreadMethod_{gatewayItem.Id}(_symbolAction));"); (currentItem, returnedBranchCount) = DrainBranch(result, gatewayItem.SourceToConnection.Single(c => c.SourceSlot == 0).Target, branchType); branchGoesThrought += returnedBranchCount; _threadMethods.AppendLine($"private void ThreadMethod_{gatewayItem.Id}(Action<int, Block> _symbolAction)"); _threadMethods.StartBlock(); (joinItem, returnedBranchCount) = DrainBranch(_threadMethods, gatewayItem.SourceToConnection.Single(c => c.SourceSlot == 1).Target, BranchType.Method); branchGoesThrought += returnedBranchCount; _threadMethods.EndBlock(); // wrong syntactic - branch has to meet, if it not end if (joinItem != null && currentItem != null && joinItem != currentItem) { throw new TapestrySyntacticOmniusException($"Gateway ends on different items[{joinItem.Id}:{joinItem.Label}, {currentItem.Id}:{currentItem.Label}]"); } // merge if (joinItem != null && currentItem != null) { result.AppendLine($"_WaitForParallel({gatewayItem.Id});"); } continue; case "circle-single": // wf beginning // DONE break; } break; case "stateItem": break; // foreach case "virtualAction": string itemName = currentItem.ParentForeach.ItemName ?? "__item__"; switch (currentItem.SymbolType) { case "foreach": if (currentItem.ParentForeach.IsParallel) { result.AppendLine($"Parallel.ForEach((IEnumerable<dynamic>){_realGlobalVarName(currentItem.ParentForeach.DataSource)}, ({itemName}) => "); result.StartBlock(); _varNames.Add("__item__"); DrainBranch(result, _context.TapestryDesignerWorkflowItems.Single(i => i.ParentForeachId == currentItem.ParentForeachId && i.IsForeachStart == true), BranchType.Method); _varNames.Remove("__item__"); result.EndBlock(");"); // end foreach } else { result.AppendLine($"foreach (object {itemName} in (IEnumerable<dynamic>){_realGlobalVarName(currentItem.ParentForeach.DataSource)})"); result.StartBlock(); _varNames.Add(itemName); DrainBranch(result, _context.TapestryDesignerWorkflowItems.Single(i => i.ParentForeachId == currentItem.ParentForeachId && i.IsForeachStart == true), BranchType.ForeachLoop); _varNames.Remove(itemName); result.EndBlock(); // end foreach } break; } break; case "uiItem": // button - wf beginning case "integrationItem": // integration - param case "templateItem": // email template - param break; case "attributeItem": case "circle-single": default: throw new NotImplementedException(); } // lock if (currentItem.HasParallelLock) { result.EndBlock(); } /// next // foreach if (currentItem?.IsForeachEnd == true) { return(null, 0); } // ok currentItem = currentItem?.SourceToConnection.SingleOrDefault()?.Target; } catch (Exception ex) { throw new TapestrySyntacticOmniusException(ex.Message, currentItem?.Id, ex); } } /// END of thread, foreach or WF switch (branchType) { case BranchType.ForeachLoop: // compile end symbol result.AppendLine($"_symbolAction(-2, this);"); // next result.AppendLine("continue;"); break; case BranchType.Method: // compile end symbol result.AppendLine($"_symbolAction(-1, this);"); // end result.AppendLine("return;"); break; default: throw new Exception("Unknown branchType"); } return(null, 0); }