KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > fr > jayasoft > ivy > IvyNode


1 /*
2  * This file is subject to the license found in LICENCE.TXT in the root directory of the project.
3  *
4  * #SNAPSHOT#
5  */

6 package fr.jayasoft.ivy;
7
8 import java.util.ArrayList JavaDoc;
9 import java.util.Arrays JavaDoc;
10 import java.util.Collection JavaDoc;
11 import java.util.Collections JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.HashSet JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.LinkedHashSet JavaDoc;
16 import java.util.LinkedList JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20 import java.util.Stack JavaDoc;
21 import java.util.regex.Matcher JavaDoc;
22 import java.util.regex.Pattern JavaDoc;
23
24 import fr.jayasoft.ivy.event.resolve.EndResolveDependencyEvent;
25 import fr.jayasoft.ivy.event.resolve.StartResolveDependencyEvent;
26 import fr.jayasoft.ivy.filter.Filter;
27 import fr.jayasoft.ivy.filter.FilterHelper;
28 import fr.jayasoft.ivy.matcher.MatcherHelper;
29 import fr.jayasoft.ivy.util.Message;
30
31 public class IvyNode {
32     private static final Pattern JavaDoc FALLBACK_CONF_PATTERN = Pattern.compile("(.+)\\((.*)\\)");
33
34     public static class EvictionData {
35         private IvyNode _node; // can be null in case of transitive eviction
36
private ConflictManager _conflictManager; // can be null in case of transitive eviction
37
private Collection JavaDoc _selected; // can be null in case of transitive eviction
38
private String JavaDoc _rootModuleConf;
39
40         public EvictionData(String JavaDoc rootModuleConf, IvyNode node, ConflictManager conflictManager, Collection JavaDoc selected) {
41             _rootModuleConf = rootModuleConf;
42             _node = node;
43             _conflictManager = conflictManager;
44             _selected = selected;
45         }
46         
47         public String JavaDoc toString() {
48             if (_selected != null) {
49                 return _selected + " in "+ _node+" ("+_conflictManager+") ["+_rootModuleConf+"]";
50             } else {
51                 return "transitively ["+_rootModuleConf+"]";
52             }
53         }
54
55         public ConflictManager getConflictManager() {
56             return _conflictManager;
57         }
58         
59
60         public IvyNode getNode() {
61             return _node;
62         }
63
64         public Collection JavaDoc getSelected() {
65             return _selected;
66         }
67         
68
69         public String JavaDoc getRootModuleConf() {
70             return _rootModuleConf;
71         }
72         
73         
74     }
75
76     public class Caller {
77         private ModuleDescriptor _md;
78         private ModuleRevisionId _mrid;
79         private Map JavaDoc _confs = new HashMap JavaDoc(); // Map (String callerConf -> String[] dependencyConfs)
80
private DependencyDescriptor _dd;
81         private boolean _callerCanExclude;
82         
83         public Caller(ModuleDescriptor md, ModuleRevisionId mrid, DependencyDescriptor dd, boolean callerCanExclude) {
84             _md = md;
85             _mrid = mrid;
86             _dd = dd;
87             _callerCanExclude = callerCanExclude;
88         }
89         public void addConfiguration(String JavaDoc callerConf, String JavaDoc[] dependencyConfs) {
90             String JavaDoc[] prevDepConfs = (String JavaDoc[])_confs.get(callerConf);
91             if (prevDepConfs != null) {
92                 Set JavaDoc newDepConfs = new HashSet JavaDoc(Arrays.asList(prevDepConfs));
93                 newDepConfs.addAll(Arrays.asList(dependencyConfs));
94                 _confs.put(callerConf, (String JavaDoc[])newDepConfs.toArray(new String JavaDoc[newDepConfs.size()]));
95             } else {
96                 _confs.put(callerConf, dependencyConfs);
97             }
98         }
99         public String JavaDoc[] getCallerConfigurations() {
100             return (String JavaDoc[])_confs.keySet().toArray(new String JavaDoc[_confs.keySet().size()]);
101         }
102         public ModuleRevisionId getModuleRevisionId() {
103             return _mrid;
104         }
105         public boolean equals(Object JavaDoc obj) {
106             if (! (obj instanceof Caller)) {
107                 return false;
108             }
109             Caller other = (Caller)obj;
110             return other._confs.equals(_confs)
111                 && _mrid.equals(other._mrid);
112         }
113         public int hashCode() {
114             int hash = 31;
115             hash = hash * 13 + _confs.hashCode();
116             hash = hash * 13 + _mrid.hashCode();
117             return hash;
118         }
119         public String JavaDoc toString() {
120             return _mrid.toString();
121         }
122         public ModuleRevisionId getAskedDependencyId() {
123             return _dd.getDependencyRevisionId();
124         }
125         public ModuleDescriptor getModuleDescriptor() {
126             return _md;
127         }
128         public boolean canExclude() {
129             return _callerCanExclude || _dd.canExclude();
130         }
131         public DependencyDescriptor getDependencyDescriptor() {
132             return _dd;
133         }
134     }
135     private static final class NodeConf {
136         private IvyNode _node;
137         private String JavaDoc _conf;
138
139         public NodeConf(IvyNode node, String JavaDoc conf) {
140             _node = node;
141             _conf = conf;
142         }
143
144         public final String JavaDoc getConf() {
145             return _conf;
146         }
147         
148         public final IvyNode getNode() {
149             return _node;
150         }
151         public boolean equals(Object JavaDoc obj) {
152             if (!(obj instanceof NodeConf)) {
153                 return false;
154             }
155             return getNode().equals(((NodeConf)obj).getNode())
156                 && getConf().equals(((NodeConf)obj).getConf());
157         }
158         public int hashCode() {
159             int hash = 33;
160             hash += getNode().hashCode() * 17;
161             hash += getConf().hashCode() * 17;
162             return hash;
163         }
164     }
165
166     private static final class ModuleIdConf {
167         private ModuleId _moduleId;
168         private String JavaDoc _conf;
169
170         public ModuleIdConf(ModuleId mid, String JavaDoc conf) {
171             _moduleId = mid;
172             _conf = conf;
173         }
174
175         public final String JavaDoc getConf() {
176             return _conf;
177         }
178         
179         public final ModuleId getModuleId() {
180             return _moduleId;
181         }
182         public boolean equals(Object JavaDoc obj) {
183             if (!(obj instanceof ModuleIdConf)) {
184                 return false;
185             }
186             return getModuleId().equals(((ModuleIdConf)obj).getModuleId())
187                 && getConf().equals(((ModuleIdConf)obj).getConf());
188         }
189         public int hashCode() {
190             int hash = 33;
191             hash += getModuleId().hashCode() * 17;
192             hash += getConf().hashCode() * 17;
193             return hash;
194         }
195     }
196
197     private ModuleRevisionId _id; // id as requested, i.e. may be with latest rev
198

199     /**
200      * Represents the current parent of the node during ivy visit
201      * of dependency graph.
202      * Use callers on Dependency to know all the callers
203      * of a dependency
204      */

205     private IvyNode _parent = null;
206     private IvyNode _root = null;
207     private Collection JavaDoc _path = null; // Collection(IvyNode): direct path from root to this node. Note that the colleciton is ordered but is not a list implementation
208
private String JavaDoc _parentConf = null;
209     private String JavaDoc _rootModuleConf;
210
211     private Map JavaDoc _selectedDeps = new HashMap JavaDoc(); // Map (ModuleIdConf -> Set(Node)) // map indicating for each dependency which node has been selected
212

213     private Map JavaDoc _evictedDeps = new HashMap JavaDoc(); // Map (ModuleIdConf -> Set(Node)) // map indicating for each dependency which node has been evicted
214
private Map JavaDoc _evictedRevs = new HashMap JavaDoc(); // Map (ModuleIdConf -> Set(ModuleRevisionId)) // map indicating for each dependency which revision has been evicted
215

216     private Map JavaDoc _evicted = new HashMap JavaDoc(); // Map (root module conf -> EvictionData) // indicates if the node is evicted in each root module conf
217

218     // Map (String rootModuleConf -> Map (ModuleRevisionId -> Caller)): key in second map is used to easily get a caller by its mrid
219
private Map JavaDoc _callersByRootConf = new HashMap JavaDoc();
220     
221     // Map (String rootConfName -> Set(String confName))
222
// used to know which configurations of the dependency are required by root
223
// module configuration
224
private Map JavaDoc _rootModuleConfs = new HashMap JavaDoc();
225         
226     // Map (String rootModuleConf -> Set(DependencyArtifactDescriptor))
227
private Map JavaDoc _dependencyArtifactsIncludes = new HashMap JavaDoc();
228
229     // shared data
230
private ResolveData _data;
231
232     private Collection JavaDoc _confsToFetch = new HashSet JavaDoc();
233     private Collection JavaDoc _fetchedConfigurations = new HashSet JavaDoc();
234
235     // set only when node has been built or updated from a DependencyDescriptor
236
private Map JavaDoc _dds = new HashMap JavaDoc(); // Map(IvyNode parent -> DependencyDescriptor)
237

238     // Set when data has been loaded only
239
private ModuleDescriptor _md;
240
241     private ResolvedModuleRevision _module;
242
243     private Exception JavaDoc _problem = null;
244     
245     private boolean _downloaded = false;
246     private boolean _searched = false;
247
248
249     private Map JavaDoc _requiredConfs = new HashMap JavaDoc(); // Map (NodeConf in -> Set(String conf))
250

251     private boolean _isRoot = false;
252
253     // this map contains all the module ids calling this one as keys
254
// the mapped nodes correspond to a direct caller from which the transitive caller comes
255

256     private Map JavaDoc _allCallers = new HashMap JavaDoc(); // Map (ModuleId -> IvyNode)
257

258     private boolean _isCircular = false;
259
260     private Collection JavaDoc _loadedRootModuleConfs = new HashSet JavaDoc();
261
262     private Map JavaDoc _requestedConf = new HashMap JavaDoc(); // Maps of requested confs per root configuration
263
// this data is contextual to the current step of the
264
// resolve process
265

266     
267     public IvyNode(ResolveData data, IvyNode parent, DependencyDescriptor dd) {
268         _id = dd.getDependencyRevisionId();
269         _dds.put(parent, dd);
270         _isRoot = false;
271
272         init(data, true);
273     }
274
275     public IvyNode(ResolveData data, ModuleDescriptor md) {
276         _id = md.getModuleRevisionId();
277         _md = md;
278         _isRoot = true;
279         _root = this;
280         
281         // we do not register nodes created from ModuleDescriptor, cause they are
282
// the root of resolve
283
init(data, false);
284     }
285
286     private void init(ResolveData data, boolean register) {
287         _data = data;
288         if (register) {
289             _data.register(this);
290         }
291     }
292
293     public ConflictManager getConflictManager(ModuleId mid) {
294         if (_md == null) {
295             throw new IllegalStateException JavaDoc("impossible to get conflict manager when data has not been loaded");
296         }
297         ConflictManager cm = _md.getConflictManager(mid);
298         return cm == null ? _data.getIvy().getDefaultConflictManager() : cm;
299     }
300     
301     public Collection JavaDoc getResolvedNodes(ModuleId mid, String JavaDoc rootModuleConf) {
302         Collection JavaDoc resolved = (Collection JavaDoc)_selectedDeps.get(new ModuleIdConf(mid, rootModuleConf));
303         Set JavaDoc ret = new HashSet JavaDoc();
304         if (resolved != null) {
305             for (Iterator JavaDoc iter = resolved.iterator(); iter.hasNext();) {
306                 IvyNode node = (IvyNode)iter.next();
307                 ret.add(node.getRealNode());
308             }
309         }
310         return ret;
311     }
312     public Collection JavaDoc getResolvedRevisions(ModuleId mid, String JavaDoc rootModuleConf) {
313         Collection JavaDoc resolved = (Collection JavaDoc)_selectedDeps.get(new ModuleIdConf(mid, rootModuleConf));
314         if (resolved == null) {
315             return new HashSet JavaDoc();
316         } else {
317             Collection JavaDoc resolvedRevs = new HashSet JavaDoc();
318             for (Iterator JavaDoc iter = resolved.iterator(); iter.hasNext();) {
319                 IvyNode node = (IvyNode)iter.next();
320                 resolvedRevs.add(node.getId());
321                 resolvedRevs.add(node.getResolvedId());
322             }
323             return resolvedRevs;
324         }
325     }
326
327     public void setResolvedNodes(ModuleId moduleId, String JavaDoc rootModuleConf, Collection JavaDoc resolved) {
328         ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId, rootModuleConf);
329         _selectedDeps.put(moduleIdConf, new HashSet JavaDoc(resolved));
330     }
331     
332     public Collection JavaDoc getEvictedNodes(ModuleId mid, String JavaDoc rootModuleConf) {
333         Collection JavaDoc resolved = (Collection JavaDoc)_evictedDeps.get(new ModuleIdConf(mid, rootModuleConf));
334         Set JavaDoc ret = new HashSet JavaDoc();
335         if (resolved != null) {
336             for (Iterator JavaDoc iter = resolved.iterator(); iter.hasNext();) {
337                 IvyNode node = (IvyNode)iter.next();
338                 ret.add(node.getRealNode());
339             }
340         }
341         return ret;
342     }
343     public Collection JavaDoc getEvictedRevisions(ModuleId mid, String JavaDoc rootModuleConf) {
344         Collection JavaDoc evicted = (Collection JavaDoc)_evictedRevs.get(new ModuleIdConf(mid, rootModuleConf));
345         if (evicted == null) {
346             return new HashSet JavaDoc();
347         } else {
348             return new HashSet JavaDoc(evicted);
349         }
350     }
351
352     public void setEvictedNodes(ModuleId moduleId, String JavaDoc rootModuleConf, Collection JavaDoc evicted) {
353         ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId, rootModuleConf);
354         _evictedDeps.put(moduleIdConf, new HashSet JavaDoc(evicted));
355         Collection JavaDoc evictedRevs = new HashSet JavaDoc();
356         for (Iterator JavaDoc iter = evicted.iterator(); iter.hasNext();) {
357             IvyNode node = (IvyNode)iter.next();
358             evictedRevs.add(node.getId());
359             evictedRevs.add(node.getResolvedId());
360         }
361         _evictedRevs.put(moduleIdConf, evictedRevs);
362     }
363     
364
365     public boolean isEvicted(String JavaDoc rootModuleConf) {
366         cleanEvicted();
367         return getRoot() != this && !getRoot().getResolvedRevisions(getId().getModuleId(), rootModuleConf).contains(getResolvedId());
368     }
369
370     public boolean isCompletelyEvicted() {
371         cleanEvicted();
372         if (getRoot() == this) {
373             return false;
374         }
375         for (Iterator JavaDoc iter = _rootModuleConfs.keySet().iterator(); iter.hasNext();) {
376             String JavaDoc conf = (String JavaDoc) iter.next();
377             if (!isEvicted(conf)) {
378                 return false;
379             }
380         }
381         return true;
382     }
383     
384     private void cleanEvicted() {
385         // check if it was evicted by a node that we are now the real node for
386
for (Iterator JavaDoc iter = _evicted.keySet().iterator(); iter.hasNext();) {
387             String JavaDoc rootModuleConf = (String JavaDoc)iter.next();
388             EvictionData ed = (EvictionData)_evicted.get(rootModuleConf);
389             Collection JavaDoc sel = ed.getSelected();
390             if (sel != null) {
391                 for (Iterator JavaDoc iterator = sel.iterator(); iterator.hasNext();) {
392                     IvyNode n = (IvyNode)iterator.next();
393                     if (n.getRealNode().equals(this)) {
394                         // yes, we are the real node for a selected one !
395
// we are no more evicted in this conf !
396
iter.remove();
397                     }
398                 }
399             }
400         }
401     }
402
403     public void markEvicted(String JavaDoc rootModuleConf, IvyNode node, ConflictManager conflictManager, Collection JavaDoc resolved) {
404         EvictionData evictionData = new EvictionData(rootModuleConf, node, conflictManager, resolved);
405         markEvicted(evictionData);
406     }
407
408     public void markEvicted(EvictionData evictionData) {
409         _evicted.put(evictionData.getRootModuleConf(), evictionData);
410         if (!_rootModuleConfs.keySet().contains(evictionData.getRootModuleConf())) {
411             _rootModuleConfs.put(evictionData.getRootModuleConf(), null);
412         }
413         
414         // bug 105: update selected data with evicted one
415
if (evictionData.getSelected() != null) {
416             for (Iterator JavaDoc iter = evictionData.getSelected().iterator(); iter.hasNext();) {
417                 IvyNode selected = (IvyNode)iter.next();
418                 selected.updateDataFrom(this, evictionData.getRootModuleConf());
419             }
420         }
421     }
422     
423     private void updateDataFrom(IvyNode node, String JavaDoc rootModuleConf) {
424         // update callers
425
Map JavaDoc nodecallers = (Map JavaDoc)node._callersByRootConf.get(rootModuleConf);
426         if (nodecallers != null) {
427             Map JavaDoc thiscallers = (Map JavaDoc)_callersByRootConf.get(rootModuleConf);
428             if (thiscallers == null) {
429                 thiscallers = new HashMap JavaDoc();
430                 _callersByRootConf.put(rootModuleConf, thiscallers);
431             }
432             for (Iterator JavaDoc iter = nodecallers.values().iterator(); iter.hasNext();) {
433                 Caller caller = (Caller)iter.next();
434                 if (!thiscallers.containsKey(caller.getModuleRevisionId())) {
435                     thiscallers.put(caller.getModuleRevisionId(), caller);
436                 }
437             }
438         }
439         
440         // update requiredConfs
441
updateMapOfSet(node._requiredConfs, _requiredConfs);
442         
443         // update rootModuleConfs
444
updateMapOfSetForKey(node._rootModuleConfs, _rootModuleConfs, rootModuleConf);
445         
446         // update dependencyArtifactsIncludes
447
updateMapOfSetForKey(node._dependencyArtifactsIncludes, _dependencyArtifactsIncludes, rootModuleConf);
448         
449         // update confsToFetch
450
updateConfsToFetch(node._fetchedConfigurations);
451         updateConfsToFetch(node._confsToFetch);
452     }
453     
454     private void updateMapOfSet(Map JavaDoc from, Map JavaDoc to) {
455         for (Iterator JavaDoc iter = from.keySet().iterator(); iter.hasNext();) {
456             Object JavaDoc key = iter.next();
457             updateMapOfSetForKey(from, to, key);
458         }
459     }
460
461     private void updateMapOfSetForKey(Map JavaDoc from, Map JavaDoc to, Object JavaDoc key) {
462         Set JavaDoc set = (Set JavaDoc)from.get(key);
463         if (set != null) {
464             Set JavaDoc toupdate = (Set JavaDoc)to.get(key);
465             if (toupdate != null) {
466                 toupdate.addAll(set);
467             } else {
468                 to.put(key, new HashSet JavaDoc(set));
469             }
470         }
471     }
472
473     public EvictionData getEvictedData(String JavaDoc rootModuleConf) {
474         cleanEvicted();
475         return (EvictionData)_evicted.get(rootModuleConf);
476     }
477     public String JavaDoc[] getEvictedConfs() {
478         cleanEvicted();
479         return (String JavaDoc[])_evicted.keySet().toArray(new String JavaDoc[_evicted.keySet().size()]);
480     }
481
482     /**
483      * Returns null if this node has only be evicted transitively, or the the colletion of selected nodes
484      * if it has been evicted by other selected nodes
485      * @return
486      */

