blob: b35c4833987b4c9bfbdc8bb7eed0e56e8d26ee47 [file] [log] [blame]
/*
* 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
*
* https://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.plugins.report;
import java.io.File;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.ivy.core.cache.ArtifactOrigin;
import org.apache.ivy.core.module.descriptor.Artifact;
import org.apache.ivy.core.module.descriptor.DefaultArtifact;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.core.report.ArtifactDownloadReport;
import org.apache.ivy.core.report.DownloadStatus;
import org.apache.ivy.core.report.MetadataArtifactDownloadReport;
import org.apache.ivy.util.DateUtil;
import org.apache.ivy.util.extendable.ExtendableItemHelper;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XmlReportParser {
private static class SaxXmlReportParser {
private final class XmlReportParserHandler extends DefaultHandler {
private String organisation;
private String module;
private String branch;
private String revision;
private int position;
private Date pubdate;
private boolean skip;
private ModuleRevisionId mrid;
private boolean isDefault;
// Use a TreeMap to order by
private SortedMap<Integer, List<ArtifactDownloadReport>> revisionsMap = new TreeMap<>();
private List<ArtifactDownloadReport> revisionArtifacts = null;
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
switch (qName) {
case "module":
organisation = attributes.getValue("organisation");
module = attributes.getValue("name");
break;
case "revision":
revisionArtifacts = new ArrayList<>();
branch = attributes.getValue("branch");
revision = attributes.getValue("name");
isDefault = Boolean.valueOf(attributes.getValue("default"));
// retrieve position from file. If no position is found, it may be an old
// report generated with a previous version,
// in which case, we put it at the last position
String pos = attributes.getValue("position");
position = pos == null ? getMaxPos() + 1 : Integer.valueOf(pos);
if (attributes.getValue("error") != null) {
hasError = true;
skip = true;
} else if (attributes.getValue("evicted") != null) {
skip = true;
} else {
revisionsMap.put(position, revisionArtifacts);
mrid = ModuleRevisionId.newInstance(organisation, module, branch, revision,
ExtendableItemHelper.getExtraAttributes(attributes, "extra-"));
mrids.add(mrid);
if (isDefault) {
defaultMrids.add(mrid);
} else {
Artifact metadataArtifact = DefaultArtifact.newIvyArtifact(mrid,
pubdate);
MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport(
metadataArtifact);
metadataReports.put(mrid, madr);
realMrids.add(mrid);
}
try {
String pubDateAttr = attributes.getValue("pubdate");
if (pubDateAttr != null) {
pubdate = DateUtil.parse(pubDateAttr);
}
skip = false;
} catch (ParseException e) {
throw new IllegalArgumentException("invalid publication date for "
+ organisation + " " + module + " " + revision + ": "
+ attributes.getValue("pubdate"));
}
}
break;
case "metadata-artifact":
if (skip) {
return;
}
MetadataArtifactDownloadReport madr = metadataReports.get(mrid);
if (madr != null) {
madr.setDownloadStatus(DownloadStatus.fromString(attributes
.getValue("status")));
madr.setDownloadDetails(attributes.getValue("details"));
madr.setSize(Long.parseLong(attributes.getValue("size")));
madr.setDownloadTimeMillis(Long.parseLong(attributes.getValue("time")));
madr.setSearched(parseBoolean(attributes.getValue("searched")));
if (attributes.getValue("location") != null) {
madr.setLocalFile(new File(attributes.getValue("location")));
}
if (attributes.getValue("original-local-location") != null) {
madr.setOriginalLocalFile(new File(attributes
.getValue("original-local-location")));
}
if (attributes.getValue("origin-location") != null) {
if (ArtifactOrigin.isUnknown(attributes.getValue("origin-location"))) {
madr.setArtifactOrigin(ArtifactOrigin.unknown(madr.getArtifact()));
} else {
madr.setArtifactOrigin(new ArtifactOrigin(madr.getArtifact(),
parseBoolean(attributes.getValue("origin-is-local")),
attributes.getValue("origin-location")));
}
}
}
break;
case "artifact":
if (skip) {
return;
}
String status = attributes.getValue("status");
String artifactName = attributes.getValue("name");
String type = attributes.getValue("type");
String ext = attributes.getValue("ext");
Artifact artifact = new DefaultArtifact(mrid, pubdate, artifactName, type, ext,
ExtendableItemHelper.getExtraAttributes(attributes, "extra-"));
ArtifactDownloadReport aReport = new ArtifactDownloadReport(artifact);
aReport.setDownloadStatus(DownloadStatus.fromString(status));
aReport.setDownloadDetails(attributes.getValue("details"));
aReport.setSize(Long.parseLong(attributes.getValue("size")));
aReport.setDownloadTimeMillis(Long.parseLong(attributes.getValue("time")));
if (attributes.getValue("location") != null) {
aReport.setLocalFile(new File(attributes.getValue("location")));
}
if (attributes.getValue("unpackedFile") != null) {
aReport.setUnpackedLocalFile(new File(attributes.getValue("unpackedFile")));
}
revisionArtifacts.add(aReport);
break;
case "origin-location":
if (skip) {
return;
}
ArtifactDownloadReport adr = revisionArtifacts
.get(revisionArtifacts.size() - 1);
if (ArtifactOrigin.isUnknown(attributes.getValue("location"))) {
adr.setArtifactOrigin(ArtifactOrigin.unknown(adr.getArtifact()));
} else {
adr.setArtifactOrigin(new ArtifactOrigin(adr.getArtifact(),
parseBoolean(attributes.getValue("is-local")),
attributes.getValue("location")));
}
break;
case "info":
String organisation = attributes.getValue("organisation");
String name = attributes.getValue("module");
String branch = attributes.getValue("branch");
String revision = attributes.getValue("revision");
mRevisionId = ModuleRevisionId.newInstance(organisation, name, branch, revision,
ExtendableItemHelper.getExtraAttributes(attributes, "extra-"));
break;
}
}
public void endElement(String uri, String localName, String qname) throws SAXException {
if ("dependencies".equals(qname)) {
// add the artifacts in the correct order
for (List<ArtifactDownloadReport> artifactReports : revisionsMap.values()) {
SaxXmlReportParser.this.artifactReports.addAll(artifactReports);
for (ArtifactDownloadReport artifactReport : artifactReports) {
if (artifactReport.getDownloadStatus() != DownloadStatus.FAILED) {
artifacts.add(artifactReport.getArtifact());
}
}
}
}
}
private int getMaxPos() {
return revisionsMap.isEmpty() ? -1
: (Integer) revisionsMap.keySet().toArray()[revisionsMap.size() - 1];
}
}
private List<ModuleRevisionId> mrids = new ArrayList<>();
private List<ModuleRevisionId> defaultMrids = new ArrayList<>();
private List<ModuleRevisionId> realMrids = new ArrayList<>();
private List<Artifact> artifacts = new ArrayList<>();
private List<ArtifactDownloadReport> artifactReports = new ArrayList<>();
private Map<ModuleRevisionId, MetadataArtifactDownloadReport> metadataReports = new HashMap<>();
private ModuleRevisionId mRevisionId;
private File report;
private boolean hasError = false;
SaxXmlReportParser(File report) {
this.report = report;
}
public void parse() throws Exception {
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
saxParser.parse(report, new XmlReportParserHandler());
}
private static boolean parseBoolean(String str) {
return (str != null) && str.equalsIgnoreCase("true");
}
public List<Artifact> getArtifacts() {
return artifacts;
}
public List<ArtifactDownloadReport> getArtifactReports() {
return artifactReports;
}
public List<ModuleRevisionId> getModuleRevisionIds() {
return mrids;
}
public List<ModuleRevisionId> getRealModuleRevisionIds() {
return realMrids;
}
public ModuleRevisionId getResolvedModule() {
return mRevisionId;
}
public MetadataArtifactDownloadReport getMetadataArtifactReport(ModuleRevisionId id) {
return metadataReports.get(id);
}
}
private SaxXmlReportParser parser = null;
public void parse(File report) throws ParseException {
if (!report.exists()) {
throw new IllegalStateException("Report file '" + report.getAbsolutePath()
+ "' does not exist.");
}
parser = new SaxXmlReportParser(report);
try {
parser.parse();
} catch (Exception e) {
ParseException pe = new ParseException("failed to parse report: " + report + ": "
+ e.getMessage(), 0);
pe.initCause(e);
throw pe;
}
}
public Artifact[] getArtifacts() {
return parser.getArtifacts().toArray(new Artifact[parser.getArtifacts().size()]);
}
public ArtifactDownloadReport[] getArtifactReports() {
return parser.getArtifactReports().toArray(
new ArtifactDownloadReport[parser.getArtifactReports().size()]);
}
public ModuleRevisionId[] getDependencyRevisionIds() {
return parser.getModuleRevisionIds().toArray(
new ModuleRevisionId[parser.getModuleRevisionIds().size()]);
}
public ModuleRevisionId[] getRealDependencyRevisionIds() {
return parser.getRealModuleRevisionIds().toArray(
new ModuleRevisionId[parser.getRealModuleRevisionIds().size()]);
}
public MetadataArtifactDownloadReport getMetadataArtifactReport(ModuleRevisionId id) {
return parser.getMetadataArtifactReport(id);
}
/**
* Returns the <tt>ModuleRevisionId</tt> of the resolved module.
*
* @return ModuleRevisionId
*/
public ModuleRevisionId getResolvedModule() {
return parser.getResolvedModule();
}
public boolean hasError() {
return parser.hasError;
}
}