All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.publicobject.issuesbrowser.IssuezillaXMLParser Maven / Gradle / Ivy

/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package com.publicobject.issuesbrowser;

import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.matchers.Matchers;

import com.publicobject.misc.xml.*;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * Parses IssueZilla issues as described by their XML.
 *
 * 

Parsing supports DTD revision 1.2 only and may not work with prior or * later versions of the IssueZilla XML format. * * @author Jesse Wilson * @author James Lemieux * @see Issuezilla DTD */ public class IssuezillaXMLParser { /** the date format for "issue_when" is documented in the DTD to be 'yyyy-MM-dd HH:mm' but is actually 'yyyy-MM-dd HH:mm:ss' */ /** the date format for "delta_ts" is documented in the DTD to be 'yyyy-MM-dd HH:mm' but is actually 'yyyyMMddHHmmss' */ private static final DateFormat[] dateFormats = {new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), new SimpleDateFormat("yyyyMMddHHmmss")}; // hardcode the servers in California static { final TimeZone laTimeZone = TimeZone.getTimeZone("America/Los_Angeles"); for (int i = 0; i < dateFormats.length; i++) dateFormats[i].setTimeZone(laTimeZone); } private static Parser createParser(Project project) { final Parser issueParser = new Parser(); // configure the Parser for Issues // Parsing instructions for Issue final XMLTagPath issueTag = new XMLTagPath("issuezilla").child("issue"); issueParser.addProcessor(issueTag.start(), Processors.createNewObject(Issue.class, new Class[] {Project.class}, new Object[] {project})); issueParser.addProcessor(issueTag.attribute("status_code"), Processors.setterMethod(Issue.class, "statusCode", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("issue_id"), Processors.setterMethod(Issue.class, "id", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("issue_status"), Processors.setterMethod(Issue.class, "status", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("priority"), Processors.setterMethod(Issue.class, "priority", new PriorityConverter())); issueParser.addProcessor(issueTag.child("resolution"), Processors.setterMethod(Issue.class, "resolution", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("component"), Processors.setterMethod(Issue.class, "component", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("version"), Processors.setterMethod(Issue.class, "version", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("rep_platform"), Processors.setterMethod(Issue.class, "repPlatform", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("assigned_to"), Processors.setterMethod(Issue.class, "assignedTo", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("delta_ts"), Processors.setterMethod(Issue.class, "deltaTimestamp", Converters.date(dateFormats))); issueParser.addProcessor(issueTag.child("subcomponent"), Processors.setterMethod(Issue.class, "subcomponent", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("reporter"), Processors.setterMethod(Issue.class, "reporter", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("target_milestone"), Processors.setterMethod(Issue.class, "targetMilestone", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("issue_type"), Processors.setterMethod(Issue.class, "issueType", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("creation_ts"), Processors.setterMethod(Issue.class, "creationTimestamp", Converters.date(dateFormats))); issueParser.addProcessor(issueTag.child("qa_contact"), Processors.setterMethod(Issue.class, "qAContact", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("status_whiteboard"), Processors.setterMethod(Issue.class, "statusWhiteboard", Converters.trim())); issueParser.addProcessor(issueTag.child("issue_file_loc"), Processors.setterMethod(Issue.class, "fileLocation", Converters.trim())); issueParser.addProcessor(issueTag.child("votes"), Processors.setterMethod(Issue.class, "votes", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("op_sys"), Processors.setterMethod(Issue.class, "operatingSystem", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("short_desc"), Processors.setterMethod(Issue.class, "shortDescription", Converters.trimAndIntern())); issueParser.addProcessor(issueTag.child("keywords"), Processors.addToCollection(Issue.class, "keywords", Converters.trimAndIntern(), Matchers.nonNullAndNonEmptyString())); issueParser.addProcessor(issueTag.child("cc"), Processors.addToCollection(Issue.class, "cC", Converters.trimAndIntern(), Matchers.nonNullAndNonEmptyString())); issueParser.addProcessor(issueTag.end(), new AddIssueToTargetListProcessor()); // Parsing instructions for Description final XMLTagPath descriptionTag = issueTag.child("long_desc"); issueParser.addProcessor(descriptionTag.start(), Processors.createNewObject(Description.class)); issueParser.addProcessor(descriptionTag.child("who"), Processors.setterMethod(Description.class, "who", Converters.trimAndIntern())); issueParser.addProcessor(descriptionTag.child("issue_when"), Processors.setterMethod(Description.class, "when", Converters.date(dateFormats))); issueParser.addProcessor(descriptionTag.child("thetext"), Processors.setterMethod(Description.class, "text", Converters.trim())); issueParser.addProcessor(descriptionTag.end(), Processors.addToCollection(Issue.class, "descriptions")); // Parsing instructions for Activity final XMLTagPath activityTag = issueTag.child("activity"); issueParser.addProcessor(activityTag.start(), Processors.createNewObject(Activity.class)); issueParser.addProcessor(activityTag.child("user"), Processors.setterMethod(Activity.class, "user", Converters.trimAndIntern())); issueParser.addProcessor(activityTag.child("when"), Processors.setterMethod(Activity.class, "when", Converters.date(dateFormats))); issueParser.addProcessor(activityTag.child("field_name"), Processors.setterMethod(Activity.class, "field", Converters.trimAndIntern())); issueParser.addProcessor(activityTag.child("field_desc"), Processors.setterMethod(Activity.class, "fieldDescription", Converters.trimAndIntern())); issueParser.addProcessor(activityTag.child("oldvalue"), Processors.setterMethod(Activity.class, "oldValue", Converters.trimAndIntern())); issueParser.addProcessor(activityTag.child("newvalue"), Processors.setterMethod(Activity.class, "newValue", Converters.trimAndIntern())); issueParser.addProcessor(activityTag.end(), Processors.addToCollection(Issue.class, "activities")); // Parsing instructions for Attachment final XMLTagPath attachmentTag = issueTag.child("attachment"); issueParser.addProcessor(attachmentTag.start(), Processors.createNewObject(Attachment.class)); issueParser.addProcessor(attachmentTag.child("mimetype"), Processors.setterMethod(Attachment.class, "mimeType", Converters.trimAndIntern())); issueParser.addProcessor(attachmentTag.child("attachid"), Processors.setterMethod(Attachment.class, "attachId", Converters.trimAndIntern())); issueParser.addProcessor(attachmentTag.child("date"), Processors.setterMethod(Attachment.class, "date", Converters.date(dateFormats))); issueParser.addProcessor(attachmentTag.child("desc"), Processors.setterMethod(Attachment.class, "description", Converters.trim())); issueParser.addProcessor(attachmentTag.child("ispatch"), Processors.setterMethod(Attachment.class, "isPatch", Converters.trim())); issueParser.addProcessor(attachmentTag.child("filename"), Processors.setterMethod(Attachment.class, "filename", Converters.trim())); issueParser.addProcessor(attachmentTag.child("submitter_id"), Processors.setterMethod(Attachment.class, "submitterId", Converters.trimAndIntern())); issueParser.addProcessor(attachmentTag.child("submitting_username"), Processors.setterMethod(Attachment.class, "submitterUsername", Converters.trimAndIntern())); issueParser.addProcessor(attachmentTag.child("data"), Processors.setterMethod(Attachment.class, "data", Converters.trim())); issueParser.addProcessor(attachmentTag.child("attachment_iz_url"), Processors.setterMethod(Attachment.class, "attachmentIzUrl", Converters.trim())); issueParser.addProcessor(attachmentTag.end(), Processors.addToCollection(Issue.class, "attachments")); // Parsing instructions for duplicante PeerIssues final XMLTagPath hasDuplicatesTag = issueTag.child("has_duplicates"); issueParser.addProcessor(hasDuplicatesTag.start(), Processors.createNewObject(PeerIssue.class)); issueParser.addProcessor(hasDuplicatesTag.child("issue_id"), Processors.setterMethod(PeerIssue.class, "issueId", Converters.trimAndIntern())); issueParser.addProcessor(hasDuplicatesTag.child("who"), Processors.setterMethod(PeerIssue.class, "who", Converters.trimAndIntern())); issueParser.addProcessor(hasDuplicatesTag.child("when"), Processors.setterMethod(PeerIssue.class, "when", Converters.date(dateFormats))); issueParser.addProcessor(hasDuplicatesTag.end(), Processors.addToCollection(Issue.class, "duplicates")); // Parsing instructions for a duplicate PeerIssue final XMLTagPath isDuplicateTag = issueTag.child("is_duplicate"); issueParser.addProcessor(isDuplicateTag.start(), Processors.createNewObject(PeerIssue.class)); issueParser.addProcessor(isDuplicateTag.child("issue_id"), Processors.setterMethod(PeerIssue.class, "issueId", Converters.trimAndIntern())); issueParser.addProcessor(isDuplicateTag.child("who"), Processors.setterMethod(PeerIssue.class, "who", Converters.trimAndIntern())); issueParser.addProcessor(isDuplicateTag.child("when"), Processors.setterMethod(PeerIssue.class, "when", Converters.date(dateFormats))); issueParser.addProcessor(isDuplicateTag.end(), Processors.setterMethod(Issue.class, "duplicate")); // Parsing instructions for a dependent PeerIssue final XMLTagPath dependsOnTag = issueTag.child("dependson"); issueParser.addProcessor(dependsOnTag.start(), Processors.createNewObject(PeerIssue.class)); issueParser.addProcessor(dependsOnTag.child("issue_id"), Processors.setterMethod(PeerIssue.class, "issueId", Converters.trimAndIntern())); issueParser.addProcessor(dependsOnTag.child("who"), Processors.setterMethod(PeerIssue.class, "who", Converters.trimAndIntern())); issueParser.addProcessor(dependsOnTag.child("when"), Processors.setterMethod(PeerIssue.class, "when", Converters.date(dateFormats))); issueParser.addProcessor(dependsOnTag.end(), Processors.addToCollection(Issue.class, "dependsOn")); // Parsing instructions for a blocking PeerIssue final XMLTagPath blocksTag = issueTag.child("blocks"); issueParser.addProcessor(blocksTag.start(), Processors.createNewObject(PeerIssue.class)); issueParser.addProcessor(blocksTag.child("issue_id"), Processors.setterMethod(PeerIssue.class, "issueId", Converters.trimAndIntern())); issueParser.addProcessor(blocksTag.child("who"), Processors.setterMethod(PeerIssue.class, "who", Converters.trimAndIntern())); issueParser.addProcessor(blocksTag.child("when"), Processors.setterMethod(PeerIssue.class, "when", Converters.date(dateFormats))); issueParser.addProcessor(blocksTag.end(), Processors.addToCollection(Issue.class, "blocks")); return issueParser; } /** * Loads issues from the specified URL. */ public static void loadIssues(EventList target, Project owner) throws IOException { int issuesPerRequest = 100; String baseQueryUrl = owner.getIssueQueryUri(); // continuously load issues until there's no more while (true) { // figure out how many to load int currentTotal = target.size(); int nextTotal = currentTotal + issuesPerRequest; // assemble the issue ID argument StringBuffer idArg = new StringBuffer(); for(int i = currentTotal + 1; i <= nextTotal; i++) { idArg.append(i); if(i < nextTotal) idArg.append(":"); } // prepare a stream final String urlAsString = baseQueryUrl + "?include_attachments=false&id=" + idArg; URL issuesUrl = new URL(urlAsString); InputStream issuesInStream = issuesUrl.openStream(); // parse loadIssues(target, issuesInStream, owner); // if we couldn't load everything, we've consumed everything if (target.size() < nextTotal) return; } } /** * Parses the Issuezilla XML document on the specified input stream into a List * of issues. While the parsing is taking place this writes some simple Java * commands to reproduce a lightweight version of this list. This is useful * to load the issues as code rather than XML. */ public static void loadIssues(EventList target, InputStream source, Project owner) throws IOException { createParser(owner).parse(source, target); } /** * This Converter can lookup Priority objects using Strings. */ private static class PriorityConverter implements Converter { @Override public Priority convert(String value) { return Priority.lookupIssuzilla(value.trim()); } } /** * This Processor adds a completely built Issue to the target EventList. * It also performs some late processing of the Issue, namely computing the * state changes of the Issue. This Processor only adds the Issue to the * target EventList if the status code is 200, indicating that the Issue * was loaded successfully. */ private static class AddIssueToTargetListProcessor implements PopProcessor,Issue> { private final Date loadingStarted = new Date(); @Override public void process(EventList issues, Issue issue) { final String statusCode = issue.getStatusCode(); // add the issue to the list if it was found okay if ("200".equals(statusCode)) { // compute the timeline of state changes now that we have loaded the entire Issue issue.getStateChanges().addAll(Issue.computeStateChanges(issue, loadingStarted)); // add the Issue to the list of Issues issues.add(issue); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy