001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.core.resolve;
019:
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import org.apache.ivy.core.module.id.ModuleId;
028: import org.apache.ivy.plugins.conflict.ConflictManager;
029:
030: public class IvyNodeEviction {
031: /**
032: * This class contains data about the eviction of an {@link IvyNode}.
033: */
034: public static class EvictionData {
035: /**
036: * Can be null in case of transitive eviction.
037: */
038: private IvyNode parent;
039:
040: /**
041: * Can be null in case of transitive eviction.
042: */
043: private ConflictManager conflictManager;
044:
045: /**
046: * Can be null in case of transitive eviction.
047: */
048: private Collection selected; // Collection(IvyNode)
049:
050: private String rootModuleConf;
051:
052: private String detail;
053:
054: /**
055: * Creates a new object containing the eviction data of an {@link IvyNode}.
056: *
057: * @param rootModuleConf
058: * the root module configuration
059: * @param parent
060: * the parent node (or <tt>null</tt> in case of transitive eviction)
061: * @param conflictManager
062: * the conflict manager which evicted the node (or <tt>null</tt> in case of
063: * transitive eviction)
064: * @param selected
065: * a collection of {@link IvyNode}s which evict the evicted node (or
066: * <tt>null</tt> in case of transitive eviction)
067: */
068: public EvictionData(String rootModuleConf, IvyNode parent,
069: ConflictManager conflictManager, Collection selected) {
070: this (rootModuleConf, parent, conflictManager, selected,
071: null);
072: }
073:
074: /**
075: * Creates a new object containing the eviction data of an {@link IvyNode}.
076: *
077: * @param rootModuleConf
078: * the root module configuration
079: * @param parent
080: * the parent node (or <tt>null</tt> in case of transitive eviction)
081: * @param conflictManager
082: * the conflict manager which evicted the node (or <tt>null</tt> in case of
083: * transitive eviction)
084: * @param selected
085: * a collection of {@link IvyNode}s which evict the evicted node (or
086: * <tt>null</tt> in case of transitive eviction)
087: * @param detail
088: * a String detailing the reason why the node was evicted
089: */
090: public EvictionData(String rootModuleConf, IvyNode parent,
091: ConflictManager conflictManager, Collection selected,
092: String detail) {
093: this .rootModuleConf = rootModuleConf;
094: this .parent = parent;
095: this .conflictManager = conflictManager;
096: this .selected = selected;
097: this .detail = detail;
098: }
099:
100: public String toString() {
101: if (selected != null) {
102: return selected + " in " + parent
103: + (detail == null ? "" : " " + detail) + " ("
104: + conflictManager + ") [" + rootModuleConf
105: + "]";
106: } else {
107: return "transitively [" + rootModuleConf + "]";
108: }
109: }
110:
111: public ConflictManager getConflictManager() {
112: return conflictManager;
113: }
114:
115: public IvyNode getParent() {
116: return parent;
117: }
118:
119: public Collection getSelected() {
120: return selected;
121: }
122:
123: public String getRootModuleConf() {
124: return rootModuleConf;
125: }
126:
127: public boolean isTransitivelyEvicted() {
128: return parent == null;
129: }
130:
131: public String getDetail() {
132: return detail;
133: }
134: }
135:
136: private static final class ModuleIdConf {
137: private ModuleId moduleId;
138:
139: private String conf;
140:
141: public ModuleIdConf(ModuleId mid, String conf) {
142: if (mid == null) {
143: throw new NullPointerException("mid cannot be null");
144: }
145: if (conf == null) {
146: throw new NullPointerException("conf cannot be null");
147: }
148: moduleId = mid;
149: this .conf = conf;
150: }
151:
152: public final String getConf() {
153: return conf;
154: }
155:
156: public final ModuleId getModuleId() {
157: return moduleId;
158: }
159:
160: public boolean equals(Object obj) {
161: if (!(obj instanceof ModuleIdConf)) {
162: return false;
163: }
164: return getModuleId().equals(
165: ((ModuleIdConf) obj).getModuleId())
166: && getConf().equals(((ModuleIdConf) obj).getConf());
167: }
168:
169: public int hashCode() {
170: //CheckStyle:MagicNumber| OFF
171: int hash = 33;
172: hash += getModuleId().hashCode() * 17;
173: hash += getConf().hashCode() * 17;
174: //CheckStyle:MagicNumber| ON
175: return hash;
176: }
177: }
178:
179: private IvyNode node;
180:
181: private Map selectedDeps = new HashMap(); // Map (ModuleIdConf -> Set(Node)) // map indicating
182:
183: // for each dependency which node has been selected
184:
185: private Map pendingConflicts = new HashMap(); // Map (ModuleIdConf -> Set(Node)) // map
186:
187: // indicating for each dependency which nodes
188: // are in pending conflict (conflict detected
189: // but not yet resolved)
190:
191: private Map evictedDeps = new HashMap(); // Map (ModuleIdConf -> Set(Node)) // map indicating
192:
193: // for each dependency which node has been evicted
194:
195: private Map evictedRevs = new HashMap(); // Map (ModuleIdConf -> Set(ModuleRevisionId)) //
196:
197: // map indicating for each dependency which revision
198: // has been evicted
199:
200: private Map evicted = new HashMap(); // Map (root module conf -> EvictionData) // indicates
201:
202: // if the node is evicted in each root module conf
203:
204: public IvyNodeEviction(IvyNode node) {
205: if (node == null) {
206: throw new NullPointerException("node must not be null");
207: }
208: this .node = node;
209: }
210:
211: public Collection getResolvedNodes(ModuleId mid,
212: String rootModuleConf) {
213: Collection resolved = (Collection) selectedDeps
214: .get(new ModuleIdConf(mid, rootModuleConf));
215: Set ret = new HashSet();
216: if (resolved != null) {
217: for (Iterator iter = resolved.iterator(); iter.hasNext();) {
218: IvyNode node = (IvyNode) iter.next();
219: ret.add(node.getRealNode());
220: }
221: }
222: return ret;
223: }
224:
225: public Collection getResolvedRevisions(ModuleId mid,
226: String rootModuleConf) {
227: Collection resolved = (Collection) selectedDeps
228: .get(new ModuleIdConf(mid, rootModuleConf));
229: if (resolved == null) {
230: return new HashSet();
231: } else {
232: Collection resolvedRevs = new HashSet();
233: for (Iterator iter = resolved.iterator(); iter.hasNext();) {
234: IvyNode node = (IvyNode) iter.next();
235: resolvedRevs.add(node.getId());
236: resolvedRevs.add(node.getResolvedId());
237: }
238: return resolvedRevs;
239: }
240: }
241:
242: public void setResolvedNodes(ModuleId moduleId,
243: String rootModuleConf, Collection resolved) {
244: ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId,
245: rootModuleConf);
246: selectedDeps.put(moduleIdConf, new HashSet(resolved));
247: }
248:
249: public Collection getEvictedNodes(ModuleId mid,
250: String rootModuleConf) {
251: Collection resolved = (Collection) evictedDeps
252: .get(new ModuleIdConf(mid, rootModuleConf));
253: Set ret = new HashSet();
254: if (resolved != null) {
255: for (Iterator iter = resolved.iterator(); iter.hasNext();) {
256: IvyNode node = (IvyNode) iter.next();
257: ret.add(node.getRealNode());
258: }
259: }
260: return ret;
261: }
262:
263: public Collection getEvictedRevisions(ModuleId mid,
264: String rootModuleConf) {
265: Collection evicted = (Collection) evictedRevs
266: .get(new ModuleIdConf(mid, rootModuleConf));
267: if (evicted == null) {
268: return new HashSet();
269: } else {
270: return new HashSet(evicted);
271: }
272: }
273:
274: public void setEvictedNodes(ModuleId moduleId,
275: String rootModuleConf, Collection evicted) {
276: ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId,
277: rootModuleConf);
278: evictedDeps.put(moduleIdConf, new HashSet(evicted));
279: Collection evictedRevs = new HashSet();
280: for (Iterator iter = evicted.iterator(); iter.hasNext();) {
281: IvyNode node = (IvyNode) iter.next();
282: evictedRevs.add(node.getId());
283: evictedRevs.add(node.getResolvedId());
284: }
285: this .evictedRevs.put(moduleIdConf, evictedRevs);
286: }
287:
288: public boolean isEvicted(String rootModuleConf) {
289: cleanEvicted();
290: IvyNode root = node.getRoot();
291: ModuleId moduleId = node.getId().getModuleId();
292: Collection resolvedRevisions = root.getResolvedRevisions(
293: moduleId, rootModuleConf);
294: EvictionData evictedData = getEvictedData(rootModuleConf);
295: return root != node
296: && evictedData != null
297: && (!resolvedRevisions.contains(node.getResolvedId()) || evictedData
298: .isTransitivelyEvicted());
299: }
300:
301: public boolean isCompletelyEvicted() {
302: cleanEvicted();
303: if (node.isRoot()) {
304: return false;
305: }
306: String[] rootModuleConfigurations = node
307: .getRootModuleConfigurations();
308: for (int i = 0; i < rootModuleConfigurations.length; i++) {
309: if (!isEvicted(rootModuleConfigurations[i])) {
310: return false;
311: }
312: }
313: return true;
314: }
315:
316: private void cleanEvicted() {
317: // check if it was evicted by a node that we are now the real node for
318: for (Iterator iter = evicted.keySet().iterator(); iter
319: .hasNext();) {
320: String rootModuleConf = (String) iter.next();
321: EvictionData ed = (EvictionData) evicted
322: .get(rootModuleConf);
323: Collection sel = ed.getSelected();
324: if (sel != null) {
325: for (Iterator iterator = sel.iterator(); iterator
326: .hasNext();) {
327: IvyNode n = (IvyNode) iterator.next();
328: if (n.getRealNode().equals(this )) {
329: // yes, we are the real node for a selected one !
330: // we are no more evicted in this conf !
331: iter.remove();
332: }
333: }
334: }
335: }
336: }
337:
338: public void markEvicted(EvictionData evictionData) {
339: evicted.put(evictionData.getRootModuleConf(), evictionData);
340: }
341:
342: public EvictionData getEvictedData(String rootModuleConf) {
343: cleanEvicted();
344: return (EvictionData) evicted.get(rootModuleConf);
345: }
346:
347: public String[] getEvictedConfs() {
348: cleanEvicted();
349: return (String[]) evicted.keySet().toArray(
350: new String[evicted.keySet().size()]);
351: }
352:
353: /**
354: * Returns null if this node has only be evicted transitively, or the the collection of selected
355: * nodes if it has been evicted by other selected nodes
356: *
357: * @return
358: */
359: public Collection getAllEvictingNodes() {
360: Collection allEvictingNodes = null;
361: for (Iterator iter = evicted.values().iterator(); iter
362: .hasNext();) {
363: EvictionData ed = (EvictionData) iter.next();
364: Collection selected = ed.getSelected();
365: if (selected != null) {
366: if (allEvictingNodes == null) {
367: allEvictingNodes = new HashSet();
368: }
369: allEvictingNodes.addAll(selected);
370: }
371: }
372: return allEvictingNodes;
373: }
374:
375: public Collection/*<String>*/getAllEvictingNodesDetails() {
376: Collection ret = null;
377: for (Iterator iter = evicted.values().iterator(); iter
378: .hasNext();) {
379: EvictionData ed = (EvictionData) iter.next();
380: Collection selected = ed.getSelected();
381: if (selected != null) {
382: if (ret == null) {
383: ret = new HashSet();
384: }
385: if (selected.size() == 1) {
386: ret.add(selected.iterator().next()
387: + (ed.getDetail() == null ? "" : " "
388: + ed.getDetail()));
389: } else if (selected.size() > 1) {
390: ret.add(selected
391: + (ed.getDetail() == null ? "" : " "
392: + ed.getDetail()));
393: }
394: }
395: }
396: return ret;
397: }
398:
399: public Collection getAllEvictingConflictManagers() {
400: Collection ret = new HashSet();
401: for (Iterator iter = evicted.values().iterator(); iter
402: .hasNext();) {
403: EvictionData ed = (EvictionData) iter.next();
404: ret.add(ed.getConflictManager());
405: }
406: return ret;
407: }
408:
409: /**
410: * Returns the eviction data for this node if it has been previously evicted in the root, null
411: * otherwise (if it hasn't been evicted in root) for the given rootModuleConf. Note that this
412: * method only works if conflict resolution has already be done in all the ancestors.
413: *
414: * @param rootModuleConf
415: * @param ancestor
416: * @return
417: */
418: public EvictionData getEvictionDataInRoot(String rootModuleConf,
419: IvyNode ancestor) {
420: Collection selectedNodes = node.getRoot().getResolvedNodes(
421: node.getModuleId(), rootModuleConf);
422: for (Iterator iter = selectedNodes.iterator(); iter.hasNext();) {
423: IvyNode node = (IvyNode) iter.next();
424: if (node.getResolvedId().equals(this .node.getResolvedId())) {
425: // the node is part of the selected ones for the root: no eviction data to return
426: return null;
427: }
428: }
429: // we didn't find this mrid in the selected ones for the root: it has been previously
430: // evicted
431: return new EvictionData(rootModuleConf, ancestor, node
432: .getRoot().getConflictManager(node.getModuleId()),
433: selectedNodes);
434: }
435:
436: public Collection getPendingConflicts(String rootModuleConf,
437: ModuleId mid) {
438: Collection resolved = (Collection) pendingConflicts
439: .get(new ModuleIdConf(mid, rootModuleConf));
440: Set ret = new HashSet();
441: if (resolved != null) {
442: for (Iterator iter = resolved.iterator(); iter.hasNext();) {
443: IvyNode node = (IvyNode) iter.next();
444: ret.add(node.getRealNode());
445: }
446: }
447: return ret;
448: }
449:
450: public void setPendingConflicts(ModuleId moduleId,
451: String rootModuleConf, Collection conflicts) {
452: ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId,
453: rootModuleConf);
454: pendingConflicts.put(moduleIdConf, new HashSet(conflicts));
455: }
456:
457: }
|