487     public Collection JavaDoc getAllEvictingNodes() {
488         Collection JavaDoc allEvictingNodes = null;
489         for (Iterator JavaDoc iter = _evicted.values().iterator(); iter.hasNext();) {
490             EvictionData ed = (EvictionData)iter.next();
491             Collection JavaDoc selected = ed.getSelected();
492             if (selected != null) {
493                 if (allEvictingNodes == null) {
494                     allEvictingNodes = new HashSet JavaDoc();
495                 }
496                 allEvictingNodes.addAll(selected);
497             }
498         }
499         return allEvictingNodes;
500     }
501
502     public Collection JavaDoc getAllEvictingConflictManagers() {
503         Collection JavaDoc ret = new HashSet JavaDoc();
504         for (Iterator JavaDoc iter = _evicted.values().iterator(); iter.hasNext();) {
505             EvictionData ed = (EvictionData)iter.next();
506             ret.add(ed.getConflictManager());
507         }
508         return ret;
509     }
510
511
512     public IvyNode getParent() {
513         return _parent;
514     }
515
516     public void setParent(IvyNode parent) {
517         _parent = parent;
518         _root = null;
519         _path = null;
520     }
521
522     public IvyNode getRoot() {
523         if (_root == null) {
524             _root = computeRoot();
525         }
526         return _root;
527     }
528
529     public Collection JavaDoc getPath() {
530         if (_path == null) {
531             _path = computePath();
532         }
533         return _path;
534     }
535
536     private Collection JavaDoc computePath() {
537         if (_parent != null) {
538             Collection JavaDoc p = new LinkedHashSet JavaDoc(_parent.getPath());
539             p.add(this);
540             return p;
541         } else {
542             return Collections.singletonList(this);
543         }
544     }
545
546     private IvyNode computeRoot() {
547         if (isRoot()) {
548             return this;
549         } else if (_parent != null) {
550             return _parent.getRoot();
551         } else {
552             return null;
553         }
554 // IvyNode root = this;
555
// Collection path = new HashSet();
556
// path.add(root);
557
// while (root.getParent() != null && !root.isRoot()) {
558
// if (path.contains(root.getParent())) {
559
// return root;
560
// }
561
// root = root.getParent();
562
// path.add(root);
563
// }
564
// return root;
565
}
566
567     public String JavaDoc getParentConf() {
568         return _parentConf;
569     }
570
571     public void setParentConf(String JavaDoc parentConf) {
572         _parentConf = parentConf;
573     }
574
575
576     public boolean hasConfigurationsToLoad() {
577         return !_confsToFetch.isEmpty();
578     }
579
580     /**
581      * After the call node may be discarded. To avoid using discarded node, make sure
582      * to get the real node after the call
583      * IvyNode node = ...
584      * node.loadData();
585      * node = node.getRealNode();
586      * ...
587      */

