001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.plugins.report;
019:
020: import java.io.File;
021: import java.text.ParseException;
022: import java.util.ArrayList;
023: import java.util.Date;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.SortedMap;
029: import java.util.TreeMap;
030:
031: import javax.xml.parsers.SAXParser;
032: import javax.xml.parsers.SAXParserFactory;
033:
034: import org.apache.ivy.Ivy;
035: import org.apache.ivy.core.cache.ArtifactOrigin;
036: import org.apache.ivy.core.module.descriptor.Artifact;
037: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
038: import org.apache.ivy.core.module.id.ModuleRevisionId;
039: import org.apache.ivy.core.report.ArtifactDownloadReport;
040: import org.apache.ivy.core.report.DownloadStatus;
041: import org.apache.ivy.core.report.MetadataArtifactDownloadReport;
042: import org.apache.ivy.util.extendable.ExtendableItemHelper;
043: import org.xml.sax.Attributes;
044: import org.xml.sax.SAXException;
045: import org.xml.sax.helpers.DefaultHandler;
046:
047: public class XmlReportParser {
048: private static class SaxXmlReportParser {
049: private List/*<ModuleRevisionId>*/mrids;
050:
051: private List/*<ModuleRevisionId>*/defaultMrids;
052:
053: private List/*<ModuleRevisionId>*/realMrids;
054:
055: private List/*<Artifact>*/artifacts;
056:
057: private List/*<ArtifactDownloadReport>*/artifactReports;
058:
059: private Map/*<ModuleRevisionId,MetadataArtifactDownloadReport>*/metadataReports;
060:
061: private ModuleRevisionId mRevisionId;
062:
063: private File report;
064:
065: SaxXmlReportParser(File report) {
066: artifacts = new ArrayList();
067: artifactReports = new ArrayList();
068: mrids = new ArrayList();
069: defaultMrids = new ArrayList();
070: realMrids = new ArrayList();
071: metadataReports = new HashMap();
072: this .report = report;
073: }
074:
075: public void parse() throws Exception {
076: SAXParser saxParser = SAXParserFactory.newInstance()
077: .newSAXParser();
078: saxParser.parse(report, new DefaultHandler() {
079: private String organisation;
080:
081: private String module;
082:
083: private String branch;
084:
085: private String revision;
086:
087: private int position;
088:
089: private Date pubdate;
090:
091: private boolean skip;
092:
093: private ModuleRevisionId mrid;
094:
095: private boolean isDefault;
096:
097: private SortedMap revisionsMap = new TreeMap(); // Use a TreeMap to order by
098:
099: // position (position = key)
100:
101: private List revisionArtifacts = null;
102:
103: public void startElement(String uri, String localName,
104: String qName, Attributes attributes)
105: throws SAXException {
106: if ("module".equals(qName)) {
107: organisation = attributes
108: .getValue("organisation");
109: module = attributes.getValue("name");
110: } else if ("revision".equals(qName)) {
111: revisionArtifacts = new ArrayList();
112: branch = attributes.getValue("branch");
113: revision = attributes.getValue("name");
114: isDefault = Boolean.valueOf(
115: attributes.getValue("default"))
116: .booleanValue();
117: // retrieve position from file. If no position is found, it may be an old
118: // report generated with a previous version,
119: // in which case, we put it at the last position
120: String pos = attributes.getValue("position");
121: position = pos == null ? getMaxPos() + 1
122: : Integer.valueOf(pos).intValue();
123: if (attributes.getValue("error") != null
124: || attributes.getValue("evicted") != null) {
125: skip = true;
126: } else {
127: revisionsMap.put(new Integer(position),
128: revisionArtifacts);
129: mrid = ModuleRevisionId.newInstance(
130: organisation, module, branch,
131: revision, ExtendableItemHelper
132: .getExtraAttributes(
133: attributes,
134: "extra-"));
135: mrids.add(mrid);
136: if (isDefault) {
137: defaultMrids.add(mrid);
138: } else {
139: Artifact metadataArtifact = DefaultArtifact
140: .newIvyArtifact(mrid, pubdate);
141: MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport(
142: metadataArtifact);
143: metadataReports.put(mrid, madr);
144: realMrids.add(mrid);
145: }
146: try {
147: pubdate = Ivy.DATE_FORMAT
148: .parse(attributes
149: .getValue("pubdate"));
150: skip = false;
151: } catch (ParseException e) {
152: throw new IllegalArgumentException(
153: "invalid publication date for "
154: + organisation
155: + " "
156: + module
157: + " "
158: + revision
159: + ": "
160: + attributes
161: .getValue("pubdate"));
162: }
163: }
164: } else if ("metadata-artifact".equals(qName)) {
165: if (skip) {
166: return;
167: }
168: MetadataArtifactDownloadReport madr = (MetadataArtifactDownloadReport) metadataReports
169: .get(mrid);
170: if (madr != null) {
171: madr.setDownloadStatus(DownloadStatus
172: .fromString(attributes
173: .getValue("status")));
174: madr.setDownloadDetails(attributes
175: .getValue("details"));
176: madr.setSize(Long.parseLong(attributes
177: .getValue("size")));
178: madr.setDownloadTimeMillis(Long
179: .parseLong(attributes
180: .getValue("time")));
181: madr.setSearched(parseBoolean(attributes
182: .getValue("searched")));
183: if (attributes.getValue("location") != null) {
184: madr.setLocalFile(new File(attributes
185: .getValue("location")));
186: }
187: if (attributes
188: .getValue("original-local-location") != null) {
189: madr
190: .setOriginalLocalFile(new File(
191: attributes
192: .getValue("original-local-location")));
193: }
194: if (attributes.getValue("origin-location") != null) {
195: if (ArtifactOrigin.UNKNOWN
196: .getLocation()
197: .equals(
198: attributes
199: .getValue("origin-location"))) {
200: madr
201: .setArtifactOrigin(ArtifactOrigin.UNKNOWN);
202: } else {
203: madr
204: .setArtifactOrigin(new ArtifactOrigin(
205: parseBoolean(attributes
206: .getValue("origin-is-local")),
207: attributes
208: .getValue("origin-location")));
209: }
210: }
211: }
212: } else if ("artifact".equals(qName)) {
213: if (skip) {
214: return;
215: }
216: String status = attributes.getValue("status");
217: String artifactName = attributes
218: .getValue("name");
219: String type = attributes.getValue("type");
220: String ext = attributes.getValue("ext");
221: Artifact artifact = new DefaultArtifact(mrid,
222: pubdate, artifactName, type, ext,
223: ExtendableItemHelper
224: .getExtraAttributes(attributes,
225: "extra-"));
226: ArtifactDownloadReport aReport = new ArtifactDownloadReport(
227: artifact);
228: aReport.setDownloadStatus(DownloadStatus
229: .fromString(status));
230: aReport.setDownloadDetails(attributes
231: .getValue("details"));
232: aReport.setSize(Long.parseLong(attributes
233: .getValue("size")));
234: aReport
235: .setDownloadTimeMillis(Long
236: .parseLong(attributes
237: .getValue("time")));
238: if (attributes.getValue("location") != null) {
239: aReport.setLocalFile(new File(attributes
240: .getValue("location")));
241: }
242: revisionArtifacts.add(aReport);
243: } else if ("origin-location".equals(qName)) {
244: if (skip) {
245: return;
246: }
247: ArtifactDownloadReport aReport = (ArtifactDownloadReport) revisionArtifacts
248: .get(revisionArtifacts.size() - 1);
249:
250: if (ArtifactOrigin.UNKNOWN
251: .getLocation()
252: .equals(attributes.getValue("location"))) {
253: aReport
254: .setArtifactOrigin(ArtifactOrigin.UNKNOWN);
255: } else {
256: aReport
257: .setArtifactOrigin(new ArtifactOrigin(
258: parseBoolean(attributes
259: .getValue("is-local")),
260: attributes
261: .getValue("location")));
262: }
263: } else if ("info".equals(qName)) {
264: String organisation = attributes
265: .getValue("organisation");
266: String name = attributes.getValue("module");
267: String branch = attributes.getValue("branch");
268: String revision = attributes
269: .getValue("revision");
270: Map extraAttributes = new HashMap();
271: for (int i = 0; i < attributes.getLength(); i++) {
272: String attName = attributes.getQName(i);
273: if (attName.startsWith("extra-")) {
274: String extraAttrName = attName
275: .substring("extra-".length());
276: String extraAttrValue = attributes
277: .getValue(i);
278: extraAttributes.put(extraAttrName,
279: extraAttrValue);
280: }
281: }
282: mRevisionId = ModuleRevisionId.newInstance(
283: organisation, name, branch, revision,
284: extraAttributes);
285: }
286: }
287:
288: public void endElement(String uri, String localName,
289: String qname) throws SAXException {
290: if ("dependencies".equals(qname)) {
291: // add the artifacts in the correct order
292: for (Iterator it = revisionsMap.values()
293: .iterator(); it.hasNext();) {
294: List artifactReports = (List) it.next();
295: SaxXmlReportParser.this .artifactReports
296: .addAll(artifactReports);
297: for (Iterator iter = artifactReports
298: .iterator(); iter.hasNext();) {
299: ArtifactDownloadReport artifactReport = (ArtifactDownloadReport) iter
300: .next();
301: if (artifactReport.getDownloadStatus() != DownloadStatus.FAILED) {
302: artifacts.add(artifactReport
303: .getArtifact());
304: }
305: }
306:
307: }
308: }
309: }
310:
311: private int getMaxPos() {
312: return revisionsMap.isEmpty() ? -1
313: : ((Integer) revisionsMap.keySet()
314: .toArray()[revisionsMap.size() - 1])
315: .intValue();
316: }
317: });
318: }
319:
320: private static boolean parseBoolean(String str) {
321: return (str != null) && str.equalsIgnoreCase("true");
322: }
323:
324: public List getArtifacts() {
325: return artifacts;
326: }
327:
328: public List getArtifactReports() {
329: return artifactReports;
330: }
331:
332: public List getModuleRevisionIds() {
333: return mrids;
334: }
335:
336: public List getRealModuleRevisionIds() {
337: return realMrids;
338: }
339:
340: public ModuleRevisionId getResolvedModule() {
341: return mRevisionId;
342: }
343:
344: public MetadataArtifactDownloadReport getMetadataArtifactReport(
345: ModuleRevisionId id) {
346: return (MetadataArtifactDownloadReport) metadataReports
347: .get(id);
348: }
349: }
350:
351: private SaxXmlReportParser parser = null;
352:
353: public void parse(File report) throws ParseException {
354: if (!report.exists()) {
355: throw new IllegalStateException("Report file '"
356: + report.getAbsolutePath() + "' does not exist.");
357: }
358:
359: parser = new SaxXmlReportParser(report);
360: try {
361: parser.parse();
362: } catch (Exception e) {
363: ParseException pe = new ParseException(
364: "failed to parse report: " + report + ": "
365: + e.getMessage(), 0);
366: pe.initCause(e);
367: throw pe;
368: }
369: }
370:
371: public Artifact[] getArtifacts() {
372: return (Artifact[]) parser.getArtifacts().toArray(
373: new Artifact[parser.getArtifacts().size()]);
374: }
375:
376: public ArtifactDownloadReport[] getArtifactReports() {
377: return (ArtifactDownloadReport[]) parser.getArtifactReports()
378: .toArray(
379: new ArtifactDownloadReport[parser
380: .getArtifactReports().size()]);
381: }
382:
383: public ModuleRevisionId[] getDependencyRevisionIds() {
384: return (ModuleRevisionId[]) parser.getModuleRevisionIds()
385: .toArray(
386: new ModuleRevisionId[parser
387: .getModuleRevisionIds().size()]);
388: }
389:
390: public ModuleRevisionId[] getRealDependencyRevisionIds() {
391: return (ModuleRevisionId[]) parser.getRealModuleRevisionIds()
392: .toArray(
393: new ModuleRevisionId[parser
394: .getRealModuleRevisionIds().size()]);
395: }
396:
397: public MetadataArtifactDownloadReport getMetadataArtifactReport(
398: ModuleRevisionId id) {
399: return parser.getMetadataArtifactReport(id);
400: }
401:
402: /**
403: * Returns the <tt>ModuleRevisionId</tt> of the resolved module.
404: */
405: public ModuleRevisionId getResolvedModule() {
406: return parser.getResolvedModule();
407: }
408: }
|