private void RemoveUnsatisfiedSuccessorActivity(T activityId) { // Check to make sure the node really exists. if (!NodeLookup.TryGetValue(activityId, out Node <T, TActivity> node)) { return; } if (node.NodeType == NodeType.End || node.NodeType == NodeType.Normal) { // If the activity was an unsatisfied successor, then remove it from the lookup. IList <KeyValuePair <T, HashSet <Node <T, TActivity> > > > kvps = UnsatisfiedSuccessorsLookup.Where(x => x.Value.Select(y => y.Id).Contains(activityId)).ToList(); foreach (KeyValuePair <T, HashSet <Node <T, TActivity> > > kvp in kvps) { HashSet <Node <T, TActivity> > unsatisfiedSuccessorNodes = kvp.Value; unsatisfiedSuccessorNodes.RemoveWhere(x => x.Id.Equals(activityId)); if (!unsatisfiedSuccessorNodes.Any()) { UnsatisfiedSuccessorsLookup.Remove(kvp); } } } }
private void ResolveUnsatisfiedSuccessorActivities(T activityId) { // Check to make sure the node really exists. if (!NodeLookup.TryGetValue(activityId, out Node <T, TActivity> dependencyNode)) { return; } // Check to see if any existing activities were expecting this activity // as a dependency. If so, then then hook their nodes to this activity with an edge. if (UnsatisfiedSuccessorsLookup.TryGetValue(activityId, out HashSet <Node <T, TActivity> > unsatisfiedSuccessorNodes)) { // If the dependency node is an End or Isolated node, then convert it. if (dependencyNode.NodeType == NodeType.End) { dependencyNode.SetNodeType(NodeType.Normal); } else if (dependencyNode.NodeType == NodeType.Isolated) { dependencyNode.SetNodeType(NodeType.Start); } foreach (Node <T, TActivity> successorNode in unsatisfiedSuccessorNodes) { T edgeId = EdgeIdGenerator(); var edge = new Edge <T, TEvent>(EventGenerator(edgeId)); dependencyNode.OutgoingEdges.Add(edgeId); EdgeTailNodeLookup.Add(edgeId, dependencyNode); successorNode.IncomingEdges.Add(edgeId); EdgeHeadNodeLookup.Add(edgeId, successorNode); EdgeLookup.Add(edgeId, edge); } UnsatisfiedSuccessorsLookup.Remove(activityId); } }
public virtual void Reset() { EdgeLookup.Clear(); NodeLookup.Clear(); UnsatisfiedSuccessorsLookup.Clear(); EdgeHeadNodeLookup.Clear(); EdgeTailNodeLookup.Clear(); }
private void ResolveUnsatisfiedSuccessorActivities(T activityId) { // Check to make sure the edge really exists. if (!EdgeLookup.ContainsKey(activityId)) { return; } // Check to see if any existing activities were expecting this activity // as a dependency. If so, then then hook up their tail nodes to this // activity's head node with a dummy edge. if (UnsatisfiedSuccessorsLookup.TryGetValue(activityId, out HashSet <Node <T, TEvent> > unsatisfiedSuccessorTailNodes)) { // We know that there are unsatisfied dependencies, so create a head node. T headEventId = NodeIdGenerator(); var headNode = new Node <T, TEvent>(EventGenerator(headEventId)); headNode.IncomingEdges.Add(activityId); EdgeHeadNodeLookup.Add(activityId, headNode); NodeLookup.Add(headNode.Id, headNode); foreach (Node <T, TEvent> tailNode in unsatisfiedSuccessorTailNodes) { T dummyEdgeId = EdgeIdGenerator(); var dummyEdge = new Edge <T, TActivity>(DummyActivityGenerator(dummyEdgeId)); tailNode.IncomingEdges.Add(dummyEdgeId); EdgeHeadNodeLookup.Add(dummyEdgeId, tailNode); headNode.OutgoingEdges.Add(dummyEdgeId); EdgeTailNodeLookup.Add(dummyEdgeId, headNode); EdgeLookup.Add(dummyEdge.Id, dummyEdge); } UnsatisfiedSuccessorsLookup.Remove(activityId); } else { // No existing activities were expecting this activity as a dependency, // so attach it directly to the end node via a dummy. T headEventId = NodeIdGenerator(); Node <T, TEvent> dependencyHeadNode = new Node <T, TEvent>(EventGenerator(headEventId)); dependencyHeadNode.IncomingEdges.Add(activityId); EdgeHeadNodeLookup.Add(activityId, dependencyHeadNode); NodeLookup.Add(dependencyHeadNode.Id, dependencyHeadNode); T dummyEdgeId = EdgeIdGenerator(); var dummyEdge = new Edge <T, TActivity>(DummyActivityGenerator(dummyEdgeId)); dependencyHeadNode.OutgoingEdges.Add(dummyEdgeId); EdgeTailNodeLookup.Add(dummyEdgeId, dependencyHeadNode); EdgeLookup.Add(dummyEdgeId, dummyEdge); EndNode.IncomingEdges.Add(dummyEdgeId); EdgeHeadNodeLookup.Add(dummyEdgeId, EndNode); } }
private void RemoveUnsatisfiedSuccessorActivityDependencies(T activityId, HashSet <T> dependencies) { if (dependencies is null) { throw new ArgumentNullException(nameof(dependencies)); } // If the activity was an unsatisfied successor for these dependencies, // then remove them from the lookup. foreach (T dependencyId in dependencies) { if (UnsatisfiedSuccessorsLookup.TryGetValue(dependencyId, out HashSet <Node <T, TActivity> > unsatisfiedSuccessorNodes)) { unsatisfiedSuccessorNodes.RemoveWhere(x => x.Id.Equals(activityId)); if (!unsatisfiedSuccessorNodes.Any()) { UnsatisfiedSuccessorsLookup.Remove(dependencyId); } } } }
public override bool AddActivity(TActivity activity, HashSet <T> dependencies) { if (activity == null) { throw new ArgumentNullException(nameof(activity)); } if (dependencies is null) { throw new ArgumentNullException(nameof(dependencies)); } if (EdgeLookup.ContainsKey(activity.Id)) { return(false); } if (dependencies.Contains(activity.Id)) { return(false); } // Create a new edge for the activity. var edge = new Edge <T, TActivity>(activity); EdgeLookup.Add(edge.Id, edge); // We expect dependencies at some point. if (dependencies.Any()) { // Since we use dummy edges to connect all tail nodes, we can create // a new tail node for this edge. T tailEventId = NodeIdGenerator(); var tailNode = new Node <T, TEvent>(EventGenerator(tailEventId)); tailNode.OutgoingEdges.Add(edge.Id); EdgeTailNodeLookup.Add(edge.Id, tailNode); NodeLookup.Add(tailNode.Id, tailNode); // Check which of the expected dependencies currently exist. IList <T> existingDependencies = EdgeLookup.Keys.Intersect(dependencies).ToList(); IList <T> nonExistingDependencies = dependencies.Except(existingDependencies).ToList(); // If any expected dependencies currently exist, then hook up their head // node to this edge's tail node with dummy edges. foreach (T dependencyId in existingDependencies) { Node <T, TEvent> dependencyHeadNode = EdgeHeadNodeLookup[dependencyId]; T dummyEdgeId = EdgeIdGenerator(); var dummyEdge = new Edge <T, TActivity>(DummyActivityGenerator(dummyEdgeId)); tailNode.IncomingEdges.Add(dummyEdgeId); EdgeHeadNodeLookup.Add(dummyEdgeId, tailNode); // If the head node of the dependency is the End node, then convert it. if (dependencyHeadNode.NodeType == NodeType.End) { dependencyHeadNode.SetNodeType(NodeType.Normal); } dependencyHeadNode.OutgoingEdges.Add(dummyEdgeId); EdgeTailNodeLookup.Add(dummyEdgeId, dependencyHeadNode); EdgeLookup.Add(dummyEdgeId, dummyEdge); } // If any expected dependencies currently do not exist, then record their // IDs and add this edge's tail node as an unsatisfied successor. foreach (T dependencyId in nonExistingDependencies) { if (!UnsatisfiedSuccessorsLookup.TryGetValue(dependencyId, out HashSet <Node <T, TEvent> > tailNodes)) { tailNodes = new HashSet <Node <T, TEvent> >(); UnsatisfiedSuccessorsLookup.Add(dependencyId, tailNodes); } tailNodes.Add(tailNode); } } else { // No dependencies, so attach it directly to the start node. StartNode.OutgoingEdges.Add(edge.Id); EdgeTailNodeLookup.Add(edge.Id, StartNode); } ResolveUnsatisfiedSuccessorActivities(edge.Id); return(true); }
public override bool AddActivityDependencies(T activityId, HashSet <T> dependencies) { if (dependencies is null) { throw new ArgumentNullException(nameof(dependencies)); } if (!NodeLookup.TryGetValue(activityId, out Node <T, TActivity> node)) { return(false); } if (!dependencies.Any()) { return(true); } if (dependencies.Contains(activityId)) { return(false); } // If the node is an Start or Isolated node, then convert it. if (node.NodeType == NodeType.Start) { node.SetNodeType(NodeType.Normal); } else if (node.NodeType == NodeType.Isolated) { node.SetNodeType(NodeType.End); } // Check which of the expected dependencies currently exist. IList <T> existingDependencies = NodeLookup.Keys.Intersect(dependencies).ToList(); IList <T> nonExistingDependencies = dependencies.Except(existingDependencies).ToList(); // If any expected dependencies currently exist, generate an edge to connect them. foreach (T dependencyId in existingDependencies) { Node <T, TActivity> dependencyNode = NodeLookup[dependencyId]; T edgeId = EdgeIdGenerator(); var edge = new Edge <T, TEvent>(EventGenerator(edgeId)); node.IncomingEdges.Add(edgeId); EdgeHeadNodeLookup.Add(edgeId, node); // If the dependency node is an End or Isolated node, then convert it. if (dependencyNode.NodeType == NodeType.End) { dependencyNode.SetNodeType(NodeType.Normal); } else if (dependencyNode.NodeType == NodeType.Isolated) { dependencyNode.SetNodeType(NodeType.Start); } dependencyNode.OutgoingEdges.Add(edgeId); EdgeTailNodeLookup.Add(edgeId, dependencyNode); EdgeLookup.Add(edgeId, edge); } // If any expected dependencies currently do not exist, then record their // IDs and add this node as an unsatisfied successor. foreach (T dependencyId in nonExistingDependencies) { if (!UnsatisfiedSuccessorsLookup.TryGetValue(dependencyId, out HashSet <Node <T, TActivity> > successorNodes)) { successorNodes = new HashSet <Node <T, TActivity> >(); UnsatisfiedSuccessorsLookup.Add(dependencyId, successorNodes); } successorNodes.Add(node); } return(true); }