1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package com.github.dexecutor.executor.graph;
19
20 import java.util.ArrayList;
21 import java.util.Collection;
22
23 import com.github.dexecutor.executor.graph.Graph.Node;
24
25
26
27
28
29
30
31
32 public class CyclicValidator<T extends Comparable<T>, R> implements Validator<T, R> {
33
34 private Collection<Graph.Node<T, R>> processedNodes = new ArrayList<Graph.Node<T, R>>();
35 private Collection<Graph.Node<T, R>> onStackNodes = new ArrayList<Graph.Node<T, R>>();
36
37 public void validate(final Graph<T, R> graph) {
38 doProcess(graph.allNodes());
39 }
40
41 private void doProcess(final Collection<Graph.Node<T, R>> nodes) {
42 for (Graph.Node<T, R> node : nodes) {
43 detectCycle(node);
44 }
45 }
46
47 private void detectCycle(final Node<T, R> node) {
48 this.processedNodes.add(node);
49 this.onStackNodes.add(node);
50 doDepthFirstTraversal(node);
51 this.onStackNodes.remove(node);
52 }
53
54 private void doDepthFirstTraversal(final Node<T, R> node) {
55 for (Node<T, R> adjNode : node.getOutGoingNodes()) {
56 if (!isAlreadyProcessed(adjNode)) {
57 detectCycle(adjNode);
58 } else if (isOnStack(adjNode)) {
59 throw new IllegalArgumentException("Cycle Detected " + node + " With " + adjNode);
60 }
61 }
62 }
63
64 private boolean isAlreadyProcessed(final Node<T, R> node) {
65 return this.processedNodes.contains(node);
66 }
67
68 private boolean isOnStack(final Node<T, R> node) {
69 return this.onStackNodes.contains(node);
70 }
71 }