588     public boolean loadData(String JavaDoc conf, boolean shouldBePublic) {
589         boolean loaded = false;
590         if (!isEvicted(_rootModuleConf) && (hasConfigurationsToLoad() || !isRootModuleConfLoaded()) && !hasProblem()) {
591             markRootModuleConfLoaded();
592             if (_md == null) {
593                 DependencyResolver resolver = _data.getIvy().getResolver(getModuleId());
594                 if (resolver == null) {
595                     Message.error("no resolver found for "+getModuleId()+": check your configuration");
596                     _problem = new RuntimeException JavaDoc("no resolver found for "+getModuleId()+": check your configuration");
597                     _data.getReport().addDependency(this);
598                     return false;
599                 }
600                 try {
601                     Message.debug("\tusing "+resolver+" to resolve "+getId());
602                     DependencyDescriptor dependencyDescriptor = getDependencyDescriptor(getParent());
603                     _data.getIvy().fireIvyEvent(new StartResolveDependencyEvent(_data.getIvy(), resolver, dependencyDescriptor));
604                     _module = resolver.getDependency(dependencyDescriptor, _data);
605                     _data.getIvy().fireIvyEvent(new EndResolveDependencyEvent(_data.getIvy(), resolver, dependencyDescriptor, _module));
606                     if (_module != null) {
607                         _data.getIvy().saveResolver(_data.getCache(), _module.getDescriptor(), _module.getResolver().getName());
608                         _data.getIvy().saveArtResolver(_data.getCache(), _module.getDescriptor(), _module.getArtifactResolver().getName());
609                         if (_data.getIvy().logModuleWhenFound()) {
610                             Message.info("\tfound "+_module.getId()+" in "+_module.getResolver().getName());
611                         } else {
612                             Message.verbose("\tfound "+_module.getId()+" in "+_module.getResolver().getName());
613                         }
614                         
615                         if (_data.getIvy().getVersionMatcher().isDynamic(getId())) {
616                             // IVY-56: check if revision has actually been resolved
617
if (_data.getIvy().getVersionMatcher().isDynamic(_module.getId())) {
618                                 Message.error("impossible to resolve dynamic revision for "+getId()+": check your configuration and make sure revision is part of your pattern");
619                                 _problem = new RuntimeException JavaDoc("impossible to resolve dynamic revision");
620                                 _data.getReport().addDependency(this);
621                                 return false;
622                             }
623                             IvyNode resolved = _data.getNode(_module.getId());
624                             if (resolved != null) {
625                                 // exact revision has already been resolved
626
// => update it and discard this node
627
_md = _module.getDescriptor(); // needed for handleConfiguration
628
if (!handleConfiguration(loaded, conf, shouldBePublic)) {
629                                     return false;
630                                 }
631                                 
632                                 if (resolved._md == null) {
633                                     resolved._md = _md;
634                                 }
635                                 if (resolved._module == null) {
636                                     resolved._module = _module;
637                                 }
638                                 resolved._downloaded |= _module.isDownloaded();
639                                 resolved._searched |= _module.isSearched();
640                                 resolved._dds.putAll(_dds);
641                                 resolved.updateDataFrom(this, _rootModuleConf);
642                                 resolved.loadData(conf, shouldBePublic);
643                                 DependencyDescriptor dd = dependencyDescriptor;
644                                 if (dd != null) {
645                                     resolved.addDependencyArtifactsIncludes(_rootModuleConf, dd.getDependencyArtifactsIncludes(getParentConf()));
646                                 }
647                                 _data.register(getId(), resolved); // this actually discards the node
648

649                                 if (_data.getIvy().logResolvedRevision()) {
650                                     Message.info("\t["+_module.getId().getRevision()+"] "+getId());
651                                 } else {
652                                     Message.verbose("\t["+_module.getId().getRevision()+"] "+getId());
653                                 }
654                                 
655                                 return true;
656                             }
657                         }
658                         _downloaded = _module.isDownloaded();
659                         _searched = _module.isSearched();
660                     } else {
661                         Message.warn("\tmodule not found: "+getId());
662                         resolver.reportFailure();
663                         _problem = new RuntimeException JavaDoc("not found");
664                     }
665                 } catch (Exception JavaDoc e) {
666                     _problem = e;
667                 }
668                 
669                 // still not resolved, report error
670
if (_module == null) {
671                     _data.getReport().addDependency(this);
672                     return false;
673                 } else {
674                     loaded = true;
675                     if (_data.getIvy().getVersionMatcher().isDynamic(getId())) {
676                         if (_data.getIvy().logResolvedRevision()) {
677                             Message.info("\t["+_module.getId().getRevision()+"] "+getId());
678                         } else {
679                             Message.verbose("\t["+_module.getId().getRevision()+"] "+getId());
680                         }
681                     }
682                     _md = _module.getDescriptor();
683                     // if the revision was a dynamic one (which has now be resolved)
684
// store also it to cache the result
685
if (_data.getIvy().getVersionMatcher().isDynamic(getId())) {
686                         _data.register(_module.getId(), this);
687                     }
688                     _confsToFetch.remove("*");
689                     updateConfsToFetch(Arrays.asList(resolveSpecialConfigurations(getRequiredConfigurations(getParent(), getParentConf()), this)));
690                 }
691             } else {
692                 loaded = true;
693             }
694         }
695         if (hasProblem()) {
696             _data.getReport().addDependency(this);
697             return handleConfiguration(loaded, conf, shouldBePublic) && loaded;
698         }
699         if (!handleConfiguration(loaded, conf, shouldBePublic)) {
700             return false;
701         }
702         DependencyDescriptor dd = getDependencyDescriptor(getParent());
703         if (dd != null) {
704             addDependencyArtifactsIncludes(_rootModuleConf, dd.getDependencyArtifactsIncludes(getParentConf()));
705         }
706         return loaded;
707         
708     }
709
710     private boolean markRootModuleConfLoaded() {
711         return _loadedRootModuleConfs.add(_rootModuleConf);
712     }
713     
714     private boolean isRootModuleConfLoaded() {
715         return _loadedRootModuleConfs.contains(_rootModuleConf);
716     }
717
718     private boolean handleConfiguration(boolean loaded, String JavaDoc conf, boolean shouldBePublic) {
719         if (_md != null) {
720             String JavaDoc[] confs = getRealConfs(conf);
721             for (int i = 0; i < confs.length; i++) {
722                 Configuration c = _md.getConfiguration(confs[i]);
723                 if (c == null) {
724                     _confsToFetch.remove(conf);
725                     if (!conf.equals(confs[i])) {
726                         _problem = new RuntimeException JavaDoc("configuration(s) not found in "+this+": "+conf+". Missing configuration: "+confs[i]+". It was required from "+getParent()+" "+getParentConf());
727                     } else {
728                         _problem = new RuntimeException JavaDoc("configuration(s) not found in "+this+": "+confs[i]+". It was required from "+getParent()+" "+getParentConf());
729                     }
730                     _data.getReport().addDependency(this);
731                     return false;
732                 } else if (shouldBePublic && !isRoot() && c.getVisibility() != Configuration.Visibility.PUBLIC) {
733                     _confsToFetch.remove(conf);
734                     _problem = new RuntimeException JavaDoc("configuration not public in "+this+": "+c+". It was required from "+getParent()+" "+getParentConf());
735                     _data.getReport().addDependency(this);
736                     return false;
737                 }
738                 if (loaded) {
739                     _fetchedConfigurations.add(conf);
740                     _confsToFetch.removeAll(Arrays.asList(confs));
741                     _confsToFetch.remove(conf);
742                 }
743                 addRootModuleConfigurations(_rootModuleConf, confs);
744             }
745         }
746         return true;
747     }
748
749     private String JavaDoc getDefaultConf(String JavaDoc conf) {
750         Matcher JavaDoc m = FALLBACK_CONF_PATTERN.matcher(conf);
751         if (m.matches()) {
752             return m.group(2);
753         } else {
754             return conf;
755         }
756     }
757
758     private String JavaDoc getMainConf(String JavaDoc conf) {
759         Matcher JavaDoc m = FALLBACK_CONF_PATTERN.matcher(conf);
760         if (m.matches()) {
761             return m.group(1);
762         } else {
763             return null;
764         }
765     }
766
767     private boolean isRoot() {
768         return _isRoot ;
769     }
770
771     public IvyNode getRealNode() {
772         return getRealNode(false);
773     }
774
775
776     public IvyNode getRealNode(boolean traverse) {
777         IvyNode node = _data.getNode(getId());
778         if (node != null) {
779             if (traverse) {
780                 node.setParent(getParent());
781                 node.setParentConf(getParentConf());
782                 node.setRootModuleConf(getRootModuleConf());
783                 node.setRequestedConf(getRequestedConf());
784                 node._data = _data;
785             }
786             return node;
787         } else {
788             return this;
789         }
790     }
791
792     public Collection JavaDoc getDependencies(String JavaDoc[] confs) {
793         if (_md == null) {
794             throw new IllegalStateException JavaDoc("impossible to get dependencies when data has not been loaded");
795         }
796         if (Arrays.asList(confs).contains("*")) {
797             confs = _md.getConfigurationsNames();
798         }
799         Collection JavaDoc deps = new HashSet JavaDoc();
800         for (int i = 0; i < confs.length; i++) {
801             deps.addAll(getDependencies(confs[i], false));
802         }
803         return deps;
804     }
805     
806     public Collection JavaDoc getDependencies(String JavaDoc conf, boolean traverse) {
807         if (_md == null) {
808             throw new IllegalStateException JavaDoc("impossible to get dependencies when data has not been loaded");
809         }
810         DependencyDescriptor[] dds = _md.getDependencies();
811         Collection JavaDoc dependencies = new LinkedHashSet JavaDoc(); // it's important to respect dependencies order
812
for (int i = 0; i < dds.length; i++) {
813             DependencyDescriptor dd = dds[i];
814             String JavaDoc[] dependencyConfigurations = dd.getDependencyConfigurations(conf, getRequestedConf());
815             if (dependencyConfigurations.length == 0) {
816                 // no configuration of the dependency is required for current confs :
817
// it is exactly the same as if there was no dependency at all on it
818
continue;
819             }
820             if (isDependencyModuleExcluded(dd.getDependencyRevisionId(), conf)) {
821                 // the whole module is excluded, it is considered as not being part of dependencies at all
822
Message.verbose("excluding "+dd.getDependencyRevisionId()+" in "+conf);
823                 continue;
824             }
825             IvyNode depNode = _data.getNode(dd.getDependencyRevisionId());
826             if (depNode == null) {
827                 depNode = new IvyNode(_data, this, dd);
828             } else {
829                 depNode.addDependencyDescriptor(this, dd);
830                 if (depNode.hasProblem()) {
831                     // dependency already tried to be resolved, but unsuccessfully
832
// nothing special to do
833
}
834                 
835             }
836             Collection JavaDoc confs = Arrays.asList(resolveSpecialConfigurations(dependencyConfigurations, depNode));
837             depNode.updateConfsToFetch(confs);
838             depNode.setRequiredConfs(this, conf, confs);
839             
840             depNode.addCaller(_rootModuleConf, this, conf, dependencyConfigurations, dd);
841             dependencies.add(depNode);
842             if (traverse) {
843                 traverse(conf, depNode);
844             }
845         }
846         return dependencies;
847     }
848
849     public void traverse(String JavaDoc conf, IvyNode depNode) {
850         if (getPath().contains(depNode)) {
851             IvyContext.getContext().getCircularDependencyStrategy().handleCircularDependency(toMrids(getPath(), depNode));
852         } else {
853             depNode.setParent(this);
854         }
855         depNode.setParentConf(conf);
856         depNode.setRootModuleConf(getRootModuleConf());
857         depNode._data = _data;
858     }
859
860     private ModuleRevisionId[] toMrids(Collection JavaDoc path, IvyNode depNode) {
861         ModuleRevisionId[] ret = new ModuleRevisionId[path.size()+1];
862         int i=0;
863         for (Iterator JavaDoc iter = path.iterator(); iter.hasNext(); i++) {
864             IvyNode node = (IvyNode) iter.next();
865             ret[i] = node.getId();
866         }
867         ret[ret.length-1] = depNode.getId();
868         return ret;
869     }
870
871     /**
872      * @return Returns the requestedConf in the current root module configuration
873      */

