View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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   * A {@code Validator} which does cyclic checks
27   * @author Nadeem Mohammad
28   *
29   * @param <T> Type of Node/Task ID
30   * @param <R> Type of Node/Task result
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  }