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.Collection;
21 import java.util.LinkedHashSet;
22 import java.util.Set;
23
24 /**
25 * Dependency would be constructed based on this APIs, Dexecutor uses this data structure to represent the dependencies between tasks
26 * @author Nadeem Mohammad
27 *
28 * @param <T> Type of Node/Task ID
29 * @param <R> Type of Node/Task result
30 */
31 public interface Graph<T extends Comparable<T>, R> {
32 /**
33 * Should add the two nodes in the datastructure in such a way that {@code evalFirstValue} should be evaluated before {@code evalAfterValue}.
34 * Nodes should be created only if it is not already added.
35 *
36 * @param evalFirstValue
37 * @param evalAfterValue
38 */
39 void addDependency(final T evalFirstValue, final T evalAfterValue);
40 /**
41 * Adds the given node to the datastructure whith out any dependency
42 * Nodes should be created only if it is not already added.
43 * @param nodeValue
44 */
45 void addIndependent(final T nodeValue);
46 /**
47 * Returns the Set of nodes for which there is no incoming dependencies.
48 * @return set of initial nodes
49 */
50 Set<Node<T, R>> getInitialNodes();
51 /**
52 * Retruns the set of nodes for which there is no outgoing dependencies.
53 * @return set of leaf nodes
54 */
55 Set<Node<T, R>> getLeafNodes();
56 /**
57 * Returns all nodes in this graph
58 * @return all nodes in this graph
59 */
60 Collection<Node<T, R>> allNodes();
61 /**
62 * Returns the total number of nodes in this graph
63 *
64 * @return total number of nodes in this graph
65 */
66 int size();
67
68 /**
69 * A node representation in this graph, every node may have set of incoming edges and outgoing edges, a node is represented by unique value
70 *
71 * @author Nadeem Mohammad
72 *
73 * @param <T>
74 */
75 public final class Node<T, R> {
76 /**
77 * Unique id of the node
78 */
79 private T value;
80 /**
81 * Execution result of this node
82 */
83 private R result;
84 /**
85 * Execution status of this node
86 */
87 private NodeStatus status;
88 /**
89 * incoming dependencies for this node
90 */
91 private Set<Node<T, R>> inComingEdges = new LinkedHashSet<Graph.Node<T, R>>();
92 /**
93 * outgoing dependencies for this node
94 */
95 private Set<Node<T, R>> outGoingEdges = new LinkedHashSet<Graph.Node<T, R>>();
96 /**
97 * Constructs the node with the given node Id
98 * @param val
99 */
100 public Node(final T val) {
101 this.value = val;
102 }
103 /**
104 * Add the given node, to the set of incoming nodes
105 * @param node
106 */
107 public void addInComingNode(final Node<T, R> node) {
108 this.inComingEdges.add(node);
109 }
110 /**
111 * add the given to the set of out going nodes
112 * @param node
113 */
114 public void addOutGoingNode(final Node<T, R> node) {
115 this.outGoingEdges.add(node);
116 }
117 /**
118 *
119 * @return the set of incoming nodes
120 */
121 public Set<Node<T, R>> getInComingNodes() {
122 return this.inComingEdges;
123 }
124 /**
125 *
126 * @return set of out going nodes
127 */
128 public Set<Node<T, R>> getOutGoingNodes() {
129 return this.outGoingEdges;
130 }
131 /**
132 *
133 * @return the node's value
134 */
135 public T getValue() {
136 return this.value;
137 }
138
139 public R getResult() {
140 return result;
141 }
142
143 public void setResult(final R result) {
144 this.result = result;
145 }
146
147 public boolean isSuccess() {
148 return NodeStatus.SUCCESS.equals(this.status);
149 }
150
151 public boolean isErrored() {
152 return NodeStatus.ERRORED.equals(this.status);
153 }
154
155 public boolean isSkipped() {
156 return NodeStatus.SKIPPED.equals(this.status);
157 }
158
159 public void setSuccess() {
160 this.status = NodeStatus.SUCCESS;
161 }
162
163 public void setErrored() {
164 this.status = NodeStatus.ERRORED;
165 }
166
167 public void setSkipped() {
168 this.status = NodeStatus.SKIPPED;
169 }
170
171 @Override
172 public int hashCode() {
173 final int prime = 31;
174 int result = 1;
175 result = prime * result + ((this.value == null) ? 0 : this.value.hashCode());
176 return result;
177 }
178
179 @Override
180 public boolean equals(final Object obj) {
181 if (obj == this) {
182 return true;
183 }
184 if (obj == null || obj.getClass() != this.getClass()) {
185 return false;
186 }
187 @SuppressWarnings("unchecked")
188 Node<T, R> other = (Node<T, R>) obj;
189
190 return this.value.equals(other.value);
191 }
192
193 @Override
194 public String toString() {
195 return String.valueOf(this.value);
196 }
197 }
198 /**
199 * Represents node's execution status
200 *
201 * @author Nadeem Mohammad
202 *
203 */
204 public enum NodeStatus {
205 ERRORED,SKIPPED,SUCCESS;
206 }
207 }