874     public final String JavaDoc getRequestedConf() {
875         return (String JavaDoc) _requestedConf.get(getRootModuleConf());
876     }
877     
878     public final void setRequestedConf(String JavaDoc requestedConf) {
879         _requestedConf.put(getRootModuleConf(), requestedConf);
880     }
881
882     private void addDependencyDescriptor(IvyNode parent, DependencyDescriptor dd) {
883         _dds.put(parent, dd);
884     }
885
886     private boolean isDependencyModuleExcluded(ModuleRevisionId dependencyRevisionId, String JavaDoc conf) {
887         return doesCallersExclude(getRootModuleConf(), DefaultArtifact.newIvyArtifact(dependencyRevisionId, null));
888     }
889
890     public ModuleRevisionId getId() {
891         return _id;
892     }
893
894     public void updateConfsToFetch(Collection JavaDoc confs) {
895         _confsToFetch.addAll(confs);
896         _confsToFetch.removeAll(_fetchedConfigurations);
897     }
898
899     public ModuleId getModuleId() {
900         return _id.getModuleId();
901     }
902
903     /**
904      * resolve the '*' special configurations if necessary and possible
905      */

906     private String JavaDoc[] resolveSpecialConfigurations(String JavaDoc[] dependencyConfigurations, IvyNode node) {
907         if (dependencyConfigurations.length == 1
908                 && dependencyConfigurations[0].startsWith("*")
909                 && node != null
910                 && node.isLoaded()) {
911             String JavaDoc conf = dependencyConfigurations[0];
912             if ("*".equals(conf)) {
913                 return node.getDescriptor().getPublicConfigurationsNames();
914             }
915             // there are exclusions in the configuration
916
List JavaDoc exclusions = Arrays.asList(conf.substring(2).split("\\!"));
917             
918             List JavaDoc ret = new ArrayList JavaDoc(Arrays.asList(node.getDescriptor().getPublicConfigurationsNames()));
919             ret.removeAll(exclusions);
920             
921             return (String JavaDoc[])ret.toArray(new String JavaDoc[ret.size()]);
922         }
923         return dependencyConfigurations;
924     }
925
926     public boolean isLoaded() {
927         return _md != null;
928     }
929
930     public ModuleDescriptor getDescriptor() {
931         return _md;
932     }
933
934     /**
935      * returns the required configurations from the given node
936      * @param in
937      * @return
938      */

