1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.pkg;
21
22 import java.util.Arrays;
23 import java.util.HashSet;
24 import java.util.Hashtable;
25 import java.util.Iterator;
26 import java.util.LinkedList;
27 import java.util.TreeMap;
28
29 /***
30 *
31 */
32 public class DependencyGraph
33 {
34
35
36
37
38
39 private PackageManager manager;
40
41 private AndDependencyNode root;
42 private TreeMap nodeByPackage = new TreeMap();
43 private Hashtable nodeByToken = new Hashtable();
44 private LinkedList unparsedNodes = new LinkedList();
45
46
47
48 public DependencyGraph(PackageManager manager)
49 {
50 this.manager = manager;
51 root = new AndDependencyNode("Root");
52 }
53
54
55
56 public void add(PackageInfo info)
57 {
58 DependencyNode node = addNode(info);
59 root.add(node);
60 }
61
62 public void buildDependencies(DependencyParser parser) throws ParseException
63 {
64 while (!unparsedNodes.isEmpty()) {
65 PackageDependencyNode node
66 = (PackageDependencyNode)unparsedNodes.removeFirst();
67
68 try {
69
70 AbstractToken token = parser.parseDepends(node.getPackage());
71 if (token != null) {
72 node.setDepends(add(token));
73 }
74
75
76 token = parser.parseConflicts(node.getPackage());
77 if (token != null) {
78 node.setConflicts(new ConflictsDependencyNode
79 ("conflicts for " + node.getID(),
80 add(token)));
81 }
82 }
83 catch (ParseException e) {
84 throw new ParseException("Invalid package description for "
85 + node.toString()
86 + "(" + e.getMessage() + ")");
87 }
88 }
89 }
90
91 public DependencyNode getRoot()
92 {
93 return root;
94 }
95
96 public Iterator preorderIterator()
97 {
98 return new PreorderIterator(root);
99 }
100
101 private DependencyNode add(AbstractToken token)
102 {
103 DependencyNode node = (DependencyNode)nodeByToken.get(token.toString());
104 if (node != null) {
105 return node;
106 }
107 else if (token instanceof CommaToken) {
108 return add((CommaToken)token);
109 }
110 else if (token instanceof PipeToken) {
111 return add((PipeToken)token);
112 }
113 else if (token instanceof PackageToken) {
114 return add((PackageToken)token);
115 }
116
117 throw new RuntimeException("Unknown token: " + token);
118 }
119
120 private DependencyNode[] add(AbstractToken[] tokens)
121 {
122 DependencyNode[] nodes = new DependencyNode[tokens.length];
123 for (int i = 0; i < tokens.length; i++) {
124 DependencyNode node = (DependencyNode)nodeByToken.get(tokens[i]);
125 nodes[i] = (node != null) ? node : add(tokens[i]);
126 }
127 return nodes;
128 }
129
130 private DependencyNode add(CommaToken token)
131 {
132 LinkedList list = new LinkedList(Arrays.asList(add(token.depends)));
133 AndDependencyNode node = new AndDependencyNode(token.toString(), list);
134 return addNode(token.toString(), node);
135 }
136
137 private DependencyNode add(PipeToken token)
138 {
139 LinkedList list = new LinkedList(Arrays.asList(add(token.depends)));
140 OrDependencyNode node = new OrDependencyNode(token.toString(), list);
141 return addNode(token.toString(), node);
142 }
143
144 private DependencyNode add(PackageToken token)
145 {
146 LinkedList list = new LinkedList();
147
148
149 for (Iterator i = manager.tailSet(token.name).iterator(); i.hasNext();) {
150 PackageInfo info = (PackageInfo)i.next();
151 if (info.getPackage().equals(token.name)) {
152 if (token.compareMode == null
153 || token.equalsVersion(info.compareToVersion
154 (token.version))) {
155
156 list.add(addNode(info));
157 }
158 }
159 else {
160 break;
161 }
162 }
163
164
165 if (token.compareMode == null) {
166 PackageInfo[] providers = manager.getProviders(token.name);
167 if (providers != null) {
168 for (int i = 0; i < providers.length; i++) {
169 list.add(addNode(providers[i]));
170 }
171 }
172 }
173
174 if (list.size() == 0) {
175 return addNode(token.toString(),
176 new UnsatisfiedDependencyNode(token.toString()));
177 }
178 else if (list.size() == 1) {
179 return addNode(token.toString(), (DependencyNode)list.get(0));
180 }
181 else {
182 return addNode(token.toString(),
183 new OrDependencyNode(token.toString(), list));
184 }
185 }
186
187 private DependencyNode addNode(String token, DependencyNode node)
188 {
189 nodeByToken.put(token, node);
190 return node;
191 }
192
193 private DependencyNode addNode(PackageInfo info)
194 {
195 DependencyNode node = (DependencyNode)nodeByPackage.get(info);
196 if (node == null) {
197 node = new PackageDependencyNode(info);
198 nodeByPackage.put(info, node);
199 unparsedNodes.add(node);
200 }
201 return node;
202 }
203
204
205
206 public static class PreorderIterator implements Iterator
207 {
208 private HashSet visited = new HashSet();
209 private LinkedList stack = new LinkedList();
210
211 public PreorderIterator(DependencyNode rootNode)
212 {
213 for (Iterator i = rootNode.children(); i.hasNext();) {
214 DependencyNode node = (DependencyNode)i.next();
215 visited.add(node);
216 stack.addFirst(node);
217 }
218 }
219
220 public boolean hasNext()
221 {
222 return !stack.isEmpty();
223 }
224
225 public Object next()
226 {
227 DependencyNode parent = (DependencyNode)stack.removeFirst();
228
229 for (Iterator i = parent.children(); i.hasNext();) {
230 DependencyNode node = (DependencyNode)i.next();
231
232 if (!visited.contains(node)) {
233 visited.add(node);
234 stack.addFirst(node);
235 }
236 }
237
238 return parent;
239 }
240
241 public void remove()
242 {
243 throw new UnsupportedOperationException();
244 }
245
246 }
247
248 }
249