org.sonar.api.server.rule.RulesDefinitionXmlLoader Maven / Gradle / Ivy
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.server.rule;
import com.google.common.io.Closeables;
import org.apache.commons.lang.StringUtils;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
import org.sonar.api.ServerComponent;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.check.Cardinality;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* Loads definitions of rules from a XML file.
*
* XML Format
*
* <rules>
* <rule>
* <!-- required fields -->
* <key>the-rule-key</key>
* <name>The purpose of the rule</name>
*
* <!-- optional fields -->
* <description>
* <![CDATA[The description]]>
* </description>
* <internalKey>Checker/TreeWalker/LocalVariableName</internalKey>
* <severity>BLOCKER</severity>
* <cardinality>MULTIPLE</cardinality>
* <status>BETA</status>
* <param>
* <key>the-param-key</key>
* <tag>style</tag>
* <tag>security</tag>
* <description>
* <![CDATA[the param-description]]>
* </description>
* <defaultValue>42</defaultValue>
* </param>
* <param>
* <key>another-param</key>
* </param>
*
* <!-- deprecated fields -->
* <configKey>Checker/TreeWalker/LocalVariableName</configKey>
* <priority>BLOCKER</priority>
* </rule>
* </rules>
*
*
* @since 4.3
*/
public class RulesDefinitionXmlLoader implements ServerComponent {
public void load(RulesDefinition.NewRepository repo, InputStream input, String encoding) {
Reader reader = null;
try {
reader = new InputStreamReader(input, encoding);
load(repo, reader);
} catch (IOException e) {
throw new IllegalStateException("Fail to load XML file", e);
} finally {
Closeables.closeQuietly(reader);
}
}
public void load(RulesDefinition.NewRepository repo, Reader reader) {
XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
// just so it won't try to load DTD in if there's DOCTYPE
xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
SMInputFactory inputFactory = new SMInputFactory(xmlFactory);
try {
SMHierarchicCursor rootC = inputFactory.rootElementCursor(reader);
rootC.advance(); //
SMInputCursor rulesC = rootC.childElementCursor("rule");
while (rulesC.getNext() != null) {
//
processRule(repo, rulesC);
}
} catch (XMLStreamException e) {
throw new IllegalStateException("XML is not valid", e);
}
}
private void processRule(RulesDefinition.NewRepository repo, SMInputCursor ruleC) throws XMLStreamException {
String key = null, name = null, description = null, internalKey = null, severity = Severity.defaultSeverity(), status = null;
Cardinality cardinality = Cardinality.SINGLE;
List params = new ArrayList();
List tags = new ArrayList();
/* BACKWARD COMPATIBILITY WITH VERY OLD FORMAT */
String keyAttribute = ruleC.getAttrValue("key");
if (StringUtils.isNotBlank(keyAttribute)) {
key = StringUtils.trim(keyAttribute);
}
String priorityAttribute = ruleC.getAttrValue("priority");
if (StringUtils.isNotBlank(priorityAttribute)) {
severity = StringUtils.trim(priorityAttribute);
}
SMInputCursor cursor = ruleC.childElementCursor();
while (cursor.getNext() != null) {
String nodeName = cursor.getLocalName();
if (StringUtils.equalsIgnoreCase("name", nodeName)) {
name = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("description", nodeName)) {
description = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("key", nodeName)) {
key = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("configKey", nodeName)) {
// deprecated field, replaced by internalKey
internalKey = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("internalKey", nodeName)) {
internalKey = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("priority", nodeName)) {
// deprecated field, replaced by severity
severity = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("severity", nodeName)) {
severity = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("cardinality", nodeName)) {
cardinality = Cardinality.valueOf(StringUtils.trim(cursor.collectDescendantText(false)));
} else if (StringUtils.equalsIgnoreCase("status", nodeName)) {
status = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equalsIgnoreCase("param", nodeName)) {
params.add(processParameter(cursor));
} else if (StringUtils.equalsIgnoreCase("tag", nodeName)) {
tags.add(StringUtils.trim(cursor.collectDescendantText(false)));
}
}
RulesDefinition.NewRule rule = repo.createRule(key)
.setHtmlDescription(description)
.setSeverity(severity)
.setName(name)
.setInternalKey(internalKey)
.setTags(tags.toArray(new String[tags.size()]))
.setTemplate(cardinality == Cardinality.MULTIPLE);
if (status != null) {
rule.setStatus(RuleStatus.valueOf(status));
}
for (ParamStruct param : params) {
rule.createParam(param.key)
.setDefaultValue(param.defaultValue)
.setType(param.type)
.setDescription(param.description);
}
}
private static class ParamStruct {
String key, description, defaultValue;
RuleParamType type = RuleParamType.STRING;
}
private ParamStruct processParameter(SMInputCursor ruleC) throws XMLStreamException {
ParamStruct param = new ParamStruct();
// BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT
String keyAttribute = ruleC.getAttrValue("key");
if (StringUtils.isNotBlank(keyAttribute)) {
param.key = StringUtils.trim(keyAttribute);
}
// BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT
String typeAttribute = ruleC.getAttrValue("type");
if (StringUtils.isNotBlank(typeAttribute)) {
param.type = RuleParamType.parse(typeAttribute);
}
SMInputCursor paramC = ruleC.childElementCursor();
while (paramC.getNext() != null) {
String propNodeName = paramC.getLocalName();
String propText = StringUtils.trim(paramC.collectDescendantText(false));
if (StringUtils.equalsIgnoreCase("key", propNodeName)) {
param.key = propText;
} else if (StringUtils.equalsIgnoreCase("description", propNodeName)) {
param.description = propText;
} else if (StringUtils.equalsIgnoreCase("type", propNodeName)) {
param.type = RuleParamType.parse(propText);
} else if (StringUtils.equalsIgnoreCase("defaultValue", propNodeName)) {
param.defaultValue = propText;
}
}
return param;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy