/** * This file is licensed under the University of Illinois/NCSA Open Source License. See LICENSE.TXT for details. */ package edu.illinois.codingspectator.refactoringproblems.parser; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import edu.illinois.codingspectator.refactoringproblems.logger.DefaultProblemWrapper; import edu.illinois.codingspectator.refactoringproblems.logger.ProblemChanges; /** * Deserializes a refactoring-problems log and returns a list of ProblemChanges (@see * {@link ProblemChanges}). * * @author Mohsen Vakilian * @author nchen * @author Balaji Ambresh Rajkumar * */ @SuppressWarnings("restriction") public class RefactoringProblemsLogDeserializer extends DefaultHandler { Set<DefaultProblemWrapper> problems; Set<DefaultProblemWrapper> afterMinusBefore, beforeMinusAfter; long refactoringTimestamp, afterTimestamp, beforeTimestamp; List<ProblemChanges> allProblemChanges; private boolean considerTimestamps; public RefactoringProblemsLogDeserializer(boolean considerTimestamps) { this.considerTimestamps= considerTimestamps; this.problems= new HashSet<DefaultProblemWrapper>(); this.afterMinusBefore= new HashSet<DefaultProblemWrapper>(); this.beforeMinusAfter= new HashSet<DefaultProblemWrapper>(); this.afterTimestamp= -1; this.beforeTimestamp= -1; this.allProblemChanges= new ArrayList<ProblemChanges>(); } public RefactoringProblemsLogDeserializer() { this(true); } public List<ProblemChanges> deserializeRefactoringProblemsLog(String fileName) throws RefactoringProblemsParserException { try { parseXML(fileName); } catch (ParserConfigurationException e) { throw new RefactoringProblemsParserException(e); } catch (SAXException e) { throw new RefactoringProblemsParserException(e); } catch (FileNotFoundException e) { throw new RefactoringProblemsParserException(e); } catch (IOException e) { throw new RefactoringProblemsParserException(e); } return allProblemChanges; } private void parseXML(String fileName) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException { SAXParser parser; parser= createParser(); parser.parse(new InputSource(wrapFileReaderWithStartEndXMLTag(fileName)), this); } private Reader wrapFileReaderWithStartEndXMLTag(String fileName) throws FileNotFoundException { final String allProblemChangesTagName= "all-problem-changes"; CompositeReader firstComposite= new CompositeReader(new StringReader("<" + allProblemChangesTagName + ">"), new FileReader(new File(fileName))); return new CompositeReader(firstComposite, new StringReader("</" + allProblemChangesTagName + ">")); } private SAXParser createParser() throws ParserConfigurationException, SAXException { final SAXParserFactory factory= SAXParserFactory.newInstance(); final SAXParser parser= factory.newSAXParser(); final XMLReader reader= parser.getXMLReader(); reader.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ return parser; } private int getIntAttribute(Attributes attributes, String attribute) { return Integer.valueOf(attributes.getValue(attribute)); } private long getLongAttribute(Attributes attributes, String attribute) { return Long.valueOf(attributes.getValue(attribute)); } private long getTimestampAttribute(Attributes attributes, String attribute) { if (considerTimestamps) { return getLongAttribute(attributes, attribute); } else { return -1; } } private String getStringAttribute(Attributes attributes, String attribute) { return attributes.getValue(attribute); } private char[] getCharArrayAttribute(Attributes attributes, String attribute) { return attributes.getValue(attribute).toCharArray(); } private String[] getStringArrayAttribute(Attributes attributes, String attribute) { String argumentsString= attributes.getValue(attribute); String[] arguments= argumentsString.substring("[".length(), argumentsString.length() - ", ]".length()).split(", "); return arguments; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals(DefaultProblemWrapper.PROBLEM_TAG_NAME)) { char[] fileName= getCharArrayAttribute(attributes, "fileName"); String message= getStringAttribute(attributes, "message"); int id= getIntAttribute(attributes, "id"); String[] arguments= getStringArrayAttribute(attributes, "arguments"); int severity= getIntAttribute(attributes, "severity"); int startPosition= getIntAttribute(attributes, "startPosition"); int endPosition= getIntAttribute(attributes, "endPosition"); int line= getIntAttribute(attributes, "line"); CategorizedProblem problem= new DefaultProblem(fileName, message, id, arguments, severity, startPosition, endPosition, line, -1); DefaultProblemWrapper defaultProblemWrapper= new DefaultProblemWrapper(getStringAttribute(attributes, "problemMarker"), problem); problems.add(defaultProblemWrapper); } else if (qName.equals(ProblemChanges.AFTER_MINUS_BEFORE_TAG_NAME)) { afterTimestamp= getTimestampAttribute(attributes, ProblemChanges.TIMESTAMP_ATTRIBUTE_NAME); problems.clear(); } else if (qName.equals(ProblemChanges.BEFORE_MINUS_AFTER_TAG_NAME)) { beforeTimestamp= getTimestampAttribute(attributes, ProblemChanges.TIMESTAMP_ATTRIBUTE_NAME); problems.clear(); } else if (qName.equals(ProblemChanges.PROBLEM_CHANGES_TAG_NAME)) { refactoringTimestamp= getTimestampAttribute(attributes, ProblemChanges.REFACTORING_TIMESTAMP_ATTRIBUTE_NAME); afterMinusBefore.clear(); beforeMinusAfter.clear(); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals(ProblemChanges.AFTER_MINUS_BEFORE_TAG_NAME)) { afterMinusBefore.addAll(problems); } else if (qName.equals(ProblemChanges.BEFORE_MINUS_AFTER_TAG_NAME)) { beforeMinusAfter.addAll(problems); } else if (qName.equals(ProblemChanges.PROBLEM_CHANGES_TAG_NAME)) { allProblemChanges.add(new ProblemChanges(refactoringTimestamp, afterTimestamp, afterMinusBefore, beforeTimestamp, beforeMinusAfter)); } } }