package hudson.plugins.cpptest.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 Cpptest XML files.
*
* @author Ulli Hafner
*
* NQH: adapt for Cpptest
*/
public class CpptestParser extends AbstractAnnotationParser {
/** Unique identifier of this class. */
private static final long serialVersionUID = -8705621867291182458L;
/**
* Creates a new instance of {@link CpptestParser}.
*/
public CpptestParser() {
super(StringUtils.EMPTY);
}
/**
* Creates a new instance of {@link CpptestParser}.
*
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
*/
public CpptestParser(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(CpptestParser.class.getClassLoader());
String rootXPath = "ResultsSession";
digester.addObjectCreate(rootXPath, Cpptest.class);
digester.addSetProperties(rootXPath);
String fileXPath = "ResultsSession/CodingStandards/StdViols/StdViol";
digester.addObjectCreate(fileXPath, hudson.plugins.cpptest.parser.StdViol.class);
digester.addSetProperties(fileXPath);
digester.addSetNext(fileXPath, "addFile", hudson.plugins.cpptest.parser.StdViol.class.getName());
String ruleXPath = "ResultsSession/CodingStandards/Rules/RulesList/Rule";
digester.addObjectCreate(ruleXPath, hudson.plugins.cpptest.parser.RuleDesc.class);
digester.addSetProperties(ruleXPath);
digester.addSetNext(ruleXPath, "addRuleDesc", hudson.plugins.cpptest.parser.RuleDesc.class.getName());
String categoryXPath = "ResultsSession/CodingStandards/Rules/CategoriesList/Category";
digester.addObjectCreate(categoryXPath, hudson.plugins.cpptest.parser.Category.class);
digester.addSetProperties(categoryXPath);
digester.addSetNext(categoryXPath, "addCategory", hudson.plugins.cpptest.parser.Category.class.getName());
String locXPath = "ResultsSession/Locations/Loc";
digester.addObjectCreate(locXPath, hudson.plugins.cpptest.parser.Location.class);
digester.addSetProperties(locXPath);
digester.addSetNext(locXPath, "addLocation", hudson.plugins.cpptest.parser.Location.class.getName());
Cpptest module;
module = (Cpptest)digester.parse(new InputStreamReader(file, "UTF-8"));
if (module == null) {
throw new SAXException("Input stream is not a Cpptest 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 Cpptest collection, final String moduleName) {
ArrayList<FileAnnotation> annotations = new ArrayList<FileAnnotation>();
for (hudson.plugins.cpptest.parser.StdViol viol : collection.getFiles()) {
if (isValidWarning(viol)) {
String packageName = new JavaPackageDetector().detectPackageName(viol.getRule());
Priority priority;
if ("1".equalsIgnoreCase(viol.getSev())) {
priority = Priority.HIGH;
}
else if ("2".equalsIgnoreCase(viol.getSev())) {
priority = Priority.HIGH;
}
else if ("3".equalsIgnoreCase(viol.getSev())) {
priority = Priority.NORMAL;
}
else if ("4".equalsIgnoreCase(viol.getSev())) {
priority = Priority.NORMAL;
}
else if ("5".equalsIgnoreCase(viol.getSev())) {
priority = Priority.LOW;
}
else {
continue; // ignore
}
String type = viol.getRule();
String category = viol.getCat();
for (hudson.plugins.cpptest.parser.Category categ : collection.getCategories())
{
if (categ.getName().equals(category))
{
category=categ.getDesc();break;
}
}
Warning warning = new Warning(priority, viol.getMsg(), StringUtils.capitalize(category),
type, viol.getLn(), viol.getLn());
warning.setFileName(viol.getLocFile());
for (hudson.plugins.cpptest.parser.RuleDesc rule : collection.getRuleDescs())
{
if (rule.getId().equals(viol.getRule()))
{
warning.setDesc(rule.getDesc());break;
}
}
for (hudson.plugins.cpptest.parser.Location loc : collection.getLocations())
{
if (loc.getLoc().equals(viol.getLocFile()))
{
warning.setFileName(loc.getFsPath());break;
}
}
//TODO: module and package settings need to be modify to work properly for C++Test purpose
warning.setModuleName(moduleName);
warning.setPackageName(packageName);
try {
warning.setContextHashCode(createContextHashCode(viol.getRule(), viol.getLn()));
}
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 Cpptest plug-in.
*
* @param file the file to check
* @return <code>true</code> if this warning is valid
*/
private boolean isValidWarning(final hudson.plugins.cpptest.parser.StdViol viol) {
return !viol.getRule().endsWith("package.html");
}
}