1 11 package org.eclipse.core.internal.dependencies; 12 13 import java.util.*; 14 15 public class DependencySystem { 16 public class CyclicSystemException extends Exception { 17 private Object [][] cycles; 18 19 public CyclicSystemException(Object [][] cycles) { 20 this.cycles = cycles; 21 } 22 23 public Object [][] getCycles() { 24 return cycles; 25 } 26 27 public String getMessage() { 28 StringBuffer result = new StringBuffer (); 29 for (int i = 0; i < cycles.length; i++) { 30 result.append("{"); for (int j = 0; j < cycles[i].length; j++) { 32 result.append(((ElementSet) cycles[i][j]).getId()); 33 result.append(","); } 35 result.deleteCharAt(result.length() - 1); 36 result.append("},"); } 38 if (result.length() > 0) 39 result.deleteCharAt(result.length() - 1); 40 return result.toString(); 41 } 42 } 43 44 public final static int SATISFACTION = 0; 45 public final static int SELECTION = 1; 46 public final static int RESOLUTION = 2; 47 public final static int UP_TO_DATE = Integer.MAX_VALUE; 48 49 private long elementCount; 50 private int mark; 51 52 private ResolutionDelta lastDelta = new ResolutionDelta(); 53 private ResolutionDelta delta = new ResolutionDelta(); 54 private Comparator comparator; 55 56 private Map elementSets = new HashMap(); 58 private ISelectionPolicy selectionPolicy; 60 private boolean debug; 62 63 66 public DependencySystem(Comparator comparator, ISelectionPolicy selectionPolicy, boolean debug) { 67 this.comparator = comparator; 68 this.selectionPolicy = selectionPolicy; 69 this.debug = debug; 70 } 71 72 public DependencySystem(Comparator comparator, ISelectionPolicy selectionPolicy) { 73 this(comparator, selectionPolicy, false); 74 } 75 76 public ElementSet getElementSet(Object id) { 77 ElementSet elementSet = (ElementSet) this.elementSets.get(id); 78 if (elementSet == null) 80 this.elementSets.put(id, elementSet = new ElementSet(id, this)); 81 return elementSet; 82 } 83 84 public Collection discoverRoots() { 85 Collection roots = new LinkedList(); 86 for (Iterator elementSetsIter = elementSets.values().iterator(); elementSetsIter.hasNext();) { 87 ElementSet elementSet = (ElementSet) elementSetsIter.next(); 88 if (elementSet.isRoot()) 89 roots.add(elementSet); 90 } 91 return roots; 92 } 93 94 97 public ResolutionDelta resolve() throws CyclicSystemException { 98 Collection roots = discoverRoots(); 99 Collection satisfied = visit(roots, new SatisfactionVisitor(SATISFACTION)); 101 Collection selected = visit(satisfied, new SelectionVisitor(SELECTION, this.selectionPolicy)); 103 visit(selected, new ResolutionVisitor(RESOLUTION)); 105 this.lastDelta = this.delta; 106 this.delta = new ResolutionDelta(); 107 pruneEmptySets(); 108 return this.lastDelta; 109 } 110 111 private void pruneEmptySets() { 113 for (Iterator elementSetsIter = elementSets.values().iterator(); elementSetsIter.hasNext();) { 114 ElementSet elementSet = (ElementSet) elementSetsIter.next(); 115 if (elementSet.getElementCount() == 0 && elementSet.getRequiringCount() == 0) 116 elementSetsIter.remove(); 117 } 118 } 119 120 124 public Collection visit(Collection elementSets, IElementSetVisitor visitor) throws CyclicSystemException { 125 int visitCounter = 0; 126 int mark = getNewMark(visitor.getOrder()); 127 if (elementSets.isEmpty()) 128 return Collections.EMPTY_SET; 129 Collection leaves = new LinkedList(); 130 while (!elementSets.isEmpty()) { 131 Collection nextLevel = new LinkedList(); 132 for (Iterator elementSetsIter = elementSets.iterator(); elementSetsIter.hasNext();) { 134 ElementSet elementSet = (ElementSet) elementSetsIter.next(); 135 if (mark == elementSet.getVisitedMark()) 137 continue; 138 139 if (elementSet.getVisitedMark() == elementSet.getChangedMark() && visitor.getOrder() > getVisitorOrder(elementSet.getChangedMark())) 142 elementSet.markNeedingUpdate(visitor.getOrder()); 143 boolean shouldVisit = true; 144 for (Iterator ancestorIter = visitor.getAncestors(elementSet).iterator(); ancestorIter.hasNext();) { 145 ElementSet ancestorNode = (ElementSet) ancestorIter.next(); 146 if (ancestorNode.getVisitedMark() != mark) { 147 shouldVisit = false; 149 break; 150 } 151 if (ancestorNode.getChangedMark() == mark) 152 elementSet.markNeedingUpdate(visitor.getOrder()); 154 } 155 if (!shouldVisit) 156 continue; 157 158 elementSet.setVisitedMark(mark); 159 if (elementSet.isNeedingUpdate(visitor.getOrder())) 161 visitor.update(elementSet); 162 163 visitCounter++; 164 165 if (visitor.getDescendants(elementSet).isEmpty()) 166 leaves.add(elementSet); 167 else 168 nextLevel.addAll(visitor.getDescendants(elementSet)); 169 } 170 elementSets = nextLevel; 171 } 172 if (visitCounter != this.elementSets.size()) 175 throw new CyclicSystemException(getCycles()); 176 return leaves; 177 } 178 179 public Object [][] getCycles() { 181 ElementSet[] nodes = (ElementSet[]) elementSets.values().toArray(new ElementSet[elementSets.size()]); 183 ArrayList dependencies = new ArrayList(); 184 for (int i = 0; i < nodes.length; i++) 185 for (Iterator required = nodes[i].getRequired().iterator(); required.hasNext();) 186 dependencies.add(new Object [] {nodes[i], required.next()}); 187 return ComputeNodeOrder.computeNodeOrder(nodes, (Object [][]) dependencies.toArray(new Object [dependencies.size()][])); 188 } 189 190 private int getVisitorOrder(int mark) { 191 return mark & 0xFF; 192 } 193 194 private int getNewMark(int order) { 195 mark = mark % 0xFF + 1; 196 return (mark << 8) + (order & 0xFF); 197 } 198 199 public void addElements(Element[] elementsToAdd) { 200 for (int i = 0; i < elementsToAdd.length; i++) 201 addElement(elementsToAdd[i]); 202 } 203 204 public void addElement(Element element) { 205 this.getElementSet(element.getId()).addElement(element); 206 this.elementCount++; 207 } 208 209 public void removeElements(Element[] elementsToRemove) { 210 for (int i = 0; i < elementsToRemove.length; i++) 211 removeElement(elementsToRemove[i]); 212 } 213 214 public void removeElement(Object id, Object versionId) { 215 ElementSet elementSet = (ElementSet) elementSets.get(id); 216 if (elementSet == null) 217 return; 218 elementSet.removeElement(versionId); 219 } 220 221 public void removeElement(Element element) { 222 ElementSet elementSet = (ElementSet) elementSets.get(element.getId()); 223 if (elementSet == null) 224 return; 225 elementSet.removeElement(element); 226 } 227 228 public long getElementCount() { 229 return elementCount; 230 } 231 232 public Map getNodes() { 233 return this.elementSets; 234 } 235 236 public List getResolved() { 238 int mark = getNewMark(RESOLUTION); 239 Collection elementSets = discoverRoots(); 240 if (elementSets.isEmpty()) 241 return Collections.EMPTY_LIST; 242 final List resolved = new LinkedList(); 243 while (!elementSets.isEmpty()) { 244 Collection nextLevel = new LinkedList(); 245 for (Iterator elementSetsIter = elementSets.iterator(); elementSetsIter.hasNext();) { 246 ElementSet elementSet = (ElementSet) elementSetsIter.next(); 247 if (mark == elementSet.getVisitedMark()) 249 continue; 250 Collection resolvedInSet = elementSet.getResolved(); 251 if (resolvedInSet.isEmpty()) 253 continue; 254 boolean shouldVisit = true; 255 for (Iterator ancestorIter = elementSet.getRequired().iterator(); ancestorIter.hasNext();) { 256 ElementSet ancestorNode = (ElementSet) ancestorIter.next(); 257 if (ancestorNode.getVisitedMark() != mark) { 258 shouldVisit = false; 260 break; 261 } 262 } 263 if (!shouldVisit) 264 continue; 265 elementSet.setVisitedMark(mark); 266 resolved.addAll(resolvedInSet); 267 nextLevel.addAll(elementSet.getRequiring()); 268 } 269 elementSets = nextLevel; 270 } 271 return resolved; 272 } 273 274 public String toString() { 275 StringBuffer result = new StringBuffer (); 276 for (Iterator elementSetsIter = elementSets.values().iterator(); elementSetsIter.hasNext();) { 277 ElementSet elementSet = (ElementSet) elementSetsIter.next(); 278 for (Iterator elementsIter = elementSet.getAvailable().iterator(); elementsIter.hasNext();) { 279 Element element = (Element) elementsIter.next(); 280 result.append(element + ": " + Arrays.asList(element.getDependencies())); result.append(','); 282 } 283 result.deleteCharAt(result.length() - 1); 284 result.append('\n'); 285 } 286 return result.toString(); 287 } 288 289 void recordElementStatusChanged(Element element, int kind) { 290 this.delta.recordChange(element, kind); 291 } 292 293 void recordDependencyChanged(Collection oldResolved, Collection newResolved) { 294 for (Iterator oldResolvedIter = oldResolved.iterator(); oldResolvedIter.hasNext();) { 295 Element element = (Element) oldResolvedIter.next(); 296 if (!newResolved.contains(element)) 297 this.delta.recordChange(element, ElementChange.UNRESOLVED); 298 } 299 for (Iterator newResolvedIter = newResolved.iterator(); newResolvedIter.hasNext();) { 300 Element element = (Element) newResolvedIter.next(); 301 if (!oldResolved.contains(element)) 302 this.delta.recordChange(element, ElementChange.RESOLVED); 303 } 304 } 305 306 public Element getElement(Object id, Object versionId) { 307 ElementSet elementSet = (ElementSet) elementSets.get(id); 308 if (elementSet == null) 309 return null; 310 return elementSet.getElement(versionId); 311 } 312 313 public Element createElement(Object id, Object versionId, Dependency[] dependencies, boolean singleton, Object userObject) { 315 return new Element(id, versionId, dependencies, singleton, userObject); 316 } 317 318 public Dependency createDependency(Object requiredObjectId, IMatchRule satisfactionRule, boolean optional, Object userObject) { 320 return new Dependency(requiredObjectId, satisfactionRule, optional, userObject); 321 } 322 323 public int compare(Object obj1, Object obj2) { 325 return comparator.compare(obj1, obj2); 326 } 327 328 332 333 public ResolutionDelta getLastDelta() { 334 return lastDelta; 335 } 336 337 boolean inDebugMode() { 338 return debug; 339 } 340 341 public Collection getRequiringElements(Element required) { 342 ElementSet containing = getElementSet(required.getId()); 343 return containing.getRequiringElements(required.getVersionId()); 344 } 345 346 353 public void unresolve(Element[] elements) { 354 int mark = getNewMark(RESOLUTION); 355 for (int i = 0; i < elements.length; i++) { 356 ElementSet set = getElementSet(elements[i].getId()); 357 if (set == null) 358 return; 359 set.unresolve(elements[i], mark); 360 } 361 } 362 } | Popular Tags |