939     public String JavaDoc[] getRequiredConfigurations(IvyNode in, String JavaDoc inConf) {
940         Collection JavaDoc req = (Collection JavaDoc)_requiredConfs.get(new NodeConf(in, inConf));
941         return req == null?new String JavaDoc[0]:(String JavaDoc[])req.toArray(new String JavaDoc[req.size()]);
942     }
943
944     /**
945      * returns all the current required configurations of the node
946      * @return
947      */

948     public String JavaDoc[] getRequiredConfigurations() {
949         Collection JavaDoc required = new ArrayList JavaDoc(_confsToFetch.size() + _fetchedConfigurations.size());
950         required.addAll(_fetchedConfigurations);
951         required.addAll(_confsToFetch);
952         return (String JavaDoc[])required.toArray(new String JavaDoc[required.size()]);
953     }
954     
955     private void setRequiredConfs(IvyNode parent, String JavaDoc parentConf, Collection JavaDoc confs) {
956         _requiredConfs.put(new NodeConf(parent, parentConf), new HashSet JavaDoc(confs));
957     }
958
959     public Configuration getConfiguration(String JavaDoc conf) {
960         if (_md == null) {
961             throw new IllegalStateException JavaDoc("impossible to get configuration when data has not been loaded");
962         }
963         String JavaDoc defaultConf = getDefaultConf(conf);
964         conf = getMainConf(conf);
965         Configuration configuration = _md.getConfiguration(conf);
966         if (configuration == null) {
967             configuration = _md.getConfiguration(defaultConf);
968         }
969         return configuration;
970     }
971
972     public ResolvedModuleRevision getModuleRevision() {
973         return _module;
974     }
975
976
977     /**
978      *
979      * @param rootModuleConf
980      * @param mrid
981      * @param callerConf
982      * @param dependencyConfs '*' must have been resolved
983      * @param dd the dependency revision id asked by the caller
984      */

