0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: */
0018: package org.apache.ivy.core.resolve;
0019:
0020: import java.util.ArrayList;
0021: import java.util.Arrays;
0022: import java.util.Collection;
0023: import java.util.HashMap;
0024: import java.util.HashSet;
0025: import java.util.Iterator;
0026: import java.util.LinkedHashSet;
0027: import java.util.LinkedList;
0028: import java.util.List;
0029: import java.util.Map;
0030: import java.util.Set;
0031: import java.util.Stack;
0032: import java.util.regex.Matcher;
0033: import java.util.regex.Pattern;
0034:
0035: import org.apache.ivy.core.IvyContext;
0036: import org.apache.ivy.core.LogOptions;
0037: import org.apache.ivy.core.event.resolve.EndResolveDependencyEvent;
0038: import org.apache.ivy.core.event.resolve.StartResolveDependencyEvent;
0039: import org.apache.ivy.core.module.descriptor.Artifact;
0040: import org.apache.ivy.core.module.descriptor.Configuration;
0041: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
0042: import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor;
0043: import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
0044: import org.apache.ivy.core.module.descriptor.IncludeRule;
0045: import org.apache.ivy.core.module.descriptor.MDArtifact;
0046: import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
0047: import org.apache.ivy.core.module.id.ArtifactId;
0048: import org.apache.ivy.core.module.id.ModuleId;
0049: import org.apache.ivy.core.module.id.ModuleRevisionId;
0050: import org.apache.ivy.core.resolve.IvyNodeCallers.Caller;
0051: import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData;
0052: import org.apache.ivy.plugins.conflict.ConflictManager;
0053: import org.apache.ivy.plugins.matcher.MatcherHelper;
0054: import org.apache.ivy.plugins.resolver.DependencyResolver;
0055: import org.apache.ivy.util.Message;
0056: import org.apache.ivy.util.StringUtils;
0057: import org.apache.ivy.util.filter.Filter;
0058: import org.apache.ivy.util.filter.FilterHelper;
0059:
0060: public class IvyNode implements Comparable {
0061: private static final Pattern FALLBACK_CONF_PATTERN = Pattern
0062: .compile("(.+)\\((.*)\\)");
0063:
0064: private static final class NodeConf {
0065: private IvyNode node;
0066:
0067: private String conf;
0068:
0069: public NodeConf(IvyNode node, String conf) {
0070: if (node == null) {
0071: throw new NullPointerException("node must not null");
0072: }
0073: if (conf == null) {
0074: throw new NullPointerException("conf must not null");
0075: }
0076: this .node = node;
0077: this .conf = conf;
0078: }
0079:
0080: public final String getConf() {
0081: return conf;
0082: }
0083:
0084: public final IvyNode getNode() {
0085: return node;
0086: }
0087:
0088: public boolean equals(Object obj) {
0089: if (!(obj instanceof NodeConf)) {
0090: return false;
0091: }
0092: return getNode().equals(((NodeConf) obj).getNode())
0093: && getConf().equals(((NodeConf) obj).getConf());
0094: }
0095:
0096: public int hashCode() {
0097: //CheckStyle:MagicNumber| OFF
0098: int hash = 33;
0099: hash += getNode().hashCode() * 17;
0100: hash += getConf().hashCode() * 17;
0101: //CheckStyle:MagicNumber| OFF
0102: return hash;
0103: }
0104:
0105: public String toString() {
0106: return "NodeConf(" + conf + ")";
0107: }
0108: }
0109:
0110: // //////// CONTEXT
0111: private ResolveData data;
0112:
0113: private ResolveEngineSettings settings;
0114:
0115: // //////// DELEGATES
0116: private IvyNodeCallers callers;
0117:
0118: private IvyNodeEviction eviction;
0119:
0120: // //////// MAIN DATA
0121:
0122: private IvyNode root;
0123:
0124: // id as requested, i.e. may be with latest rev
0125: private ModuleRevisionId id;
0126:
0127: // set only when node has been built or updated from a DependencyDescriptor
0128: // Map(IvyNode parent -> DependencyDescriptor)
0129: private Map dds = new HashMap();
0130:
0131: // Set when data has been loaded only, or when constructed from a module descriptor
0132: private ModuleDescriptor md;
0133:
0134: private ResolvedModuleRevision module;
0135:
0136: // //////// LOADING METADATA
0137: private Exception problem = null;
0138:
0139: private boolean downloaded = false;
0140:
0141: private boolean searched = false;
0142:
0143: private Collection confsToFetch = new HashSet();
0144:
0145: private Collection fetchedConfigurations = new HashSet();
0146:
0147: private Collection loadedRootModuleConfs = new HashSet();
0148:
0149: // //////// USAGE DATA
0150:
0151: // Map (String rootConfName -> Set(String confName))
0152: // used to know which configurations of the dependency are required
0153: // for each root module configuration
0154: private Map rootModuleConfs = new HashMap();
0155:
0156: // Map (NodeConf in -> Set(String conf))
0157: private Map requiredConfs = new HashMap();
0158:
0159: // Map (String rootModuleConf -> Set(DependencyArtifactDescriptor))
0160: private Map dependencyArtifacts = new HashMap();
0161:
0162: // Map (String rootModuleConf -> Set(IncludeRule))
0163: private Map dependencyIncludes = new HashMap();
0164:
0165: // Map (String rootModuleConf -> IvyNodeBlacklist)
0166: private Map blacklisted = new HashMap();
0167:
0168: public IvyNode(ResolveData data, IvyNode parent,
0169: DependencyDescriptor dd) {
0170: id = dd.getDependencyRevisionId();
0171: dds.put(parent, dd);
0172: root = parent.getRoot();
0173: init(data);
0174: }
0175:
0176: public IvyNode(ResolveData data, ModuleDescriptor md) {
0177: id = md.getModuleRevisionId();
0178: this .md = md;
0179: root = this ;
0180: init(data);
0181: }
0182:
0183: private void init(ResolveData data) {
0184: this .data = data;
0185: settings = data.getSettings();
0186: eviction = new IvyNodeEviction(this );
0187: callers = new IvyNodeCallers(this );
0188: }
0189:
0190: /**
0191: * After the call node may be discarded. To avoid using discarded node, make sure to get the
0192: * real node after the call IvyNode node = ... node.loadData(); node = node.getRealNode(); ...
0193: */
0194: public boolean loadData(String rootModuleConf, IvyNode parent,
0195: String parentConf, String conf, boolean shouldBePublic) {
0196: Message.debug("loadData of " + this .toString()
0197: + " of rootConf=" + rootModuleConf);
0198: if (!isRoot() && (data.getReport() != null)) {
0199: data.getReport().addDependency(this );
0200: }
0201:
0202: boolean loaded = false;
0203: if (hasProblem()) {
0204: Message.debug("Node has problem. Skip loading");
0205: } else if (isEvicted(rootModuleConf)) {
0206: Message
0207: .debug(rootModuleConf
0208: + " is evicted. Skip loading");
0209: } else if (!hasConfigurationsToLoad()
0210: && isRootModuleConfLoaded(rootModuleConf)) {
0211: Message.debug(rootModuleConf
0212: + " is loaded and no conf to load. Skip loading");
0213: } else {
0214: markRootModuleConfLoaded(rootModuleConf);
0215: if (md == null) {
0216: DependencyResolver resolver = data.getSettings()
0217: .getResolver(getId());
0218: if (resolver == null) {
0219: Message.error("no resolver found for "
0220: + getModuleId()
0221: + ": check your configuration");
0222: problem = new RuntimeException(
0223: "no resolver found for " + getModuleId()
0224: + ": check your configuration");
0225: return false;
0226: }
0227: try {
0228: Message.debug("\tusing " + resolver
0229: + " to resolve " + getId());
0230: DependencyDescriptor dependencyDescriptor = getDependencyDescriptor(parent);
0231: long start = System.currentTimeMillis();
0232: data.getEventManager().fireIvyEvent(
0233: new StartResolveDependencyEvent(resolver,
0234: dependencyDescriptor));
0235: module = resolver.getDependency(
0236: dependencyDescriptor, data);
0237: data.getEventManager()
0238: .fireIvyEvent(
0239: new EndResolveDependencyEvent(
0240: resolver,
0241: dependencyDescriptor,
0242: module,
0243: System.currentTimeMillis()
0244: - start));
0245: if (module != null) {
0246: module.getResolver()
0247: .getRepositoryCacheManager()
0248: .saveResolvers(
0249: module.getDescriptor(),
0250: module.getResolver().getName(),
0251: module.getArtifactResolver()
0252: .getName());
0253: if (settings.logModuleWhenFound()
0254: && LogOptions.LOG_DEFAULT
0255: .equals(getData().getOptions()
0256: .getLog())) {
0257: Message.info("\tfound " + module.getId()
0258: + " in "
0259: + module.getResolver().getName());
0260: } else {
0261: Message.verbose("\tfound " + module.getId()
0262: + " in "
0263: + module.getResolver().getName());
0264: }
0265:
0266: if (settings.getVersionMatcher().isDynamic(
0267: getId())) {
0268: // IVY-56: check if revision has actually been resolved
0269: if (settings.getVersionMatcher().isDynamic(
0270: module.getId())) {
0271: Message
0272: .error("impossible to resolve dynamic revision for "
0273: + getId()
0274: + ": check your configuration and make sure revision is part of your pattern");
0275: problem = new RuntimeException(
0276: "impossible to resolve dynamic revision");
0277: return false;
0278: }
0279: IvyNode resolved = data.getNode(module
0280: .getId());
0281: if (resolved != null) {
0282: // exact revision has already been resolved
0283: // => update it and discard this node
0284: md = module.getDescriptor(); // needed for handleConfiguration
0285: if (!handleConfiguration(loaded,
0286: rootModuleConf, parent,
0287: parentConf, conf,
0288: shouldBePublic)) {
0289: return false;
0290: }
0291:
0292: if (resolved.md == null) {
0293: resolved.md = md;
0294: }
0295: if (resolved.module == null) {
0296: resolved.module = module;
0297: }
0298: resolved.downloaded |= module
0299: .getReport().isDownloaded();
0300: resolved.searched |= module.getReport()
0301: .isSearched();
0302: resolved.dds.putAll(dds);
0303: resolved.updateDataFrom(this ,
0304: rootModuleConf, true);
0305: resolved.loadData(rootModuleConf,
0306: parent, parentConf, conf,
0307: shouldBePublic);
0308: DependencyDescriptor dd = dependencyDescriptor;
0309: if (dd != null) {
0310: resolved
0311: .addDependencyArtifacts(
0312: rootModuleConf,
0313: dd
0314: .getDependencyArtifacts(parentConf));
0315: resolved
0316: .addDependencyIncludes(
0317: rootModuleConf,
0318: dd
0319: .getIncludeRules(parentConf));
0320: }
0321:
0322: data.replaceNode(getId(), resolved,
0323: rootModuleConf);
0324: // this actually discards the node
0325:
0326: if (settings.logResolvedRevision()) {
0327: Message.info("\t["
0328: + module.getId()
0329: .getRevision()
0330: + "] " + getId());
0331: } else {
0332: Message.verbose("\t["
0333: + module.getId()
0334: .getRevision()
0335: + "] " + getId());
0336: }
0337:
0338: return true;
0339: }
0340: }
0341: downloaded = module.getReport().isDownloaded();
0342: searched = module.getReport().isSearched();
0343: } else {
0344: Message.warn("\tmodule not found: " + getId());
0345: resolver.reportFailure();
0346: problem = new RuntimeException("not found");
0347: }
0348: } catch (ResolveProcessException e) {
0349: throw e;
0350: } catch (Exception e) {
0351: e.printStackTrace();
0352: problem = e;
0353: }
0354:
0355: // still not resolved, report error
0356: if (module == null) {
0357: return false;
0358: } else {
0359: loaded = true;
0360: if (settings.getVersionMatcher().isDynamic(getId())) {
0361: if (settings.logResolvedRevision()) {
0362: Message.info("\t["
0363: + module.getId().getRevision()
0364: + "] " + getId());
0365: } else {
0366: Message.verbose("\t["
0367: + module.getId().getRevision()
0368: + "] " + getId());
0369: }
0370: }
0371: md = module.getDescriptor();
0372: confsToFetch.remove("*");
0373: updateConfsToFetch(Arrays
0374: .asList(resolveSpecialConfigurations(
0375: getRequiredConfigurations(parent,
0376: parentConf), this )));
0377: }
0378: } else {
0379: loaded = true;
0380: }
0381: }
0382: handleConfiguration(loaded, rootModuleConf, parent, parentConf,
0383: conf, shouldBePublic);
0384: if (hasProblem()) {
0385: Message.debug("problem : " + problem.getMessage());
0386: return false;
0387: } else {
0388: DependencyDescriptor dd = getDependencyDescriptor(parent);
0389: if (dd != null) {
0390: addDependencyArtifacts(rootModuleConf, dd
0391: .getDependencyArtifacts(parentConf));
0392: addDependencyIncludes(rootModuleConf, dd
0393: .getIncludeRules(parentConf));
0394: }
0395: return loaded;
0396: }
0397: }
0398:
0399: public Collection getDependencies(String rootModuleConf,
0400: String[] confs) {
0401: if (md == null) {
0402: throw new IllegalStateException(
0403: "impossible to get dependencies when data has not been loaded");
0404: }
0405: if (Arrays.asList(confs).contains("*")) {
0406: confs = md.getConfigurationsNames();
0407: }
0408: Collection deps = new HashSet();
0409: for (int i = 0; i < confs.length; i++) {
0410: deps.addAll(getDependencies(rootModuleConf, confs[i],
0411: confs[i]));
0412: }
0413: return deps;
0414: }
0415:
0416: public Collection getDependencies(String rootModuleConf,
0417: String conf, String requestedConf) {
0418: if (md == null) {
0419: throw new IllegalStateException(
0420: "impossible to get dependencies when data has not been loaded");
0421: }
0422: DependencyDescriptor[] dds = md.getDependencies();
0423: Collection dependencies = new LinkedHashSet(); // it's important to respect order
0424: for (int i = 0; i < dds.length; i++) {
0425: DependencyDescriptor dd = dds[i];
0426: String[] dependencyConfigurations = dd
0427: .getDependencyConfigurations(conf, requestedConf);
0428: if (dependencyConfigurations.length == 0) {
0429: // no configuration of the dependency is required for current confs :
0430: // it is exactly the same as if there was no dependency at all on it
0431: continue;
0432: }
0433: if (isDependencyModuleExcluded(rootModuleConf, dd
0434: .getDependencyRevisionId(), conf)) {
0435: // the whole module is excluded, it is considered as not being part of dependencies
0436: // at all
0437: Message.verbose("excluding "
0438: + dd.getDependencyRevisionId() + " in " + conf);
0439: continue;
0440: }
0441: IvyNode depNode = data
0442: .getNode(dd.getDependencyRevisionId());
0443: if (depNode == null) {
0444: depNode = new IvyNode(data, this , dd);
0445: } else {
0446: depNode.addDependencyDescriptor(this , dd);
0447: if (depNode.hasProblem()) {
0448: // dependency already tried to be resolved, but unsuccessfully
0449: // nothing special to do
0450: }
0451:
0452: }
0453: Collection confs = Arrays
0454: .asList(resolveSpecialConfigurations(
0455: dependencyConfigurations, depNode));
0456: depNode.updateConfsToFetch(confs);
0457: depNode.setRequiredConfs(this , conf, confs);
0458:
0459: depNode.addCaller(rootModuleConf, this , conf,
0460: dependencyConfigurations, dd);
0461: dependencies.add(depNode);
0462: }
0463: return dependencies;
0464: }
0465:
0466: private void addDependencyDescriptor(IvyNode parent,
0467: DependencyDescriptor dd) {
0468: dds.put(parent, dd);
0469: }
0470:
0471: public DependencyDescriptor getDependencyDescriptor(IvyNode parent) {
0472: return (DependencyDescriptor) dds.get(parent);
0473: }
0474:
0475: private boolean isDependencyModuleExcluded(String rootModuleConf,
0476: ModuleRevisionId dependencyRevisionId, String conf) {
0477: return callers.doesCallersExclude(rootModuleConf,
0478: DefaultArtifact.newIvyArtifact(dependencyRevisionId,
0479: null));
0480: }
0481:
0482: public boolean hasConfigurationsToLoad() {
0483: return !confsToFetch.isEmpty();
0484: }
0485:
0486: private boolean markRootModuleConfLoaded(String rootModuleConf) {
0487: return loadedRootModuleConfs.add(rootModuleConf);
0488: }
0489:
0490: private boolean isRootModuleConfLoaded(String rootModuleConf) {
0491: return loadedRootModuleConfs.contains(rootModuleConf);
0492: }
0493:
0494: private boolean handleConfiguration(boolean loaded,
0495: String rootModuleConf, IvyNode parent, String parentConf,
0496: String conf, boolean shouldBePublic) {
0497: if (md != null) {
0498: String[] confs = getRealConfs(conf);
0499: for (int i = 0; i < confs.length; i++) {
0500: Configuration c = md.getConfiguration(confs[i]);
0501: if (c == null) {
0502: confsToFetch.remove(conf);
0503: if (!conf.equals(confs[i])) {
0504: problem = new RuntimeException(
0505: "configuration(s) not found in " + this
0506: + ": " + conf
0507: + ". Missing configuration: "
0508: + confs[i]
0509: + ". It was required from "
0510: + parent + " " + parentConf);
0511: } else {
0512: problem = new RuntimeException(
0513: "configuration(s) not found in " + this
0514: + ": " + confs[i]
0515: + ". It was required from "
0516: + parent + " " + parentConf);
0517: }
0518: return false;
0519: } else if (shouldBePublic
0520: && !isRoot()
0521: && c.getVisibility() != Configuration.Visibility.PUBLIC) {
0522: confsToFetch.remove(conf);
0523: problem = new RuntimeException(
0524: "configuration not public in " + this
0525: + ": " + c
0526: + ". It was required from "
0527: + parent + " " + parentConf);
0528: return false;
0529: }
0530: if (loaded) {
0531: fetchedConfigurations.add(conf);
0532: confsToFetch.removeAll(Arrays.asList(confs));
0533: confsToFetch.remove(conf);
0534: }
0535: addRootModuleConfigurations(rootModuleConf, confs);
0536: }
0537: }
0538: return true;
0539: }
0540:
0541: private String getDefaultConf(String conf) {
0542: Matcher m = FALLBACK_CONF_PATTERN.matcher(conf);
0543: if (m.matches()) {
0544: return m.group(2);
0545: } else {
0546: return conf;
0547: }
0548: }
0549:
0550: private String getMainConf(String conf) {
0551: Matcher m = FALLBACK_CONF_PATTERN.matcher(conf);
0552: if (m.matches()) {
0553: return m.group(1);
0554: } else {
0555: return null;
0556: }
0557: }
0558:
0559: public void updateConfsToFetch(Collection confs) {
0560: confsToFetch.addAll(confs);
0561: confsToFetch.removeAll(fetchedConfigurations);
0562: }
0563:
0564: /**
0565: * resolve the '*' special configurations if necessary and possible
0566: */
0567: private String[] resolveSpecialConfigurations(
0568: String[] dependencyConfigurations, IvyNode node) {
0569: if (dependencyConfigurations.length == 1
0570: && dependencyConfigurations[0].startsWith("*")
0571: && node != null && node.isLoaded()) {
0572: String conf = dependencyConfigurations[0];
0573: if ("*".equals(conf)) {
0574: return node.getDescriptor()
0575: .getPublicConfigurationsNames();
0576: }
0577: // there are exclusions in the configuration
0578: List exclusions = Arrays.asList(conf.substring(2).split(
0579: "\\!"));
0580:
0581: List ret = new ArrayList(Arrays.asList(node.getDescriptor()
0582: .getPublicConfigurationsNames()));
0583: ret.removeAll(exclusions);
0584:
0585: return (String[]) ret.toArray(new String[ret.size()]);
0586: }
0587: return dependencyConfigurations;
0588: }
0589:
0590: /**
0591: * returns the required configurations from the given node
0592: *
0593: * @param in
0594: * @return
0595: */
0596: public String[] getRequiredConfigurations(IvyNode in, String inConf) {
0597: Collection req = (Collection) requiredConfs.get(new NodeConf(
0598: in, inConf));
0599: return req == null ? new String[0] : (String[]) req
0600: .toArray(new String[req.size()]);
0601: }
0602:
0603: /**
0604: * returns all the current required configurations of the node
0605: *
0606: * @return
0607: */
0608: public String[] getRequiredConfigurations() {
0609: Collection required = new ArrayList(confsToFetch.size()
0610: + fetchedConfigurations.size());
0611: required.addAll(fetchedConfigurations);
0612: required.addAll(confsToFetch);
0613: return (String[]) required.toArray(new String[required.size()]);
0614: }
0615:
0616: private void setRequiredConfs(IvyNode parent, String parentConf,
0617: Collection confs) {
0618: requiredConfs.put(new NodeConf(parent, parentConf),
0619: new HashSet(confs));
0620: }
0621:
0622: public Configuration getConfiguration(String conf) {
0623: if (md == null) {
0624: throw new IllegalStateException(
0625: "impossible to get configuration when data has not been loaded");
0626: }
0627: String defaultConf = getDefaultConf(conf);
0628: conf = getMainConf(conf);
0629: Configuration configuration = md.getConfiguration(conf);
0630: if (configuration == null) {
0631: configuration = md.getConfiguration(defaultConf);
0632: }
0633: return configuration;
0634: }
0635:
0636: /**
0637: * Returns the configurations of the dependency required in a given root module configuration.
0638: *
0639: * @param rootModuleConf
0640: * @return
0641: */
0642: public String[] getConfigurations(String rootModuleConf) {
0643: Set depConfs = (Set) rootModuleConfs.get(rootModuleConf);
0644: if (depConfs == null) {
0645: return new String[0];
0646: }
0647: return (String[]) depConfs.toArray(new String[depConfs.size()]);
0648: }
0649:
0650: //This is never called. Could we remove it?
0651: public void discardConf(String rootModuleConf, String conf) {
0652: Set depConfs = (Set) rootModuleConfs.get(rootModuleConf);
0653: if (depConfs == null) {
0654: depConfs = new HashSet();
0655: rootModuleConfs.put(rootModuleConf, depConfs);
0656: }
0657: if (md != null) {
0658: // remove all given dependency configurations to the set + extended ones
0659: Configuration c = md.getConfiguration(conf);
0660: if (conf != null) {
0661: String[] exts = c.getExtends();
0662: for (int i = 0; i < exts.length; i++) {
0663: discardConf(rootModuleConf, exts[i]); // recursive remove of extended
0664: // configurations
0665: }
0666: depConfs.remove(c.getName());
0667: } else {
0668: Message.warn("unknown configuration in " + getId()
0669: + ": " + conf);
0670: }
0671: } else {
0672: depConfs.remove(conf);
0673: }
0674: }
0675:
0676: private void addRootModuleConfigurations(String rootModuleConf,
0677: String[] dependencyConfs) {
0678: Set depConfs = (Set) rootModuleConfs.get(rootModuleConf);
0679: if (depConfs == null) {
0680: depConfs = new HashSet();
0681: rootModuleConfs.put(rootModuleConf, depConfs);
0682: }
0683: if (md != null) {
0684: // add all given dependency configurations to the set + extended ones
0685: for (int i = 0; i < dependencyConfs.length; i++) {
0686: Configuration conf = md
0687: .getConfiguration(dependencyConfs[i]);
0688: if (conf != null) {
0689: String[] exts = conf.getExtends();
0690: addRootModuleConfigurations(rootModuleConf, exts); // recursive add of extended
0691: // configurations
0692: depConfs.add(conf.getName());
0693: } else {
0694: Message.warn("unknown configuration in " + getId()
0695: + ": " + dependencyConfs[i]);
0696: }
0697: }
0698: } else {
0699: for (int i = 0; i < dependencyConfs.length; i++) {
0700: depConfs.add(dependencyConfs[i]);
0701: }
0702: }
0703: }
0704:
0705: /**
0706: * Returns the root module configurations in which this dependency is required
0707: *
0708: * @return
0709: */
0710: public String[] getRootModuleConfigurations() {
0711: return (String[]) rootModuleConfs.keySet().toArray(
0712: new String[rootModuleConfs.size()]);
0713: }
0714:
0715: public String[] getConfsToFetch() {
0716: return (String[]) confsToFetch.toArray(new String[confsToFetch
0717: .size()]);
0718: }
0719:
0720: public String[] getRealConfs(String conf) {
0721: if (md == null) {
0722: return new String[] { conf };
0723: }
0724: String defaultConf = getDefaultConf(conf);
0725: conf = getMainConf(conf);
0726: if (md.getConfiguration(conf) == null) {
0727: if ("".equals(defaultConf)) {
0728: return new String[0];
0729: }
0730: conf = defaultConf;
0731: }
0732: if (conf.startsWith("*")) {
0733: return resolveSpecialConfigurations(new String[] { conf },
0734: this );
0735: } else if (conf.indexOf(',') != -1) {
0736: String[] confs = conf.split(",");
0737: for (int i = 0; i < confs.length; i++) {
0738: confs[i] = confs[i].trim();
0739: }
0740: }
0741: return new String[] { conf };
0742:
0743: }
0744:
0745: /**
0746: * Finds and returns a path in callers from the given module id to the current node
0747: *
0748: * @param from
0749: * the module id to start the path from
0750: * @return a collection representing the path, starting with the from node, followed by the list
0751: * of nodes being one path to the current node, excluded
0752: */
0753: private Collection findPath(ModuleId from) {
0754: return findPath(from, this , new LinkedList());
0755: }
0756:
0757: private Collection findPath(ModuleId from, IvyNode node, List path) {
0758: IvyNode parent = (IvyNode) node.getDirectCallerFor(from);
0759: if (parent == null) {
0760: throw new IllegalArgumentException("no path from " + from
0761: + " to " + getId() + " found");
0762: }
0763: if (path.contains(parent)) {
0764: path.add(0, parent);
0765: Message
0766: .verbose("circular dependency found while looking for the path for another one: was looking for "
0767: + from
0768: + " as a caller of "
0769: + path.get(path.size() - 1));
0770: return path;
0771: }
0772: path.add(0, parent);
0773: if (parent.getId().getModuleId().equals(from)) {
0774: return path;
0775: }
0776: return findPath(from, parent, path);
0777: }
0778:
0779: /**
0780: * Update data in this node from data of the given node, for the given root module
0781: * configuration.
0782: *
0783: * @param node
0784: * the source node from which data should be copied
0785: * @param rootModuleConf
0786: * the root module configuration for which data should be updated
0787: * @param real
0788: * true if the node to update from actually corresponds to the same real node
0789: * (usually updated because of dynamic revision resolution), false if it's not the
0790: * same real node (usually updated because of node eviction)
0791: */
0792: private void updateDataFrom(IvyNode node, String rootModuleConf,
0793: boolean real) {
0794: // update callers
0795: callers.updateFrom(node.callers, rootModuleConf, real);
0796:
0797: // update requiredConfs
0798: updateMapOfSet(node.requiredConfs, requiredConfs);
0799:
0800: // update rootModuleConfs
0801: updateMapOfSetForKey(node.rootModuleConfs, rootModuleConfs,
0802: rootModuleConf);
0803:
0804: // update dependencyArtifactsIncludes
0805: updateMapOfSetForKey(node.dependencyArtifacts,
0806: dependencyArtifacts, rootModuleConf);
0807:
0808: // update confsToFetch
0809: updateConfsToFetch(node.fetchedConfigurations);
0810: updateConfsToFetch(node.confsToFetch);
0811: }
0812:
0813: private void updateMapOfSet(Map from, Map to) {
0814: for (Iterator iter = from.keySet().iterator(); iter.hasNext();) {
0815: Object key = iter.next();
0816: updateMapOfSetForKey(from, to, key);
0817: }
0818: }
0819:
0820: private void updateMapOfSetForKey(Map from, Map to, Object key) {
0821: Set set = (Set) from.get(key);
0822: if (set != null) {
0823: Set toupdate = (Set) to.get(key);
0824: if (toupdate != null) {
0825: toupdate.addAll(set);
0826: } else {
0827: to.put(key, new HashSet(set));
0828: }
0829: }
0830: }
0831:
0832: /**
0833: * Returns all the artifacts of this dependency required in all the root module configurations
0834: *
0835: * @return
0836: */
0837: public Artifact[] getAllArtifacts() {
0838: Set ret = new HashSet();
0839: for (Iterator it = rootModuleConfs.keySet().iterator(); it
0840: .hasNext();) {
0841: String rootModuleConf = (String) it.next();
0842: ret.addAll(Arrays.asList(getArtifacts(rootModuleConf)));
0843: }
0844: return (Artifact[]) ret.toArray(new Artifact[ret.size()]);
0845: }
0846:
0847: /**
0848: * Returns all the artifacts of this dependency required in the root module configurations in
0849: * which the node is not evicted nor blacklisted
0850: *
0851: * @param artifactFilter
0852: * @return
0853: */
0854: public Artifact[] getSelectedArtifacts(Filter artifactFilter) {
0855: Collection ret = new HashSet();
0856: for (Iterator it = rootModuleConfs.keySet().iterator(); it
0857: .hasNext();) {
0858: String rootModuleConf = (String) it.next();
0859: if (!isEvicted(rootModuleConf)
0860: && !isBlacklisted(rootModuleConf)) {
0861: ret.addAll(Arrays.asList(getArtifacts(rootModuleConf)));
0862: }
0863: }
0864: ret = FilterHelper.filter(ret, artifactFilter);
0865: return (Artifact[]) ret.toArray(new Artifact[ret.size()]);
0866: }
0867:
0868: /**
0869: * Returns the artifacts of this dependency required in the configurations themselves required
0870: * in the given root module configuration
0871: *
0872: * @param rootModuleConf
0873: * @return
0874: */
0875: public Artifact[] getArtifacts(String rootModuleConf) {
0876: // first we look for the dependency configurations required
0877: // in the given root module configuration
0878: Set confs = (Set) rootModuleConfs.get(rootModuleConf);
0879: if (confs == null) {
0880: // no configuration required => no artifact required
0881: return new Artifact[0];
0882: }
0883: if (md == null) {
0884: throw new IllegalStateException(
0885: "impossible to get artefacts when data has not been loaded. IvyNode = "
0886: + this .toString());
0887: }
0888:
0889: Set artifacts = new HashSet(); // the set we fill before returning
0890:
0891: // we check if we have dependencyArtifacts includes description for this rootModuleConf
0892: Set dependencyArtifacts = (Set) this .dependencyArtifacts
0893: .get(rootModuleConf);
0894:
0895: if (md.isDefault() && dependencyArtifacts != null
0896: && !dependencyArtifacts.isEmpty()) {
0897: // the descriptor is a default one: it has been generated from nothing
0898: // moreover, we have dependency artifacts description
0899: // these descritions are thus used as if they were declared in the module
0900: // descriptor. If one is not really present, the error will be raised
0901: // at download time
0902: for (Iterator it = dependencyArtifacts.iterator(); it
0903: .hasNext();) {
0904: DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor) it
0905: .next();
0906: artifacts.add(new MDArtifact(md, dad.getName(), dad
0907: .getType(), dad.getExt(), dad.getUrl(), dad
0908: .getExtraAttributes()));
0909: }
0910: } else {
0911: Set includes = (Set) dependencyIncludes.get(rootModuleConf);
0912:
0913: if ((dependencyArtifacts == null || dependencyArtifacts
0914: .isEmpty())
0915: && (includes == null || includes.isEmpty())) {
0916: // no artifacts / includes: we get all artifacts as defined by the descriptor
0917: for (Iterator iter = confs.iterator(); iter.hasNext();) {
0918: String conf = (String) iter.next();
0919: artifacts.addAll(Arrays.asList(md
0920: .getArtifacts(conf)));
0921: }
0922: } else {
0923: // we have to get only artifacts listed as "includes"
0924:
0925: // first we get all artifacts as defined by the module descriptor
0926: // and classify them by artifact id
0927: Map allArtifacts = new HashMap();
0928: for (Iterator iter = confs.iterator(); iter.hasNext();) {
0929: String conf = (String) iter.next();
0930: Artifact[] arts = md.getArtifacts(conf);
0931: for (int i = 0; i < arts.length; i++) {
0932: allArtifacts.put(arts[i].getId()
0933: .getArtifactId(), arts[i]);
0934: }
0935: }
0936:
0937: // now we add caller defined ones
0938: for (Iterator it = dependencyArtifacts.iterator(); it
0939: .hasNext();) {
0940: DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor) it
0941: .next();
0942: artifacts.add(new MDArtifact(md, dad.getName(), dad
0943: .getType(), dad.getExt(), dad.getUrl(), dad
0944: .getExtraAttributes()));
0945: }
0946:
0947: // and now we filter according to include rules
0948: for (Iterator it = includes.iterator(); it.hasNext();) {
0949: IncludeRule dad = (IncludeRule) it.next();
0950: Collection arts = findArtifactsMatching(dad,
0951: allArtifacts);
0952: if (arts.isEmpty()) {
0953: Message
0954: .error("a required artifact is not listed by module descriptor: "
0955: + dad.getId());
0956: // we remove it from required list to prevent message to be displayed more
0957: // than once
0958: it.remove();
0959: } else {
0960: Message.debug(this + " in " + rootModuleConf
0961: + ": including " + arts);
0962: artifacts.addAll(arts);
0963: }
0964: }
0965: }
0966: }
0967:
0968: // now excludes artifacts that aren't accepted by any caller
0969: for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
0970: Artifact artifact = (Artifact) iter.next();
0971: boolean excluded = callers.doesCallersExclude(
0972: rootModuleConf, artifact);
0973: if (excluded) {
0974: Message.debug(this + " in " + rootModuleConf
0975: + ": excluding " + artifact);
0976: iter.remove();
0977: }
0978: }
0979: return (Artifact[]) artifacts.toArray(new Artifact[artifacts
0980: .size()]);
0981: }
0982:
0983: private static Collection findArtifactsMatching(IncludeRule rule,
0984: Map allArtifacts) {
0985: Collection ret = new ArrayList();
0986: for (Iterator iter = allArtifacts.keySet().iterator(); iter
0987: .hasNext();) {
0988: ArtifactId aid = (ArtifactId) iter.next();
0989: if (MatcherHelper.matches(rule.getMatcher(), rule.getId(),
0990: aid)) {
0991: ret.add(allArtifacts.get(aid));
0992: }
0993: }
0994: return ret;
0995: }
0996:
0997: private void addDependencyArtifacts(String rootModuleConf,
0998: DependencyArtifactDescriptor[] dependencyArtifacts) {
0999: addObjectsForConf(rootModuleConf, Arrays
1000: .asList(dependencyArtifacts), this .dependencyArtifacts);
1001: }
1002:
1003: private void addDependencyIncludes(String rootModuleConf,
1004: IncludeRule[] rules) {
1005: addObjectsForConf(rootModuleConf, Arrays.asList(rules),
1006: dependencyIncludes);
1007: }
1008:
1009: private void addObjectsForConf(String rootModuleConf,
1010: Collection objectsToAdd, Map map) {
1011: Set set = (Set) map.get(rootModuleConf);
1012: if (set == null) {
1013: set = new HashSet();
1014: map.put(rootModuleConf, set);
1015: }
1016: set.addAll(objectsToAdd);
1017: }
1018:
1019: public boolean hasProblem() {
1020: return problem != null;
1021: }
1022:
1023: public Exception getProblem() {
1024: return problem;
1025: }
1026:
1027: public String getProblemMessage() {
1028: return StringUtils.getErrorMessage(problem);
1029: }
1030:
1031: public boolean isDownloaded() {
1032: return downloaded;
1033: }
1034:
1035: public boolean isSearched() {
1036: return searched;
1037: }
1038:
1039: public boolean isLoaded() {
1040: return md != null;
1041: }
1042:
1043: public boolean isFetched(String conf) {
1044: return fetchedConfigurations.contains(conf);
1045: }
1046:
1047: public IvyNode findNode(ModuleRevisionId mrid) {
1048: return data.getNode(mrid);
1049: }
1050:
1051: boolean isRoot() {
1052: return root == this ;
1053: }
1054:
1055: public IvyNode getRoot() {
1056: return root;
1057: }
1058:
1059: public ConflictManager getConflictManager(ModuleId mid) {
1060: if (md == null) {
1061: throw new IllegalStateException(
1062: "impossible to get conflict manager when data has not been loaded. IvyNode = "
1063: + this .toString());
1064: }
1065: ConflictManager cm = md.getConflictManager(mid);
1066: return cm == null ? settings.getConflictManager(mid) : cm;
1067: }
1068:
1069: public IvyNode getRealNode() {
1070: IvyNode real = data.getNode(getId());
1071: return real != null ? real : this ;
1072: }
1073:
1074: public ModuleRevisionId getId() {
1075: return id;
1076: }
1077:
1078: public ModuleId getModuleId() {
1079: return id.getModuleId();
1080: }
1081:
1082: public ModuleDescriptor getDescriptor() {
1083: return md;
1084: }
1085:
1086: public ResolveData getData() {
1087: return data;
1088: }
1089:
1090: public ResolvedModuleRevision getModuleRevision() {
1091: return module;
1092: }
1093:
1094: public long getPublication() {
1095: if (module != null) {
1096: return module.getPublicationDate().getTime();
1097: }
1098: return 0;
1099: }
1100:
1101: /**
1102: * Returns the last modified timestamp of the module represented by this Node, or 0 if the last
1103: * modified timestamp is currently unkwown (module not loaded)
1104: *
1105: * @return the last modified timestamp of the module represented by this Node
1106: */
1107: public long getLastModified() {
1108: if (md != null) {
1109: return md.getLastModified();
1110: }
1111: return 0;
1112: }
1113:
1114: public ModuleRevisionId getResolvedId() {
1115: if (md != null
1116: && md.getResolvedModuleRevisionId().getRevision() != null) {
1117: return md.getResolvedModuleRevisionId();
1118: } else if (module != null) {
1119: return module.getId();
1120: } else {
1121: return getId();
1122: }
1123: }
1124:
1125: /**
1126: * Clean data related to one root module configuration only
1127: */
1128: public void clean() {
1129: confsToFetch.clear();
1130: }
1131:
1132: // /////////////////////////////////////////////////////////////////////////////
1133: // CALLERS MANAGEMENT
1134: // /////////////////////////////////////////////////////////////////////////////
1135:
1136: boolean canExclude(String rootModuleConf) {
1137: Caller[] callers = getCallers(rootModuleConf);
1138: for (int i = 0; i < callers.length; i++) {
1139: if (callers[i].canExclude()) {
1140: return true;
1141: }
1142: }
1143: return false;
1144: }
1145:
1146: private IvyNode getDirectCallerFor(ModuleId from) {
1147: return callers.getDirectCallerFor(from);
1148: }
1149:
1150: public Caller[] getCallers(String rootModuleConf) {
1151: return callers.getCallers(rootModuleConf);
1152: }
1153:
1154: public Collection getAllCallersModuleIds() {
1155: return callers.getAllCallersModuleIds();
1156: }
1157:
1158: public Caller[] getAllCallers() {
1159: return callers.getAllCallers();
1160: }
1161:
1162: public Caller[] getAllRealCallers() {
1163: return callers.getAllRealCallers();
1164: }
1165:
1166: public void addCaller(String rootModuleConf, IvyNode callerNode,
1167: String callerConf, String[] dependencyConfs,
1168: DependencyDescriptor dd) {
1169: callers.addCaller(rootModuleConf, callerNode, callerConf,
1170: dependencyConfs, dd);
1171: boolean isCircular = callers.getAllCallersModuleIds().contains(
1172: getId().getModuleId());
1173: if (isCircular) {
1174: IvyContext.getContext().getCircularDependencyStrategy()
1175: .handleCircularDependency(
1176: toMrids(findPath(getId().getModuleId()),
1177: this ));
1178: }
1179: }
1180:
1181: public boolean doesCallersExclude(String rootModuleConf,
1182: Artifact artifact, Stack callersStack) {
1183: return callers.doesCallersExclude(rootModuleConf, artifact,
1184: callersStack);
1185: }
1186:
1187: private ModuleRevisionId[] toMrids(Collection path, IvyNode depNode) {
1188: ModuleRevisionId[] ret = new ModuleRevisionId[path.size() + 1];
1189: int i = 0;
1190: for (Iterator iter = path.iterator(); iter.hasNext(); i++) {
1191: IvyNode node = (IvyNode) iter.next();
1192: ret[i] = node.getId();
1193: }
1194: ret[ret.length - 1] = depNode.getId();
1195: return ret;
1196: }
1197:
1198: // /////////////////////////////////////////////////////////////////////////////
1199: // EVICTION MANAGEMENT
1200: // /////////////////////////////////////////////////////////////////////////////
1201:
1202: public Collection getResolvedNodes(ModuleId moduleId,
1203: String rootModuleConf) {
1204: return eviction.getResolvedNodes(moduleId, rootModuleConf);
1205: }
1206:
1207: public Collection getResolvedRevisions(ModuleId moduleId,
1208: String rootModuleConf) {
1209: return eviction.getResolvedRevisions(moduleId, rootModuleConf);
1210: }
1211:
1212: public void markEvicted(EvictionData evictionData) {
1213: eviction.markEvicted(evictionData);
1214: if (!rootModuleConfs.keySet().contains(
1215: evictionData.getRootModuleConf())) {
1216: rootModuleConfs.put(evictionData.getRootModuleConf(), null);
1217: }
1218:
1219: // bug 105: update selected data with evicted one
1220: if (evictionData.getSelected() != null) {
1221: for (Iterator iter = evictionData.getSelected().iterator(); iter
1222: .hasNext();) {
1223: IvyNode selected = (IvyNode) iter.next();
1224: selected.updateDataFrom(this , evictionData
1225: .getRootModuleConf(), false);
1226: }
1227: }
1228: }
1229:
1230: public Collection getAllEvictingConflictManagers() {
1231: return eviction.getAllEvictingConflictManagers();
1232: }
1233:
1234: public Collection getAllEvictingNodes() {
1235: return eviction.getAllEvictingNodes();
1236: }
1237:
1238: public Collection/*<String>*/getAllEvictingNodesDetails() {
1239: return eviction.getAllEvictingNodesDetails();
1240: }
1241:
1242: public String[] getEvictedConfs() {
1243: return eviction.getEvictedConfs();
1244: }
1245:
1246: public EvictionData getEvictedData(String rootModuleConf) {
1247: return eviction.getEvictedData(rootModuleConf);
1248: }
1249:
1250: public Collection getEvictedNodes(ModuleId mid,
1251: String rootModuleConf) {
1252: return eviction.getEvictedNodes(mid, rootModuleConf);
1253: }
1254:
1255: public Collection getEvictedRevisions(ModuleId mid,
1256: String rootModuleConf) {
1257: return eviction.getEvictedRevisions(mid, rootModuleConf);
1258: }
1259:
1260: public EvictionData getEvictionDataInRoot(String rootModuleConf,
1261: IvyNode ancestor) {
1262: return eviction.getEvictionDataInRoot(rootModuleConf, ancestor);
1263: }
1264:
1265: public boolean isCompletelyEvicted() {
1266: return eviction.isCompletelyEvicted();
1267: }
1268:
1269: public boolean isEvicted(String rootModuleConf) {
1270: return eviction.isEvicted(rootModuleConf);
1271: }
1272:
1273: public void markEvicted(String rootModuleConf, IvyNode node,
1274: ConflictManager conflictManager, Collection resolved) {
1275: EvictionData evictionData = new EvictionData(rootModuleConf,
1276: node, conflictManager, resolved);
1277: markEvicted(evictionData);
1278: }
1279:
1280: public void setEvictedNodes(ModuleId moduleId,
1281: String rootModuleConf, Collection evicted) {
1282: eviction.setEvictedNodes(moduleId, rootModuleConf, evicted);
1283: }
1284:
1285: public void setResolvedNodes(ModuleId moduleId,
1286: String rootModuleConf, Collection resolved) {
1287: eviction.setResolvedNodes(moduleId, rootModuleConf, resolved);
1288: }
1289:
1290: public String toString() {
1291: return getResolvedId().toString();
1292: }
1293:
1294: public boolean equals(Object obj) {
1295: if (!(obj instanceof IvyNode)) {
1296: return false;
1297: }
1298: IvyNode node = (IvyNode) obj;
1299: return node.getId().equals(getId());
1300: }
1301:
1302: public int compareTo(Object obj) {
1303: IvyNode that = (IvyNode) obj;
1304: return this .getModuleId().compareTo(that.getModuleId());
1305: }
1306:
1307: public int hashCode() {
1308: return getId().hashCode();
1309: }
1310:
1311: /**
1312: * Returns a collection of Nodes in conflict for which conflict has been detected but conflict
1313: * resolution hasn't been done yet
1314: *
1315: * @param rootModuleConf
1316: * @param mid
1317: * the module id for which pending conflicts should be found
1318: * @return a Collection of IvyNode in pending conflict
1319: */
1320: public Collection getPendingConflicts(String rootModuleConf,
1321: ModuleId mid) {
1322: return eviction.getPendingConflicts(rootModuleConf, mid);
1323: }
1324:
1325: public void setPendingConflicts(ModuleId moduleId,
1326: String rootModuleConf, Collection conflicts) {
1327: eviction.setPendingConflicts(moduleId, rootModuleConf,
1328: conflicts);
1329: }
1330:
1331: // /////////////////////////////////////////////////////////////////////////////
1332: // BLACKLISTING MANAGEMENT
1333: // /////////////////////////////////////////////////////////////////////////////
1334:
1335: /**
1336: * Blacklists the current node, so that a new resolve process won't ever consider this node as
1337: * available in the repository.
1338: * <p>
1339: * This is useful in combination with {@link RestartResolveProcess} for conflict manager
1340: * implementation which use a best effort strategy to find compatible dependency set, like
1341: * {@link LatestCompatibleConflictManager}
1342: * </p>
1343: *
1344: * @param rootModuleConf the root module configuration in which the node should be blacklisted
1345: */
1346: public void blacklist(IvyNodeBlacklist bdata) {
1347: if (data.getSettings().logResolvedRevision()) {
1348: Message.info("BLACKLISTING " + bdata);
1349: } else {
1350: Message.verbose("BLACKLISTING " + bdata);
1351: }
1352:
1353: Stack callerStack = new Stack();
1354: callerStack.push(this );
1355: clearEvictionDataInAllCallers(bdata.getRootModuleConf(),
1356: callerStack);
1357:
1358: blacklisted.put(bdata.getRootModuleConf(), bdata);
1359: data.blacklist(this );
1360: }
1361:
1362: private void clearEvictionDataInAllCallers(String rootModuleConf,
1363: Stack/*<IvyNode>*/callerStack) {
1364: IvyNode node = (IvyNode) callerStack.peek();
1365: Caller[] callers = node.getCallers(rootModuleConf);
1366: for (int i = 0; i < callers.length; i++) {
1367: IvyNode callerNode = findNode(callers[i]
1368: .getModuleRevisionId());
1369: if (callerNode != null) {
1370: callerNode.eviction = new IvyNodeEviction(callerNode);
1371: if (!callerStack.contains(callerNode)) {
1372: callerStack.push(callerNode);
1373: clearEvictionDataInAllCallers(rootModuleConf,
1374: callerStack);
1375: callerStack.pop();
1376: }
1377: }
1378: }
1379: }
1380:
1381: /**
1382: * Indicates if this node has been blacklisted in the given root module conf.
1383: * <p>
1384: * A blacklisted node should be considered as if it doesn't even exist on the repository.
1385: * </p>
1386: *
1387: * @param rootModuleConf
1388: * the root module conf for which we'd like to know if the node is blacklisted
1389: *
1390: * @return true if this node is blacklisted int he given root module conf, false otherwise
1391: * @see #blacklist(String)
1392: */
1393: public boolean isBlacklisted(String rootModuleConf) {
1394: return blacklisted.containsKey(rootModuleConf);
1395: }
1396:
1397: /**
1398: * Indicates if this node has been blacklisted in all root module configurations.
1399: *
1400: * @return true if this node is blacklisted in all root module configurations, false otherwise
1401: * @see #blacklist(String)
1402: */
1403: public boolean isCompletelyBlacklisted() {
1404: if (isRoot()) {
1405: return false;
1406: }
1407: String[] rootModuleConfigurations = getRootModuleConfigurations();
1408: for (int i = 0; i < rootModuleConfigurations.length; i++) {
1409: if (!isBlacklisted(rootModuleConfigurations[i])) {
1410: return false;
1411: }
1412: }
1413: return true;
1414: }
1415:
1416: /**
1417: * Returns the blacklist data of this node in the given root module conf, or <code>null</code>
1418: * if this node is not blacklisted in this root module conf.
1419: *
1420: * @param rootModuleConf
1421: * the root module configuration to consider
1422: * @return the blacklist data if any
1423: */
1424: public IvyNodeBlacklist getBlacklistData(String rootModuleConf) {
1425: return (IvyNodeBlacklist) blacklisted.get(rootModuleConf);
1426: }
1427:
1428: }
|