View Javadoc
1   package com.github.dexecutor.executor.graph;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   
6   import com.github.dexecutor.executor.graph.Graph.Node;
7   
8   /**
9    * A {@code Validator} which does cyclic checks
10   * @author Nadeem Mohammad
11   *
12   * @param <T>
13   */
14  public class CyclicValidator<T extends Comparable<T>> implements Validator<T> {
15  
16  	private Collection<Graph.Node<T>> processedNodes = new ArrayList<Graph.Node<T>>();
17  	private Collection<Graph.Node<T>> onStackNodes = new ArrayList<Graph.Node<T>>();
18  
19  	public void validate(final Graph<T> graph) {
20  		doProcess(graph.allNodes());
21  	}
22  
23  	private void doProcess(final Collection<Graph.Node<T>> nodes) {
24  		for (Graph.Node<T> node : nodes) {
25  			detectCycle(node);
26  		}
27  	}
28  
29  	private void detectCycle(final Node<T> node) {
30  		this.processedNodes.add(node);
31  		this.onStackNodes.add(node);
32  		doDepthFirstTraversal(node);
33  		this.onStackNodes.remove(node);
34  	}
35  
36  	private void doDepthFirstTraversal(final Node<T> node) {
37  		for (Node<T> adjNode : node.getOutGoingNodes()) {
38  			if (!isAlreadyProcessed(adjNode)) {
39  				detectCycle(adjNode);
40  			} else if (isOnStack(adjNode)) {
41  				throw new IllegalArgumentException("Cycle Detected " + node + " With " + adjNode);
42  			}
43  		}
44  	}
45  
46  	private boolean isAlreadyProcessed(final Node<T> node) {
47  		return this.processedNodes.contains(node);
48  	}
49  
50  	private boolean isOnStack(final Node<T> node) {
51  		return this.onStackNodes.contains(node);
52  	}
53  }