985     public void addCaller(String JavaDoc rootModuleConf, IvyNode node, String JavaDoc callerConf, String JavaDoc[] dependencyConfs, DependencyDescriptor dd) {
986         ModuleDescriptor md = node.getDescriptor();
987         ModuleRevisionId mrid = node.getId();
988         if (mrid.getModuleId().equals(getId().getModuleId())) {
989             throw new IllegalArgumentException JavaDoc("a module is not authorized to depend on itself: "+getId());
990         }
991         Map JavaDoc callers = (Map JavaDoc)_callersByRootConf.get(rootModuleConf);
992         if (callers == null) {
993             callers = new HashMap JavaDoc();
994             _callersByRootConf.put(rootModuleConf, callers);
995         }
996         Caller caller = (Caller)callers.get(mrid);
997         if (caller == null) {
998             caller = new Caller(md, mrid, dd, node.canExclude(rootModuleConf));
999             callers.put(mrid, caller);
1000        }
1001        caller.addConfiguration(callerConf, dependencyConfs);
1002
1003        IvyNode parent = node.getRealNode();
1004        for (Iterator JavaDoc iter = parent._allCallers.keySet().iterator(); iter.hasNext();) {
1005            ModuleId mid = (ModuleId) iter.next();
1006            _allCallers.put(mid, parent);
1007        }
1008        _allCallers.put(mrid.getModuleId(), node);
1009        _isCircular = _allCallers.keySet().contains(getId().getModuleId());
1010        if (_isCircular) {
1011            IvyContext.getContext().getCircularDependencyStrategy().handleCircularDependency(
1012                    toMrids(findPath(getId().getModuleId()), this));
1013        }
1014    }
1015    
1016    /**
1017     * Finds and returns a path in callers from the given module id to the current node
1018     * @param from the module id to start the path from
1019     * @return a collection representing the path, starting with the from node, followed by
1020     * the list of nodes being one path to the current node, excluded
1021     */

1022    private Collection JavaDoc findPath(ModuleId from) {
1023        return findPath(from, this, new LinkedList JavaDoc());
1024    }
1025    
1026    private Collection JavaDoc findPath(ModuleId from, IvyNode node, List JavaDoc path) {
1027        IvyNode parent = (IvyNode) node._allCallers.get(from);
1028        if (parent == null) {
1029            throw new IllegalArgumentException JavaDoc("no path from "+from+" to "+getId()+" found");
1030        }
1031        if (path.contains(parent)) {
1032            path.add(0, parent);
1033            Message.verbose("circular dependency found while looking for the path for another one: was looking for "+from+" as a caller of "+path.get(path.size()-1));
1034            return path;
1035        }
1036        path.add(0, parent);
1037        if (parent.getId().getModuleId().equals(from)) {
1038            return path;
1039        }
1040        return findPath(from, parent, path);
1041    }
1042
1043    private boolean canExclude(String JavaDoc rootModuleConf) {
1044        DependencyDescriptor dd = getDependencyDescriptor(getParent());
1045        if (dd != null && dd.canExclude()) {
1046            return true;
1047        }
1048        Caller[] callers = getCallers(rootModuleConf);
1049        for (int i = 0; i < callers.length; i++) {
1050            if (callers[i].canExclude()) {
1051                return true;
1052            }
1053        }
1054        return false;
1055    }
1056
1057    public Caller[] getCallers(String JavaDoc rootModuleConf) {
1058        Map JavaDoc callers = (Map JavaDoc)_callersByRootConf.get(rootModuleConf);
1059        if (callers == null) {
1060            return new Caller[0];
1061        }
1062        return (Caller[])callers.values().toArray(new Caller[callers.values().size()]);
1063    }
1064
1065    public Caller[] getAllCallers() {
1066        Set JavaDoc all = new HashSet JavaDoc();
1067        for (Iterator JavaDoc iter = _callersByRootConf.values().iterator(); iter.hasNext();) {
1068            Map JavaDoc callers = (Map JavaDoc)iter.next();
1069            all.addAll(callers.values());
1070        }
1071        return (Caller[])all.toArray(new Caller[all.size()]);
1072    }
1073
1074    public String JavaDoc toString() {
1075        return getResolvedId().toString();
1076    }
1077    
1078    public boolean equals(Object JavaDoc obj) {
1079        if (! (obj instanceof IvyNode)) {
1080            return false;
1081        }
1082        IvyNode node = (IvyNode)obj;
1083        return node.getId().equals(getId());
1084    }
1085    
1086    public int hashCode() {
1087        return getId().hashCode();
1088    }
1089    
1090    /**
1091     * Returns the configurations of the dependency required in a given
1092     * root module configuration.
1093     * @param rootModuleConf
1094     * @return
1095     */

1096    public String JavaDoc[] getConfigurations(String JavaDoc rootModuleConf) {
1097        Set JavaDoc depConfs = (Set JavaDoc) _rootModuleConfs.get(rootModuleConf);
1098        if (depConfs == null) {
1099            return new String JavaDoc[0];
1100        }
1101        return (String JavaDoc[]) depConfs.toArray(new String JavaDoc[depConfs.size()]);
1102    }
1103
1104    public void discardConf(String JavaDoc conf) {
1105        discardConf(_rootModuleConf, conf);
1106    }
1107    
1108    public void discardConf(String JavaDoc rootModuleConf, String JavaDoc conf) {
1109        Set JavaDoc depConfs = (Set JavaDoc) _rootModuleConfs.get(rootModuleConf);
1110        if (depConfs == null) {
1111            depConfs = new HashSet JavaDoc();
1112            _rootModuleConfs.put(rootModuleConf, depConfs);
1113        }
1114        if (_md != null) {
1115            // remove all given dependency configurations to the set + extended ones
1116
Configuration c = _md.getConfiguration(conf);
1117                if (conf != null) {
1118                    String JavaDoc[] exts = c.getExtends();
1119                    for (int i = 0; i < exts.length; i++) {
1120                        discardConf(rootModuleConf, exts[i]); // recursive remove of extended configurations
1121
}
1122                    depConfs.remove(c.getName());
1123                } else {
1124                    Message.warn("unknown configuration in "+getId()+": "+conf);
1125                }
1126        } else {
1127            depConfs.remove(conf);
1128        }
1129    }
1130
1131    private void addRootModuleConfigurations(String JavaDoc rootModuleConf, String JavaDoc[] dependencyConfs) {
1132        Set JavaDoc depConfs = (Set JavaDoc) _rootModuleConfs.get(rootModuleConf);
1133        if (depConfs == null) {
1134            depConfs = new HashSet JavaDoc();
1135            _rootModuleConfs.put(rootModuleConf, depConfs);
1136        }
1137        if (_md != null) {
1138            // add all given dependency configurations to the set + extended ones
1139
for (int i = 0; i < dependencyConfs.length; i++) {
1140                Configuration conf = _md.getConfiguration(dependencyConfs[i]);
1141                if (conf != null) {
1142                    String JavaDoc[] exts = conf.getExtends();
1143                    addRootModuleConfigurations(rootModuleConf, exts); // recursive add of extended configurations
1144
depConfs.add(conf.getName());
1145                } else {
1146                    Message.warn("unknown configuration in "+getId()+": "+dependencyConfs[i]);
1147                }
1148            }
1149        } else {
1150            for (int i = 0; i < dependencyConfs.length; i++) {
1151                depConfs.add(dependencyConfs[i]);
1152            }
1153        }
1154    }
1155    
1156    /**
1157     * Returns the root module configurations in which this dependency is required
1158     * @return
1159     */

