package hudson.plugins.violations.types.cpd; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import hudson.plugins.violations.model.Severity; import hudson.plugins.violations.model.Violation; import hudson.plugins.violations.parse.ViolationsDOMParser; import hudson.plugins.violations.util.StringUtil; /** * Parses a cpd xml report file. */ public class CPDParser extends ViolationsDOMParser { private static final int LOW_LIMIT = 100; private static final int MEDIUM_LIMIT = 1000; /** * Parse the CPD file. * @throws IOException if there is a problem reading the file. * @throws XmlPullParserException if there is a problem parsing the file. */ protected void execute() throws IOException, Exception { Element docElement = getDocument().getDocumentElement(); NodeList nl = docElement.getElementsByTagName("duplication"); if (nl == null) { return; } for (int i = 0; i < nl.getLength(); ++i) { Element el = (Element) nl.item(i); parseDuplicationElement(el); } } private class FileElement { private int line; private String path; } private void parseDuplicationElement(Element parent) throws IOException, Exception { int lines = getInt(parent, "lines"); int tokens = getInt(parent, "tokens"); List<FileElement> fileElements = new ArrayList<FileElement>(); // There should now be two or more file elements // and a codefragmentelement NodeList nl = parent.getElementsByTagName("file"); if (nl == null) { return; } for (int i = 0; i < nl.getLength(); ++i) { Element el = (Element) nl.item(i); fileElements.add(parseFileElement(el)); } FileElement prev = fileElements.get( fileElements.size() - 1); for (FileElement curr: fileElements) { addViolation(lines, tokens, curr, prev); prev = curr; } } private FileElement parseFileElement(Element parent) throws IOException, Exception { FileElement ret = new FileElement(); ret.line = getInt(parent, "line"); ret.path = fixAbsolutePath(checkNotBlank(parent, "path").replace('\\', '/')); return ret; } private String relativePoint( FileElement self, FileElement other) { String path = StringUtil.relativePath(self.path + "/bats", other.path); return path + "#line" + other.line; } private String relativeOther( FileElement self, FileElement other) { StringBuilder b = new StringBuilder(); b.append("line " + other.line); if (!self.path.equals(other.path)) { b.append(" in "); b.append(other.path.substring(other.path.lastIndexOf("/") + 1)); } return b.toString(); } private String relativeHRef( FileElement self, FileElement other) { StringBuilder b = new StringBuilder(); b.append("<a href='"); b.append(relativePoint(self, other)); b.append("'>"); b.append(relativeOther(self, other)); b.append("</a>"); return b.toString(); } private void addViolation(int lines, int tokens, FileElement self, FileElement other) { Violation v = new Violation(); v.setType("cpd"); v.setLine(self.line); setSeverity( v, (tokens < LOW_LIMIT) ? Severity.LOW : (tokens < MEDIUM_LIMIT) ? Severity.MEDIUM : Severity.HIGH); v.setSource("duplication"); v.setMessage( "Duplication of " + tokens + " tokens from " + relativeHRef(self, other)); v.setPopupMessage( "Duplication of " + tokens + " tokens from " + relativeOther(self, other)); getFileModel(self.path).addViolation(v); } private void setSeverity(Violation v, String severity) { v.setSeverity(severity); v.setSeverityLevel(Severity.getSeverityLevel( severity)); } }