package hudson.plugins.checkstyle.parser;
import hudson.plugins.analysis.core.AbstractAnnotationParser;
import hudson.plugins.analysis.util.JavaPackageDetector;
import hudson.plugins.analysis.util.model.FileAnnotation;
import hudson.plugins.analysis.util.model.Priority;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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 Checkstyle XML files.
*
* @author Ulli Hafner
*/
public class CheckStyleParser extends AbstractAnnotationParser {
/** Unique identifier of this class. */
private static final long serialVersionUID = -8705621875291182458L;
/**
* Creates a new instance of {@link CheckStyleParser}.
*/
public CheckStyleParser() {
super(StringUtils.EMPTY);
}
/**
* Creates a new instance of {@link CheckStyleParser}.
*
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
*/
public CheckStyleParser(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(CheckStyleParser.class.getClassLoader());
String rootXPath = "checkstyle";
digester.addObjectCreate(rootXPath, CheckStyle.class);
digester.addSetProperties(rootXPath);
String fileXPath = "checkstyle/file";
digester.addObjectCreate(fileXPath, hudson.plugins.checkstyle.parser.File.class);
digester.addSetProperties(fileXPath);
digester.addSetNext(fileXPath, "addFile", hudson.plugins.checkstyle.parser.File.class.getName());
String bugXPath = "checkstyle/file/error";
digester.addObjectCreate(bugXPath, Error.class);
digester.addSetProperties(bugXPath);
digester.addSetNext(bugXPath, "addError", Error.class.getName());
CheckStyle module;
module = (CheckStyle)digester.parse(new InputStreamReader(file, "UTF-8"));
if (module == null) {
throw new SAXException("Input stream is not a Checkstyle 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 CheckStyle collection, final String moduleName) {
ArrayList<FileAnnotation> annotations = new ArrayList<FileAnnotation>();
for (hudson.plugins.checkstyle.parser.File file : collection.getFiles()) {
if (isValidWarning(file)) {
String packageName = new JavaPackageDetector().detectPackageName(file.getName());
for (Error error : file.getErrors()) {
Priority priority;
if ("error".equalsIgnoreCase(error.getSeverity())) {
priority = Priority.HIGH;
}
else if ("warning".equalsIgnoreCase(error.getSeverity())) {
priority = Priority.NORMAL;
}
else if ("info".equalsIgnoreCase(error.getSeverity())) {
priority = Priority.LOW;
}
else {
continue; // ignore
}
String source = error.getSource();
String type = StringUtils.substringAfterLast(source, ".");
String category = StringUtils.substringAfterLast(StringUtils.substringBeforeLast(source, "."), ".");
Warning warning = new Warning(priority, error.getMessage(), StringUtils.capitalize(category),
type, error.getLine(), error.getLine());
warning.setModuleName(moduleName);
warning.setFileName(file.getName());
warning.setPackageName(packageName);
try {
warning.setContextHashCode(createContextHashCode(file.getName(), error.getLine()));
}
catch (IOException exception) {
// ignore and continue
}
annotations.add(warning);
}
}
}
return annotations;
}
/**
* Returns <code>true</code> if this warning is valid or <code>false</code>
* if the warning can't be processed by the checkstyle plug-in.
*
* @param file the file to check
* @return <code>true</code> if this warning is valid
*/
private boolean isValidWarning(final hudson.plugins.checkstyle.parser.File file) {
return !file.getName().endsWith("package.html");
}
}