package hudson.plugins.pmd.parser;
import hudson.plugins.analysis.core.AbstractAnnotationParser;
import hudson.plugins.analysis.util.model.FileAnnotation;
import hudson.plugins.analysis.util.model.Priority;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.digester.Digester;
import org.apache.commons.lang.StringUtils;
import org.xml.sax.SAXException;
/**
* A parser for PMD XML files.
*
* @author Ulli Hafner
*/
public class PmdParser extends AbstractAnnotationParser {
/** Unique ID of this class. */
private static final long serialVersionUID = 6507147028628714706L;
/** PMD priorities smaller than this value are mapped to {@link Priority#HIGH}. */
private static final int PMD_PRIORITY_MAPPED_TO_HIGH_PRIORITY = 3;
/** PMD priorities greater than this value are mapped to {@link Priority#LOW}. */
private static final int PMD_PRIORITY_MAPPED_TO_LOW_PRIORITY = 4;
/**
* Creates a new instance of {@link PmdParser}.
*/
public PmdParser() {
super(StringUtils.EMPTY);
}
/**
* Creates a new instance of {@link PmdParser}.
*
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
*/
public PmdParser(final String defaultEncoding) {
super(defaultEncoding);
}
/** {@inheritDoc} */
@Override
public Collection<FileAnnotation> parse(final InputStream file, final String moduleName) throws InvocationTargetException {
try {
Digester digester = new Digester();
digester.setValidating(false);
digester.setClassLoader(PmdParser.class.getClassLoader());
String rootXPath = "pmd";
digester.addObjectCreate(rootXPath, Pmd.class);
digester.addSetProperties(rootXPath);
String fileXPath = "pmd/file";
digester.addObjectCreate(fileXPath, hudson.plugins.pmd.parser.File.class);
digester.addSetProperties(fileXPath);
digester.addSetNext(fileXPath, "addFile", hudson.plugins.pmd.parser.File.class.getName());
String bugXPath = "pmd/file/violation";
digester.addObjectCreate(bugXPath, Violation.class);
digester.addSetProperties(bugXPath);
digester.addCallMethod(bugXPath, "setMessage", 0);
digester.addSetNext(bugXPath, "addViolation", Violation.class.getName());
Pmd module = (Pmd)digester.parse(file);
if (module == null) {
throw new SAXException("Input stream is not a PMD file.");
}
return convert(module, moduleName);
}
catch (IOException exception) {
throw new InvocationTargetException(exception);
}
catch (SAXException exception) {
throw new InvocationTargetException(exception);
}
}
/**
* Converts the internal structure to the annotations API.
*
* @param collection
* the internal maven module
* @param moduleName
* name of the maven module
* @return a maven module of the annotations API
*/
private Collection<FileAnnotation> convert(final Pmd collection, final String moduleName) {
ArrayList<FileAnnotation> annotations = new ArrayList<FileAnnotation>();
for (hudson.plugins.pmd.parser.File file : collection.getFiles()) {
for (Violation warning : file.getViolations()) {
Priority priority;
if (warning.getPriority() < PMD_PRIORITY_MAPPED_TO_HIGH_PRIORITY) {
priority = Priority.HIGH;
}
else if (warning.getPriority() > PMD_PRIORITY_MAPPED_TO_LOW_PRIORITY) {
priority = Priority.LOW;
}
else {
priority = Priority.NORMAL;
}
Bug bug = new Bug(priority, warning.getMessage() + ".", warning.getRuleset(), warning.getRule(),
warning.getBeginline(), warning.getEndline());
bug.setPackageName(warning.getPackage());
bug.setModuleName(moduleName);
bug.setFileName(file.getName());
try {
bug.setContextHashCode(createContextHashCode(file.getName(), warning.getBeginline()));
}
catch (IOException exception) {
// ignore and continue
}
annotations.add(bug);
}
}
return annotations;
}
}