1160    public String JavaDoc[] getRootModuleConfigurations() {
1161        return (String JavaDoc[])_rootModuleConfs.keySet().toArray(new String JavaDoc[_rootModuleConfs.size()]);
1162    }
1163
1164    /**
1165     * Returns all the artifacts of this dependency required in all the
1166     * root module configurations
1167     * @return
1168     */

1169    public Artifact[] getAllArtifacts() {
1170        Set JavaDoc ret = new HashSet JavaDoc();
1171        for (Iterator JavaDoc it = _rootModuleConfs.keySet().iterator(); it.hasNext();) {
1172            String JavaDoc rootModuleConf = (String JavaDoc)it.next();
1173            ret.addAll(Arrays.asList(getArtifacts(rootModuleConf)));
1174        }
1175        return (Artifact[])ret.toArray(new Artifact[ret.size()]);
1176    }
1177
1178    /**
1179     * Returns all the artifacts of this dependency required in the
1180     * root module configurations in which the node is not evicted
1181     * @param artifactFilter
1182     * @return
1183     */

1184    public Artifact[] getSelectedArtifacts(Filter artifactFilter) {
1185        Collection JavaDoc ret = new HashSet JavaDoc();
1186        for (Iterator JavaDoc it = _rootModuleConfs.keySet().iterator(); it.hasNext();) {
1187            String JavaDoc rootModuleConf = (String JavaDoc)it.next();
1188            if (!isEvicted(rootModuleConf)) {
1189                ret.addAll(Arrays.asList(getArtifacts(rootModuleConf)));
1190            }
1191        }
1192        ret = FilterHelper.filter(ret, artifactFilter);
1193        return (Artifact[])ret.toArray(new Artifact[ret.size()]);
1194    }
1195
1196    /**
1197     * Returns the artifacts of this dependency required in the
1198     * configurations themselves required in the given root module configuration
1199     * @param rootModuleConf
1200     * @return
1201     */

1202    public Artifact[] getArtifacts(String JavaDoc rootModuleConf) {
1203        // first we look for the dependency configurations required
1204
// in the given root module configuration
1205
Set JavaDoc confs = (Set JavaDoc) _rootModuleConfs.get(rootModuleConf);
1206        if (confs == null) {
1207            // no configuration required => no artifact required
1208
return new Artifact[0];
1209        }
1210        
1211        Set JavaDoc artifacts = new HashSet JavaDoc(); // the set we fill before returning
1212

1213        // we check if we have dependencyArtifacts includes description for this rootModuleConf
1214
Set JavaDoc includes = (Set JavaDoc)_dependencyArtifactsIncludes.get(rootModuleConf);
1215        
1216        if (_md.isDefault() && includes != null && !includes.isEmpty()) {
1217            // the descriptor is a default one: it has been generated from nothing
1218
// moreover, we have dependency artifacts description
1219
// these descritions are thus used as if they were declared in the module
1220
// descriptor. If one is not really present, the error will be raised
1221
// at download time
1222
for (Iterator JavaDoc it = includes.iterator(); it.hasNext();) {
1223                DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor)it.next();
1224                artifacts.add(new MDArtifact(_md, dad.getName(), dad.getType(), dad.getExt(), dad.getUrl(), null));
1225            }
1226        } else {
1227            if (includes == null || includes.isEmpty()) {
1228                // no artifacts includes: we get all artifacts as defined by the descriptor
1229
for (Iterator JavaDoc iter = confs.iterator(); iter.hasNext();) {
1230                    String JavaDoc conf = (String JavaDoc) iter.next();
1231                    artifacts.addAll(Arrays.asList(_md.getArtifacts(conf)));
1232                }
1233            } else {
1234                // we have to get only artifacts listed as "includes"
1235

1236                // first we get all artifacts as defined by the module descriptor
1237
// and classify them by artifact id
1238
Map JavaDoc allArtifacts = new HashMap JavaDoc();
1239                for (Iterator JavaDoc iter = confs.iterator(); iter.hasNext();) {
1240                    String JavaDoc conf = (String JavaDoc) iter.next();
1241                    Artifact[] arts = _md.getArtifacts(conf);
1242                    for (int i = 0; i < arts.length; i++) {
1243                        allArtifacts.put(arts[i].getId().getArtifactId(), arts[i]);
1244                    }
1245                }
1246                
1247                // now we can keep only listed ones
1248
for (Iterator JavaDoc it = includes.iterator(); it.hasNext();) {
1249                    DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor)it.next();
1250                    Collection JavaDoc arts = findArtifactsMatching(dad, allArtifacts);
1251                    if (arts.isEmpty()) {
1252                        Message.error("a required artifact is not listed by module descriptor: "+dad.getId());
1253                        // we remove it from required list to prevent message to be displayed more than once
1254
it.remove();
1255                    } else {
1256                        Message.debug(this+" in "+rootModuleConf+": including "+arts);
1257                        artifacts.addAll(arts);
1258                    }
1259                }
1260            }
1261        }
1262        
1263        // now excludes artifacts that aren't accepted by any caller
1264
for (Iterator JavaDoc iter = artifacts.iterator(); iter.hasNext();) {
1265            Artifact artifact = (Artifact)iter.next();
1266            boolean excluded = doesCallersExclude(rootModuleConf, artifact);
1267            if (excluded) {
1268                Message.debug(this+" in "+rootModuleConf+": excluding "+artifact);
1269                iter.remove();
1270            }
1271        }
1272        return (Artifact[]) artifacts.toArray(new Artifact[artifacts.size()]);
1273    }
1274
1275    /**
1276     * Returns true if ALL callers exclude the given artifact in the given root module conf
1277     * @param rootModuleConf
1278     * @param artifact
1279     * @return
1280     */

