changeset 449:56aa3f718c24 Faradi-7.0.x

Use SAX instead of DOM
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Tue, 03 Jul 2012 18:22:26 +0400
parents 6fb828bf0d87
children 12cb638b63c4 5d4a7174c316
files mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MercurialXmlLogParser.java
diffstat 2 files changed, 129 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Mon Jul 02 16:22:01 2012 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Tue Jul 03 18:22:26 2012 +0400
@@ -16,25 +16,27 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
 import com.intellij.execution.configurations.GeneralCommandLine;
-import com.intellij.openapi.util.JDOMUtil;
 import jetbrains.buildServer.vcs.VcsException;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.xml.sax.SAXException;
 
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public class LogCommand extends VcsRootCommand {
 
   private final static String ZERO_PARENT_ID = "0000000000000000000000000000000000000000";
-  private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss yyyy Z";
+  private final static SAXParserFactory ourSAXFactory = SAXParserFactory.newInstance();
 
   private String myFromId;
   private String myToId;
@@ -130,17 +132,15 @@
     }
   }
 
-  private List<ChangeSet> parseChangeSetsXml(@NotNull final String xml) throws JDOMException, IOException, ParseException {
+  private List<ChangeSet> parseChangeSetsXml(@NotNull final String xml) throws SAXException, ParserConfigurationException, IOException {
     if ("".equals(xml))
       return Collections.emptyList();
-    Document doc = loadDocument(xml);
-    Element log = doc.getRootElement();
-    return parseLog(log);
-  }
 
-  private Document loadDocument(@NotNull final String xml) throws IOException, JDOMException {
     String validXml = makeValidXml(xml);
-    return JDOMUtil.loadDocument(validXml);
+    MercurialXmlLogParser parser = new MercurialXmlLogParser();
+    SAXParser saxParser = ourSAXFactory.newSAXParser();
+    saxParser.parse(new ByteArrayInputStream(validXml.getBytes(Charset.forName("UTF-8"))), parser);
+    return parser.getChangeSets();
   }
 
   private String makeValidXml(@NotNull final String xml) {
@@ -151,104 +151,6 @@
       return xml + "</log>";
   }
 
-
-  private List<ChangeSet> parseLog(@NotNull final Element logElement) throws ParseException {
-    List<ChangeSet> result = new ArrayList<ChangeSet>();
-    for (Object o : logElement.getChildren("logentry")) {
-      Element entry = (Element) o;
-      result.add(parseLogEntry(entry));
-    }
-    return result;
-  }
-
-
-  private ChangeSet parseLogEntry(@NotNull final Element logEntry) throws ParseException {
-    ChangeSet cset = new ChangeSet(getRevision(logEntry), getId(logEntry));
-    addParents(cset, logEntry);
-    cset.setUser(getAuthor(logEntry));
-    cset.setDescription(getDescription(logEntry));
-    cset.setTimestamp(getDate(logEntry));
-    cset.setModifiedFiles(getModifiedFiles(logEntry));
-    return cset;
-  }
-
-
-  private int getRevision(@NotNull final Element logEntry) {
-    return Integer.parseInt(logEntry.getAttribute("revision").getValue());
-  }
-
-
-  private String getId(@NotNull final Element logEntry) {
-    return logEntry.getAttribute("shortnode").getValue();
-  }
-
-
-  private void addParents(@NotNull final ChangeSet cset, @NotNull final Element logEntry) {
-    List parents = logEntry.getChildren("parent");
-    for (Object p : parents) {
-      Element parent = (Element) p;
-      ChangeSetRevision parentCset = getParent(parent);
-      cset.addParent(parentCset);
-    }
-  }
-
-
-  private ChangeSetRevision getParent(@NotNull final Element parent) {
-    return new ChangeSetRevision(getRevision(parent), getId(parent));
-  }
-
-
-  private String getAuthor(@NotNull final Element logEntry) {
-    Element author = logEntry.getChild("author");
-    return author.getAttribute("original").getValue();
-  }
-
-
-  private String getDescription(@NotNull final Element logEntry) {
-    Element msg = logEntry.getChild("msg");
-    return msg.getText();
-  }
-
-
-  private Date getDate(@NotNull final Element logEntry) throws ParseException {
-    Element date = logEntry.getChild("date");
-    return new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH).parse(date.getText());
-  }
-
-
-  private List<ModifiedFile> getModifiedFiles(@NotNull final Element logEntry) {
-    List<ModifiedFile> result = new ArrayList<ModifiedFile>();
-    Element paths = logEntry.getChild("paths");
-    if (paths == null)
-      return result;
-    for (Object o : paths.getChildren("path")) {
-      Element path = (Element) o;
-      result.add(getModifiedFile(path));
-    }
-    return result;
-  }
-
-
-  private ModifiedFile getModifiedFile(@NotNull final Element path) {
-    String filePath = path.getText();
-    ModifiedFile.Status status = getStatus(path);
-    return new ModifiedFile(status, filePath);
-  }
-
-
-  private ModifiedFile.Status getStatus(@NotNull final Element path) {
-    String action = path.getAttribute("action").getValue();
-    if (action.equals("A")) {
-      return ModifiedFile.Status.ADDED;
-    } else if (action.equals("M")) {
-      return ModifiedFile.Status.MODIFIED;
-    } else if (action.equals("R")) {
-      return ModifiedFile.Status.REMOVED;
-    } else {
-      return ModifiedFile.Status.UNKNOWN;
-    }
-  }
-
   private void assignTrivialParents(final @NotNull List<ChangeSet> csets) throws VcsException {
     Map<Integer, ChangeSet> revNumberMap = makeMapByRevNumber(csets);
     for (ChangeSet cset : csets) {
@@ -281,4 +183,4 @@
             .inLocalRepository()
             .call();
   }
-}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MercurialXmlLogParser.java	Tue Jul 03 18:22:26 2012 +0400
@@ -0,0 +1,113 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import org.jetbrains.annotations.NotNull;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import static com.intellij.openapi.util.text.StringUtil.isEmpty;
+
+/**
+* @author dmitry.neverov
+*/
+public class MercurialXmlLogParser extends DefaultHandler {
+
+  private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss yyyy Z";
+  private static final SimpleDateFormat ourSimpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH);
+  private List<ChangeSet> myChangeSets = new ArrayList<ChangeSet>();
+  private ChangeSet myCset = null;
+  private StringBuilder myText = new StringBuilder();
+  private List<ModifiedFile> myFiles;
+  private String myFileAction;
+
+  @NotNull
+  public List<ChangeSet> getChangeSets() {
+    return myChangeSets;
+  }
+
+  @Override
+  public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
+    if ("logentry".equals(qName)) {
+      myCset = new ChangeSet(getRevision(attrs), getId(attrs));
+    } else if ("parent".equals(qName)) {
+      ChangeSetRevision parentCset = new ChangeSetRevision(getRevision(attrs), getId(attrs));
+      myCset.addParent(parentCset);
+    } else if ("author".equals(qName)) {
+      myCset.setUser(attrs.getValue("original"));
+    } else if ("paths".equals(qName)) {
+      myFiles = new ArrayList<ModifiedFile>();
+    } else if ("path".equals(qName)) {
+      myFileAction = attrs.getValue("action");
+      resetText();
+    } else if ("msg".equals(qName)) {
+      resetText();
+    } else if ("date".equals(qName)) {
+      resetText();
+    }
+  }
+
+  @Override
+  public void endElement(String uri, String localName, String qName) throws SAXException {
+    if ("logentry".equals(qName)) {
+      myChangeSets.add(myCset);
+    } else if ("paths".equals(qName)) {
+      myCset.setModifiedFiles(myFiles);
+    } else if ("path".equals(qName)) {
+      myFiles.add(new ModifiedFile(getStatus(myFileAction), getText()));
+    } else if ("msg".equals(qName)) {
+      myCset.setDescription(getText());
+    } else if ("date".equals(qName)) {
+      myCset.setTimestamp(parseDate());
+    }
+  }
+
+  @Override
+  public void characters(char[] ch, int start, int length) throws SAXException {
+    myText.append(ch, start, length);
+  }
+
+  private String getText() {
+    return myText.toString();
+  }
+
+  private void resetText() {
+    myText = new StringBuilder();
+  }
+
+  private Date parseDate() throws SAXException {
+    try {
+      return ourSimpleDateFormat.parse(getText());
+    } catch (ParseException e) {
+      throw new SAXException(e);
+    }
+  }
+
+  private int getRevision(@NotNull Attributes attrs) {
+    return Integer.parseInt(attrs.getValue("revision"));
+  }
+
+  private String getId(@NotNull Attributes attrs) {
+    return attrs.getValue("shortnode");
+  }
+
+  private ModifiedFile.Status getStatus(String action) {
+    if (isEmpty(action))
+      return ModifiedFile.Status.UNKNOWN;
+    if (action.equals("A")) {
+      return ModifiedFile.Status.ADDED;
+    } else if (action.equals("M")) {
+      return ModifiedFile.Status.MODIFIED;
+    } else if (action.equals("R")) {
+      return ModifiedFile.Status.REMOVED;
+    } else {
+      return ModifiedFile.Status.UNKNOWN;
+    }
+  }
+}