KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > hudson > model > DependencyGraph


1 package hudson.model;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Collection JavaDoc;
5 import java.util.Collections JavaDoc;
6 import java.util.Comparator JavaDoc;
7 import java.util.HashMap JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Map JavaDoc;
10 import java.util.Set JavaDoc;
11 import java.util.HashSet JavaDoc;
12 import java.util.Stack JavaDoc;
13 import java.util.Map.Entry;
14
15 /**
16  * Maintains the build dependencies between {@link AbstractProject}s
17  * for efficient dependency computation.
18  *
19  * <p>
20  * The "master" data of dependencies are owned/persisted/maintained by
21  * individual {@link AbstractProject}s, but because of that, it's relatively
22  * slow to compute backward edges.
23  *
24  * <p>
25  * This class builds the complete bi-directional dependency graph
26  * by collecting information from all {@link AbstractProject}s.
27  *
28  * <p>
29  * Once built, {@link DependencyGraph} is immutable, and every time
30  * there's a change (which is relatively rare), a new instance
31  * will be created. This eliminates the need of synchronization.
32  *
33  * @author Kohsuke Kawaguchi
34  */

35 public final class DependencyGraph {
36
37     private Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> forward = new HashMap JavaDoc<AbstractProject, List JavaDoc<AbstractProject>>();
38     private Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> backward = new HashMap JavaDoc<AbstractProject, List JavaDoc<AbstractProject>>();
39
40     private boolean built;
41
42     /**
43      * Builds the dependency graph.
44      */

45     public DependencyGraph() {
46         for( AbstractProject p : Hudson.getInstance().getAllItems(AbstractProject.class) )
47             p.buildDependencyGraph(this);
48
49         forward = finalize(forward);
50         backward = finalize(backward);
51
52         built = true;
53     }
54
55     /**
56      * Special constructor for creating an empty graph
57      */

58     private DependencyGraph(boolean dummy) {
59         forward = backward = Collections.emptyMap();
60         built = true;
61     }
62
63     /**
64      * Gets all the immediate downstream projects (IOW forward edges) of the given project.
65      *
66      * @return
67      * can be empty but never null.
68      */

69     public List JavaDoc<AbstractProject> getDownstream(AbstractProject p) {
70         return get(forward,p);
71     }
72
73     /**
74      * Gets all the immediate upstream projects (IOW backward edges) of the given project.
75      *
76      * @return
77      * can be empty but never null.
78      */

79     public List JavaDoc<AbstractProject> getUpstream(AbstractProject p) {
80         return get(backward,p);
81     }
82
83     private List JavaDoc<AbstractProject> get(Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> map, AbstractProject src) {
84         List JavaDoc<AbstractProject> v = map.get(src);
85         if(v!=null) return v;
86         else return Collections.emptyList();
87     }
88
89     /**
90      * Called during the dependency graph build phase to add a dependency edge.
91      */

92     public void addDependency(AbstractProject from, AbstractProject to) {
93         if(built)
94             throw new IllegalStateException JavaDoc();
95         add(forward,from,to);
96         add(backward,to,from);
97     }
98
99     public void addDependency(AbstractProject from, Collection JavaDoc<? extends AbstractProject> to) {
100         for (AbstractProject p : to)
101             addDependency(from,p);
102     }
103
104     public void addDependency(Collection JavaDoc<? extends AbstractProject> from, AbstractProject to) {
105         for (AbstractProject p : from)
106             addDependency(p,to);
107     }
108
109     /**
110      * Returns true if a project has a non-direct dependency to another project.
111      * <p>
112      * A non-direct dependency is a path of dependency "edge"s from the source to the destination,
113      * where the length is greater than 1.
114      */

115     public boolean hasIndirectDependencies(AbstractProject src, AbstractProject dst) {
116         Set JavaDoc<AbstractProject> visited = new HashSet JavaDoc<AbstractProject>();
117         Stack JavaDoc<AbstractProject> queue = new Stack JavaDoc<AbstractProject>();
118
119         queue.addAll(getDownstream(src));
120         queue.remove(dst);
121
122         while(!queue.isEmpty()) {
123             AbstractProject p = queue.pop();
124             if(p==dst)
125                 return true;
126             if(visited.add(p))
127                 queue.addAll(getDownstream(p));
128         }
129
130         return false;
131     }
132
133     /**
134      * Gets all the direct and indirect upstream dependencies of the given project.
135      */

136     public Set JavaDoc<AbstractProject> getTransitiveUpstream(AbstractProject src) {
137         return getTransitive(backward,src);
138     }
139
140     /**
141      * Gets all the direct and indirect downstream dependencies of the given project.
142      */

143     public Set JavaDoc<AbstractProject> getTransitiveDownstream(AbstractProject src) {
144         return getTransitive(forward,src);
145     }
146
147     private Set JavaDoc<AbstractProject> getTransitive(Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> direction, AbstractProject src) {
148         Set JavaDoc<AbstractProject> visited = new HashSet JavaDoc<AbstractProject>();
149         Stack JavaDoc<AbstractProject> queue = new Stack JavaDoc<AbstractProject>();
150
151         queue.add(src);
152
153         while(!queue.isEmpty()) {
154             AbstractProject p = queue.pop();
155
156             for (AbstractProject child : get(direction,p)) {
157                 if(visited.add(child))
158                     queue.add(child);
159             }
160         }
161
162         return visited;
163     }
164
165     private void add(Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> map, AbstractProject src, AbstractProject dst) {
166         List JavaDoc<AbstractProject> set = map.get(src);
167         if(set==null) {
168             set = new ArrayList JavaDoc<AbstractProject>();
169             map.put(src,set);
170         }
171         set.add(dst);
172     }
173
174     private Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> finalize(Map JavaDoc<AbstractProject, List JavaDoc<AbstractProject>> m) {
175         for (Entry<AbstractProject, List JavaDoc<AbstractProject>> e : m.entrySet()) {
176             Collections.sort( e.getValue(), NAME_COMPARATOR );
177             e.setValue( Collections.unmodifiableList(e.getValue()) );
178         }
179         return Collections.unmodifiableMap(m);
180     }
181
182     private static final Comparator JavaDoc<AbstractProject> NAME_COMPARATOR = new Comparator JavaDoc<AbstractProject>() {
183         public int compare(AbstractProject lhs, AbstractProject rhs) {
184             return lhs.getName().compareTo(rhs.getName());
185         }
186     };
187
188     public static final DependencyGraph EMPTY = new DependencyGraph(false);
189 }
190
Popular Tags