/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.report.ReportOutputter; import org.apache.ivy.util.filter.Filter; /** * Represents a whole resolution report for a module */ public class ResolveReport { private ModuleDescriptor md; private Map<String, ConfigurationResolveReport> confReports = new LinkedHashMap<String, ConfigurationResolveReport>(); private List<String> problemMessages = new ArrayList<String>(); /** * the list of all dependencies resolved, ordered from the more dependent to the less dependent */ private List<IvyNode> dependencies = new ArrayList<IvyNode>(); private List<Artifact> artifacts = new ArrayList<Artifact>(); private long resolveTime; private long downloadTime; private String resolveId; private long downloadSize; public ResolveReport(ModuleDescriptor md) { this(md, ResolveOptions.getDefaultResolveId(md)); } public ResolveReport(ModuleDescriptor md, String resolveId) { this.md = md; this.resolveId = resolveId; } public void addReport(String conf, ConfigurationResolveReport report) { confReports.put(conf, report); } public ConfigurationResolveReport getConfigurationReport(String conf) { return confReports.get(conf); } public String[] getConfigurations() { return confReports.keySet().toArray(new String[confReports.size()]); } public boolean hasError() { for (ConfigurationResolveReport report : confReports.values()) { if (report.hasError()) { return true; } } return false; } public void output(ReportOutputter[] outputters, ResolutionCacheManager cacheMgr, ResolveOptions options) throws IOException { for (int i = 0; i < outputters.length; i++) { outputters[i].output(this, cacheMgr, options); } } public ModuleDescriptor getModuleDescriptor() { return md; } public IvyNode[] getEvictedNodes() { Collection<IvyNode> all = new LinkedHashSet<IvyNode>(); for (ConfigurationResolveReport report : confReports.values()) { all.addAll(Arrays.asList(report.getEvictedNodes())); } return all.toArray(new IvyNode[all.size()]); } public IvyNode[] getUnresolvedDependencies() { Collection<IvyNode> all = new LinkedHashSet<IvyNode>(); for (ConfigurationResolveReport report : confReports.values()) { all.addAll(Arrays.asList(report.getUnresolvedDependencies())); } return all.toArray(new IvyNode[all.size()]); } /** * Get every report on the download requests. * * @return the list of reports, never <code>null</code> */ public ArtifactDownloadReport[] getFailedArtifactsReports() { return ConfigurationResolveReport.filterOutMergedArtifacts(getArtifactsReports( DownloadStatus.FAILED, true)); } /** * Get every report on the download requests. * * @return the list of reports, never <code>null</code> */ public ArtifactDownloadReport[] getAllArtifactsReports() { return getArtifactsReports(null, true); } /** * Get the report on the download requests. The list of download report can be restricted to a * specific download status, and also remove the download report for the evicted modules. * * @param downloadStatus * the status of download to retreive. Set it to <code>null</code> for no restriction * on the download status * @param withEvicted * set it to <code>true</code> if the report for the evicted modules have to be * retrieved, <code>false</code> to exclude reports from modules evicted in all * configurations. * @return the list of reports, never <code>null</code> * @see ConfigurationResolveReport#getArtifactsReports(DownloadStatus, boolean) */ public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus downloadStatus, boolean withEvicted) { Collection<ArtifactDownloadReport> all = new LinkedHashSet<ArtifactDownloadReport>(); for (ConfigurationResolveReport report : confReports.values()) { ArtifactDownloadReport[] reports = report.getArtifactsReports(downloadStatus, withEvicted); all.addAll(Arrays.asList(reports)); } return all.toArray(new ArtifactDownloadReport[all.size()]); } public ArtifactDownloadReport[] getArtifactsReports(ModuleRevisionId mrid) { Collection<ArtifactDownloadReport> all = new LinkedHashSet<ArtifactDownloadReport>(); for (ConfigurationResolveReport report : confReports.values()) { all.addAll(Arrays.asList(report.getDownloadReports(mrid))); } return all.toArray(new ArtifactDownloadReport[all.size()]); } public void checkIfChanged() { for (ConfigurationResolveReport report : confReports.values()) { report.checkIfChanged(); } } /** Can only be called if checkIfChanged has been called */ public boolean hasChanged() { for (ConfigurationResolveReport report : confReports.values()) { if (report.hasChanged()) { return true; } } return false; } public void setProblemMessages(List<String> problems) { problemMessages = problems; } public List<String> getProblemMessages() { return problemMessages; } public List<String> getAllProblemMessages() { List<String> ret = new ArrayList<String>(problemMessages); for (ConfigurationResolveReport r : confReports.values()) { IvyNode[] unresolved = r.getUnresolvedDependencies(); for (int i = 0; i < unresolved.length; i++) { String errMsg = unresolved[i].getProblemMessage(); if (errMsg.length() > 0) { ret.add("unresolved dependency: " + unresolved[i].getId() + ": " + errMsg); } else { ret.add("unresolved dependency: " + unresolved[i].getId()); } } ArtifactDownloadReport[] adrs = r.getFailedArtifactsReports(); for (int i = 0; i < adrs.length; i++) { ret.add("download failed: " + adrs[i].getArtifact()); } } return ret; } public void setDependencies(List<IvyNode> dependencies, Filter<Artifact> artifactFilter) { this.dependencies = dependencies; // collect list of artifacts artifacts = new ArrayList<Artifact>(); for (IvyNode dependency : dependencies) { if (!dependency.isCompletelyEvicted() && !dependency.hasProblem()) { artifacts.addAll(Arrays.asList(dependency.getSelectedArtifacts(artifactFilter))); } // update the configurations reports with the dependencies // these reports will be completed later with download information, if any String[] dconfs = dependency.getRootModuleConfigurations(); for (int j = 0; j < dconfs.length; j++) { ConfigurationResolveReport configurationReport = getConfigurationReport(dconfs[j]); if (configurationReport != null) { configurationReport.addDependency(dependency); } } } } /** * Returns the list of all dependencies concerned by this report as a List of IvyNode ordered * from the more dependent to the least one * * @return The list of all dependencies. */ public List<IvyNode> getDependencies() { return dependencies; } /** * Returns the list of all artifacts which should be downloaded per this resolve To know if the * artifact have actually been downloaded use information found in ConfigurationResolveReport. * * @return The list of all artifacts. */ public List<Artifact> getArtifacts() { return artifacts; } /** * gives all the modules ids concerned by this report, from the most dependent to the least one * * @return a list of ModuleId */ public List<ModuleId> getModuleIds() { List<ModuleId> ret = new ArrayList<ModuleId>(); List<IvyNode> sortedDependencies = new ArrayList<IvyNode>(dependencies); for (IvyNode dependency : sortedDependencies) { ModuleId mid = dependency.getResolvedId().getModuleId(); if (!ret.contains(mid)) { ret.add(mid); } } return ret; } public void setResolveTime(long elapsedTime) { resolveTime = elapsedTime; } public long getResolveTime() { return resolveTime; } public void setDownloadTime(long elapsedTime) { downloadTime = elapsedTime; } public long getDownloadTime() { return downloadTime; } public void setDownloadSize(long size) { this.downloadSize = size; } /** * The total size of downloaded artifacts, in bytes. * <p> * This only includes artifacts actually downloaded to cache (DownloadStatus.SUCCESSFUL), and * not artifacts already in cache or used at their original location. * </p> * * @return The total size of downloaded artifacts, in bytes. */ public long getDownloadSize() { return downloadSize; } public String getResolveId() { return resolveId; } /** * Get every configuration which extends the specified one. The returned list also includes the * specified one. * * @param extended * @return */ private String[] getExtendingConfs(String extended) { String[] allConfs = md.getConfigurationsNames(); Set<String> extendingConfs = new HashSet<String>(); extendingConfs.add(extended); for (int i = 0; i < allConfs.length; i++) { gatherExtendingConfs(extendingConfs, allConfs[i], extended); } return extendingConfs.toArray(new String[extendingConfs.size()]); } private boolean gatherExtendingConfs(Set<String> extendingConfs, String conf, String extended) { if (extendingConfs.contains(conf)) { return true; } String[] ext = md.getConfiguration(conf).getExtends(); if (ext == null || ext.length == 0) { return false; } for (int i = 0; i < ext.length; i++) { if (extendingConfs.contains(ext[i])) { extendingConfs.add(conf); return true; } if (ext[i].equals(extended)) { extendingConfs.add(conf); return true; } if (gatherExtendingConfs(extendingConfs, ext[i], extended)) { extendingConfs.add(conf); return true; } } return false; } public ModuleDescriptor toFixedModuleDescriptor(IvySettings settings, List<ModuleId> midToKeep) { DefaultModuleDescriptor fixedmd = new DefaultModuleDescriptor(md.getModuleRevisionId(), md.getStatus(), new Date()); // copy namespaces for (Entry<String, String> ns : md.getExtraAttributesNamespaces().entrySet()) { fixedmd.addExtraAttributeNamespace(ns.getKey(), ns.getValue()); } // copy info fixedmd.setDescription(md.getDescription()); fixedmd.setHomePage(md.getHomePage()); fixedmd.getExtraInfos().addAll(md.getExtraInfos()); // copy configurations List<String> resolvedConfs = Arrays.asList(getConfigurations()); for (String conf : resolvedConfs) { fixedmd.addConfiguration(new Configuration(conf)); } // copy artifacts for (String conf : resolvedConfs) { for (Artifact a : md.getArtifacts(conf)) { fixedmd.addArtifact(conf, a); } } // add resolved dependencies for (IvyNode dep : dependencies) { ModuleRevisionId depMrid; boolean force; if (midToKeep != null && midToKeep.contains(dep.getModuleId())) { depMrid = dep.getId(); force = false; } else { depMrid = dep.getResolvedId(); force = true; } DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(fixedmd, depMrid, force, false, false); boolean evicted = true; for (String rootConf : dep.getRootModuleConfigurations()) { if (dep.isEvicted(rootConf)) { continue; } evicted = false; for (String targetConf : dep.getConfigurations(rootConf)) { dd.addDependencyConfiguration(rootConf, targetConf); } } if (!evicted) { fixedmd.addDependency(dd); } } return fixedmd; } }