1281    private boolean doesCallersExclude(String JavaDoc rootModuleConf, Artifact artifact) {
1282        return doesCallersExclude(rootModuleConf, artifact, new Stack JavaDoc());
1283    }
1284    private boolean doesCallersExclude(String JavaDoc rootModuleConf, Artifact artifact, Stack JavaDoc callersStack) {
1285        if (callersStack.contains(getId())) {
1286            return false;
1287        }
1288        callersStack.push(getId());
1289        try {
1290            Caller[] callers = getCallers(rootModuleConf);
1291            if (callers.length == 0) {
1292                return false;
1293            }
1294            Collection JavaDoc callersNodes = new ArrayList JavaDoc();
1295            for (int i = 0; i < callers.length; i++) {
1296                if (!callers[i].canExclude()) {
1297                    return false;
1298                }
1299                ModuleDescriptor md = callers[i].getModuleDescriptor();
1300                if (!doesExclude(md, rootModuleConf, callers[i].getCallerConfigurations(), this, callers[i].getDependencyDescriptor(), artifact, callersStack)) {
1301                    return false;
1302                }
1303            }
1304            return true;
1305        } finally {
1306            callersStack.pop();
1307        }
1308    }
1309
1310    private boolean doesExclude(ModuleDescriptor md, String JavaDoc rootModuleConf, String JavaDoc[] moduleConfs, IvyNode dependency, DependencyDescriptor dd, Artifact artifact, Stack JavaDoc callersStack) {
1311        // artifact is excluded if it match any of the exclude pattern for this dependency...
1312
if (dd != null) {
1313            if (dd.doesExclude(moduleConfs, artifact.getId().getArtifactId())) {
1314                return true;
1315            }
1316        }
1317        // ... or if it is excluded by all its callers
1318
IvyNode c = _data.getNode(md.getModuleRevisionId());
1319        if (c != null) {
1320            return c.doesCallersExclude(rootModuleConf, artifact, callersStack);
1321        } else {
1322            return false;
1323        }
1324    }
1325
1326    private static DependencyDescriptor getDependencyDescriptor(ModuleDescriptor md, IvyNode dependency) {
1327        if (md != null) {
1328            DependencyDescriptor[] dds = md.getDependencies();
1329            for (int i = 0; i < dds.length; i++) {
1330                if (dds[i].getDependencyId().equals(dependency.getModuleId())) {
1331                    return dds[i];
1332                }
1333            }
1334        }
1335        return null;
1336    }
1337
1338    private static Collection JavaDoc findArtifactsMatching(DependencyArtifactDescriptor dad, Map JavaDoc allArtifacts) {
1339        Collection JavaDoc ret = new ArrayList JavaDoc();
1340        for (Iterator JavaDoc iter = allArtifacts.keySet().iterator(); iter.hasNext();) {
1341            ArtifactId aid = (ArtifactId)iter.next();
1342            if (MatcherHelper.matches(dad.getMatcher(), dad.getId(), aid)) {
1343                ret.add(allArtifacts.get(aid));
1344            }
1345        }
1346        return ret;
1347    }
1348
1349    private void addDependencyArtifactsIncludes(String JavaDoc rootModuleConf, DependencyArtifactDescriptor[] dependencyArtifacts) {
1350        addDependencyArtifacts(rootModuleConf, dependencyArtifacts, _dependencyArtifactsIncludes);
1351    }
1352
1353    private void addDependencyArtifacts(String JavaDoc rootModuleConf, DependencyArtifactDescriptor[] dependencyArtifacts, Map JavaDoc artifactsMap) {
1354        Set JavaDoc depArtifacts = (Set JavaDoc) artifactsMap.get(rootModuleConf);
1355        if (depArtifacts == null) {
1356            depArtifacts = new HashSet JavaDoc();
1357            artifactsMap.put(rootModuleConf, depArtifacts);
1358        }
1359        depArtifacts.addAll(Arrays.asList(dependencyArtifacts));
1360    }
1361
1362    public long getPublication() {
1363        if (_module != null) {
1364            return _module.getPublicationDate().getTime();
1365        }
1366        return 0;
1367    }
1368
1369    public DependencyDescriptor getDependencyDescriptor(IvyNode parent) {
1370        return (DependencyDescriptor)_dds.get(parent);
1371    }
1372
1373    public boolean hasProblem() {
1374        return _problem != null;
1375    }
1376    
1377    public ModuleRevisionId getResolvedId() {
1378        if (_md != null && _md.getResolvedModuleRevisionId().getRevision() != null) {
1379            return _md.getResolvedModuleRevisionId();
1380        } else if (_module != null) {
1381            return _module.getId();
1382        } else {
1383            return getId();
1384        }
1385    }
1386    
1387    public Exception JavaDoc getProblem() {
1388        return _problem;
1389    }
1390
1391    public boolean isDownloaded() {
1392        return _downloaded;
1393    }
1394    
1395    public boolean isSearched() {
1396        return _searched;
1397    }
1398
1399    public String JavaDoc getRootModuleConf() {
1400        return _rootModuleConf;
1401    }
1402    
1403
1404    public void setRootModuleConf(String JavaDoc rootModuleConf) {
1405        if (_rootModuleConf != null && !_rootModuleConf.equals(rootModuleConf)) {
1406            _confsToFetch.clear(); // we change of root module conf => we discard all confs to fetch
1407
}
1408        if (rootModuleConf != null && rootModuleConf.equals(_rootModuleConf)) {
1409            _selectedDeps.put(new ModuleIdConf(_id.getModuleId(), rootModuleConf), Collections.singleton(this));
1410        }
1411        _rootModuleConf = rootModuleConf;
1412    }
1413
1414    public String JavaDoc[] getConfsToFetch() {
1415        return (String JavaDoc[])_confsToFetch.toArray(new String JavaDoc[_confsToFetch.size()]);
1416    }
1417
1418    /**
1419     * Returns true if this node can already be found among its callers
1420     * @return
1421     */

1422    public boolean isCircular() {
1423        return _isCircular;
1424    }
1425    
1426    public boolean isFetched(String JavaDoc conf) {
1427        return _fetchedConfigurations.contains(conf);
1428    }
1429
1430    /**
1431     * Returns the eviction data for this node if it has been previously evicted in the most far parent
1432     * of the given node, null otherwise (if it hasn't been evicted in root) for the
1433     * given rootModuleConf.
1434     * Note that this method only works if conflict resolution has already be done in all the ancestors.
1435     *
1436     * @param rootModuleConf
1437     * @param parent
1438     * @return
1439     */

1440    public EvictionData getEvictionDataInRoot(String JavaDoc rootModuleConf, IvyNode parent) {
1441        IvyNode root = parent.getRoot();
1442        Collection JavaDoc selectedNodes = root.getResolvedNodes(getModuleId(), rootModuleConf);
1443        for (Iterator JavaDoc iter = selectedNodes.iterator(); iter.hasNext();) {
1444            IvyNode node = (IvyNode)iter.next();
1445            if (node.getResolvedId().equals(getResolvedId())) {
1446                // the node is part of the selected ones for the root: no eviction data to return
1447
return null;
1448            }
1449        }
1450        // we didn't find this mrid in the selected ones for the root: it has been previously evicted
1451
return new EvictionData(rootModuleConf, parent, root.getConflictManager(getModuleId()), selectedNodes);
1452    }
1453
1454    public static IvyNode getRoot(IvyNode parent) {
1455        IvyNode root = parent;
1456        Collection JavaDoc path = new HashSet JavaDoc();
1457        path.add(root);
1458        while (root.getParent() != null && !root.isRoot()) {
1459            if (path.contains(root.getParent())) {
1460                return root;
1461            }
1462            root = root.getParent();
1463            path.add(root);
1464        }
1465        return root;
1466    }
1467
1468    public IvyNode findNode(ModuleRevisionId mrid) {
1469        return _data.getNode(mrid);
1470    }
1471
1472    public String JavaDoc[] getRealConfs(String JavaDoc conf) {
1473        if (_md == null) {
1474            return new String JavaDoc[] {conf};
1475        }
1476        String JavaDoc defaultConf = getDefaultConf(conf);
1477        conf = getMainConf(conf);
1478        if (_md.getConfiguration(conf) == null) {
1479            if ("".equals(defaultConf)) {
1480                return new String JavaDoc[0];
1481            }
1482            conf = defaultConf;
1483        }
1484        if (conf.startsWith("*")) {
1485            return resolveSpecialConfigurations(new String JavaDoc[] {conf}, this);
1486        } else if (conf.indexOf(',') != -1) {
1487            String JavaDoc[] confs = conf.split(",");
1488            for (int i = 0; i < confs.length; i++) {
1489                confs[i] = confs[i].trim();
1490            }
1491        }
1492        return new String JavaDoc[] {conf};
1493        
1494    }
1495
1496    /**
1497     * Returns true if the current dependency descriptor is transitive
1498     * and the parent configuration is transitive. Otherwise returns false.
1499     * @param node curent node
1500     * @return true if current node is transitive and the parent configuration is
1501     * transitive.
1502     */

1503    protected boolean isTransitive() {
1504        return (_data.isTransitive() &&
1505                getDependencyDescriptor(getParent()).isTransitive() &&
1506                isParentConfTransitive() );
1507    }
1508
1509    /**
1510     * Checks if the current node's parent configuration is transitive.
1511     * @param node current node
1512     * @return true if the node's parent configuration is transitive
1513     */

1514    protected boolean isParentConfTransitive() {
1515        String JavaDoc conf = getParent().getRequestedConf();
1516        if (conf==null) {
1517            return true;
1518        }
1519        Configuration parentConf = getParent().getConfiguration(conf);
1520        return parentConf.isTransitive();
1521
1522    }
1523
1524    public ResolveData getResolveData() {
1525        return _data;
1526    }
1527
1528}
1529
Popular Tags