31 * deletion without notice.</b> |
31 * deletion without notice.</b> |
32 */ |
32 */ |
33 public class GraphUtils { |
33 public class GraphUtils { |
34 |
34 |
35 /** |
35 /** |
|
36 * Basic interface for defining various dependency kinds. All dependency kinds |
|
37 * must at least support basic capabilities to tell the DOT engine how to render them. |
|
38 */ |
|
39 public interface DependencyKind { |
|
40 /** |
|
41 * Returns the DOT representation (to be used in a {@code style} attribute |
|
42 * that's most suited for this dependency kind. |
|
43 */ |
|
44 String getDotStyle(); |
|
45 } |
|
46 |
|
47 /** |
36 * This class is a basic abstract class for representing a node. |
48 * This class is a basic abstract class for representing a node. |
37 * A node is associated with a given data. |
49 * A node is associated with a given data. |
38 */ |
50 */ |
39 public static abstract class Node<D> { |
51 public static abstract class Node<D> { |
40 public final D data; |
52 public final D data; |
41 |
53 |
42 public Node(D data) { |
54 public Node(D data) { |
43 this.data = data; |
55 this.data = data; |
44 } |
56 } |
45 |
57 |
46 public abstract Iterable<? extends Node<D>> getDependencies(); |
58 /** |
|
59 * Get an array of the dependency kinds supported by this node. |
|
60 */ |
|
61 public abstract DependencyKind[] getSupportedDependencyKinds(); |
47 |
62 |
48 public abstract String printDependency(Node<D> to); |
63 /** |
|
64 * Get all dependencies, regardless of their kind. |
|
65 */ |
|
66 public abstract Iterable<? extends Node<D>> getAllDependencies(); |
|
67 |
|
68 /** |
|
69 * Get a name for the dependency (of given kind) linking this node to a given node |
|
70 */ |
|
71 public abstract String getDependencyName(Node<D> to, DependencyKind dk); |
49 |
72 |
50 @Override |
73 @Override |
51 public String toString() { |
74 public String toString() { |
52 return data.toString(); |
75 return data.toString(); |
53 } |
76 } |
64 |
87 |
65 public TarjanNode(D data) { |
88 public TarjanNode(D data) { |
66 super(data); |
89 super(data); |
67 } |
90 } |
68 |
91 |
69 public abstract Iterable<? extends TarjanNode<D>> getDependencies(); |
92 public abstract Iterable<? extends TarjanNode<D>> getAllDependencies(); |
|
93 |
|
94 public abstract Iterable<? extends TarjanNode<D>> getDependenciesByKind(DependencyKind dk); |
70 |
95 |
71 public int compareTo(TarjanNode<D> o) { |
96 public int compareTo(TarjanNode<D> o) { |
72 return (index < o.index) ? -1 : (index == o.index) ? 0 : 1; |
97 return (index < o.index) ? -1 : (index == o.index) ? 0 : 1; |
73 } |
98 } |
74 } |
99 } |
93 v.index = index; |
118 v.index = index; |
94 v.lowlink = index; |
119 v.lowlink = index; |
95 index++; |
120 index++; |
96 stack.prepend(v); |
121 stack.prepend(v); |
97 v.active = true; |
122 v.active = true; |
98 for (TarjanNode<D> nd: v.getDependencies()) { |
123 for (TarjanNode<D> nd: v.getAllDependencies()) { |
99 @SuppressWarnings("unchecked") |
124 @SuppressWarnings("unchecked") |
100 N n = (N)nd; |
125 N n = (N)nd; |
101 if (n.index == -1) { |
126 if (n.index == -1) { |
102 tarjan(n, index, stack, cycles); |
127 tarjan(n, index, stack, cycles); |
103 v.lowlink = Math.min(v.lowlink, n.lowlink); |
128 v.lowlink = Math.min(v.lowlink, n.lowlink); |
132 for (TarjanNode<D> n : nodes) { |
157 for (TarjanNode<D> n : nodes) { |
133 buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.toString())); |
158 buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.toString())); |
134 } |
159 } |
135 //dump arcs |
160 //dump arcs |
136 for (TarjanNode<D> from : nodes) { |
161 for (TarjanNode<D> from : nodes) { |
137 for (TarjanNode<D> to : from.getDependencies()) { |
162 for (DependencyKind dk : from.getSupportedDependencyKinds()) { |
138 buf.append(String.format("%s -> %s [label = \" %s \"];\n", |
163 for (TarjanNode<D> to : from.getDependenciesByKind(dk)) { |
139 from.hashCode(), to.hashCode(), from.printDependency(to))); |
164 buf.append(String.format("%s -> %s [label = \" %s \" style = %s ];\n", |
|
165 from.hashCode(), to.hashCode(), from.getDependencyName(to, dk), dk.getDotStyle())); |
|
166 } |
140 } |
167 } |
141 } |
168 } |
142 buf.append("}\n"); |
169 buf.append("}\n"); |
143 return buf.toString(); |
170 return buf.toString(); |
144 } |
171 } |