Skip to content

Commit b5859aa

Browse files
committed
Merge pull request Azure#17 from jianghaolu/renamesetters
Renamings and DAGraph
2 parents 4736d63 + 24d5c1e commit b5859aa

File tree

10 files changed

+679
-3
lines changed

10 files changed

+679
-3
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.microsoft.azure;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* The type representing node in a {@link DAGraph}.
8+
*
9+
* @param <T> the type of the data stored in the node
10+
*/
11+
public class DAGNode<T> extends Node<T> {
12+
private List<String> dependentKeys;
13+
private int toBeResolved;
14+
15+
/**
16+
* Creates a DAG node.
17+
*
18+
* @param key unique id of the node
19+
* @param data data to be stored in the node
20+
*/
21+
public DAGNode(String key, T data) {
22+
super(key, data);
23+
dependentKeys = new ArrayList<>();
24+
}
25+
26+
/**
27+
* @return a list of keys of nodes in {@link DAGraph} those are dependents on this node
28+
*/
29+
List<String> dependentKeys() {
30+
return this.dependentKeys;
31+
}
32+
33+
/**
34+
* mark the node identified by the given key as dependent of this node.
35+
*
36+
* @param key the id of the dependent node
37+
*/
38+
public void addDependent(String key) {
39+
this.dependentKeys.add(key);
40+
}
41+
42+
/**
43+
* @return a list of keys of nodes in {@link DAGraph} that this node depends on
44+
*/
45+
public List<String> dependencyKeys() {
46+
return this.children();
47+
}
48+
49+
/**
50+
* mark the node identified by the given key as this node's dependency.
51+
*
52+
* @param dependencyKey the id of the dependency node
53+
*/
54+
public void addDependency(String dependencyKey) {
55+
toBeResolved++;
56+
super.addChild(dependencyKey);
57+
}
58+
59+
/**
60+
* @return <tt>true</tt> if this node has any dependency
61+
*/
62+
public boolean hasDependencies() {
63+
return this.hasChildren();
64+
}
65+
66+
/**
67+
* @return <tt>true</tt> if all dependencies of this node are ready to be consumed
68+
*/
69+
boolean hasAllResolved() {
70+
return toBeResolved == 0;
71+
}
72+
73+
/**
74+
* Reports that one of this node's dependency has been resolved and ready to be consumed.
75+
*
76+
* @param dependencyKey the id of the dependency node
77+
*/
78+
void reportResolved(String dependencyKey) {
79+
if (toBeResolved == 0) {
80+
throw new RuntimeException("invalid state - " + this.key() + ": The dependency '" + dependencyKey + "' is already reported or there is no such dependencyKey");
81+
}
82+
toBeResolved--;
83+
}
84+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package com.microsoft.azure;
2+
3+
import java.util.ArrayDeque;
4+
import java.util.Map;
5+
import java.util.Queue;
6+
7+
/**
8+
* Type representing a DAG (directed acyclic graph).
9+
* <p>
10+
* each node in a DAG is represented by {@link DAGNode}
11+
*
12+
* @param <T> the type of the data stored in the graph nodes
13+
* @param <U> the type of the nodes in the graph
14+
*/
15+
public class DAGraph<T, U extends DAGNode<T>> extends Graph<T, U> {
16+
private Queue<String> queue;
17+
private boolean hasParent;
18+
private U rootNode;
19+
20+
/**
21+
* Creates a new DAG.
22+
*
23+
* @param rootNode the root node of this DAG
24+
*/
25+
public DAGraph(U rootNode) {
26+
this.rootNode = rootNode;
27+
this.queue = new ArrayDeque<>();
28+
this.addNode(rootNode);
29+
}
30+
31+
/**
32+
* @return <tt>true</tt> if this DAG is merged with another DAG and hence has a parent
33+
*/
34+
public boolean hasParent() {
35+
return hasParent;
36+
}
37+
38+
/**
39+
* Checks whether the given node is root node of this DAG.
40+
*
41+
* @param node the node {@link DAGNode} to be checked
42+
* @return <tt>true</tt> if the given node is root node
43+
*/
44+
public boolean isRootNode(U node) {
45+
return this.rootNode == node;
46+
}
47+
48+
/**
49+
* Merge this DAG with another DAG.
50+
* <p>
51+
* this will mark this DAG as a child DAG, the dependencies of nodes in this DAG will be merged
52+
* with (copied to) the parent DAG
53+
*
54+
* @param parent the parent DAG
55+
*/
56+
public void merge(DAGraph<T, U> parent) {
57+
this.hasParent = true;
58+
parent.rootNode.addDependency(this.rootNode.key());
59+
this.rootNode.addDependent(parent.rootNode.key());
60+
for (Map.Entry<String, U> entry: graph.entrySet()) {
61+
String key = entry.getKey();
62+
if (!parent.graph.containsKey(key)) {
63+
parent.graph.put(key, entry.getValue());
64+
}
65+
}
66+
}
67+
68+
/**
69+
* Prepares this DAG for traversal using getNext method, each call to getNext returns next node
70+
* in the DAG with no dependencies.
71+
*/
72+
public void prepare() {
73+
initializeQueue();
74+
if (queue.isEmpty()) {
75+
throw new RuntimeException("Found circular dependency");
76+
}
77+
}
78+
79+
/**
80+
* Gets next node in the DAG which has no dependency or all of it's dependencies are resolved and
81+
* ready to be consumed.
82+
* <p>
83+
* null will be returned when all the nodes are explored
84+
*
85+
* @return next node
86+
*/
87+
public U getNext() {
88+
return graph.get(queue.poll());
89+
}
90+
91+
/**
92+
* Gets the data stored in a graph node with a given key.
93+
*
94+
* @param key the key of the node
95+
* @return the value stored in the node
96+
*/
97+
public T getNodeData(String key) {
98+
return graph.get(key).data();
99+
}
100+
101+
/**
102+
* Reports that a node is resolved hence other nodes depends on it can consume it.
103+
*
104+
* @param completed the node ready to be consumed
105+
*/
106+
public void reportedCompleted(U completed) {
107+
String dependency = completed.key();
108+
for (String dependentKey : graph.get(dependency).dependentKeys()) {
109+
DAGNode<T> dependent = graph.get(dependentKey);
110+
dependent.reportResolved(dependency);
111+
if (dependent.hasAllResolved()) {
112+
queue.add(dependent.key());
113+
}
114+
}
115+
}
116+
117+
/**
118+
* populate dependents of all nodes.
119+
* <p>
120+
* the DAG will be explored in DFS order and all node's dependents will be identified,
121+
* this prepares the DAG for traversal using getNext method, each call to getNext returns next node
122+
* in the DAG with no dependencies.
123+
*/
124+
public void populateDependentKeys() {
125+
this.queue.clear();
126+
visit(new Visitor<U>() {
127+
@Override
128+
public void visit(U node) {
129+
if (node.dependencyKeys().isEmpty()) {
130+
queue.add(node.key());
131+
return;
132+
}
133+
134+
String dependentKey = node.key();
135+
for (String dependencyKey : node.dependencyKeys()) {
136+
graph.get(dependencyKey)
137+
.dependentKeys()
138+
.add(dependentKey);
139+
}
140+
}
141+
});
142+
}
143+
144+
/**
145+
* Initializes the queue that tracks the next set of nodes with no dependencies or
146+
* whose dependencies are resolved.
147+
*/
148+
private void initializeQueue() {
149+
this.queue.clear();
150+
for (Map.Entry<String, U> entry: graph.entrySet()) {
151+
if (!entry.getValue().hasDependencies()) {
152+
this.queue.add(entry.getKey());
153+
}
154+
}
155+
}
156+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.microsoft.azure;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.Map;
6+
import java.util.Set;
7+
8+
/**
9+
* Type representing a directed graph data structure.
10+
* <p>
11+
* each node in a graph is represented by {@link Node}
12+
*
13+
* @param <T> the type of the data stored in the graph's nodes
14+
* @param <U> the type of the nodes in the graph
15+
*/
16+
public class Graph<T, U extends Node<T>> {
17+
protected Map<String, U> graph;
18+
private Set<String> visited;
19+
20+
/**
21+
* Creates a directed graph.
22+
*/
23+
public Graph() {
24+
this.graph = new HashMap<>();
25+
this.visited = new HashSet<>();
26+
}
27+
28+
/**
29+
* Adds a node to this graph.
30+
*
31+
* @param node the node
32+
*/
33+
public void addNode(U node) {
34+
graph.put(node.key(), node);
35+
}
36+
37+
/**
38+
* Represents a visitor to be implemented by the consumer who want to visit the
39+
* graph's nodes in DFS order.
40+
*
41+
* @param <U> the type of the node
42+
*/
43+
interface Visitor<U> {
44+
/**
45+
* visit a node.
46+
*
47+
* @param node the node to visited
48+
*/
49+
void visit(U node);
50+
}
51+
52+
/**
53+
* Perform DFS visit in this graph.
54+
* <p>
55+
* The directed graph will be traversed in DFS order and the visitor will be notified as
56+
* search explores each node
57+
*
58+
* @param visitor the graph visitor
59+
*/
60+
public void visit(Visitor visitor) {
61+
for (Map.Entry<String, ? extends Node<T>> item : graph.entrySet()) {
62+
if (!visited.contains(item.getKey())) {
63+
this.dfs(visitor, item.getValue());
64+
}
65+
}
66+
visited.clear();
67+
}
68+
69+
private void dfs(Visitor visitor, Node<T> node) {
70+
visitor.visit(node);
71+
visited.add(node.key());
72+
for (String childKey : node.children()) {
73+
if (!visited.contains(childKey)) {
74+
this.dfs(visitor, this.graph.get(childKey));
75+
}
76+
}
77+
}
78+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.microsoft.azure;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Type represents a node in a {@link Graph}.
8+
*
9+
* @param <T> the type of the data stored in the node
10+
*/
11+
public class Node<T> {
12+
private String key;
13+
private T data;
14+
private List<String> children;
15+
16+
/**
17+
* Creates a graph node.
18+
*
19+
* @param key unique id of the node
20+
* @param data data to be stored in the node
21+
*/
22+
public Node(String key, T data) {
23+
this.key = key;
24+
this.data = data;
25+
this.children = new ArrayList<>();
26+
}
27+
28+
/**
29+
* @return this node's unique id
30+
*/
31+
public String key() {
32+
return this.key;
33+
}
34+
35+
/**
36+
* @return data stored in this node
37+
*/
38+
public T data() {
39+
return data;
40+
}
41+
42+
/**
43+
* @return <tt>true</tt> if this node has any children
44+
*/
45+
public boolean hasChildren() {
46+
return !this.children.isEmpty();
47+
}
48+
49+
/**
50+
* @return children (neighbours) of this node
51+
*/
52+
public List<String> children() {
53+
return this.children;
54+
}
55+
56+
/**
57+
* @param childKey add a child (neighbour) of this node
58+
*/
59+
public void addChild(String childKey) {
60+
this.children.add(childKey);
61+
}
62+
}

0 commit comments

Comments
 (0)