+++ /dev/null
-/*
- * 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.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;
-
-/**
- * @since 4.2
- */
-class RuleDefinitionsFromXml {
-
- void loadRules(RulesDefinition.NewRepository repo, InputStream input, String encoding) {
- Reader reader = null;
- try {
- reader = new InputStreamReader(input, encoding);
- loadRules(repo, reader);
-
- } catch (IOException e) {
- throw new IllegalStateException("Fail to load XML file", e);
-
- } finally {
- Closeables.closeQuietly(reader);
- }
- }
-
- void loadRules(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(); // <rules>
-
- SMInputCursor rulesC = rootC.childElementCursor("rule");
- while (rulesC.getNext() != null) {
- // <rule>
- 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<ParamStruct> params = new ArrayList<ParamStruct>();
- List<String> tags = new ArrayList<String>();
-
- /* 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;
- }
-}
package org.sonar.api.server.rule;
import com.google.common.base.Strings;
-import com.google.common.collect.*;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
-
import java.io.IOException;
-import java.io.InputStream;
import java.net.URL;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
*/
NewExtendedRepository loadAnnotatedClasses(Class... classes);
- /**
- * Reads definitions of rules from a XML file. Format is :
- * <pre>
- * <rules>
- * <rule>
- * <!-- required fields -->
- * <key>the-rule-key</key>
- * <name>The purpose of the rule</name>
- * <description>
- * <![CDATA[The description]]>
- * </description>
- *
- * <!-- optional fields -->
- * <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>
- *
- * </pre>
- */
- NewExtendedRepository loadXml(InputStream xmlInput, String encoding);
-
void done();
}
@CheckForNull
NewRule rule(String ruleKey);
+
+ Collection<NewRule> rules();
+
+ String key();
}
class NewRepositoryImpl implements NewRepository {
this.language = language;
}
+ @Override
+ public String key() {
+ return key;
+ }
+
@Override
public NewRepositoryImpl setName(@Nullable String s) {
if (StringUtils.isNotEmpty(s)) {
return newRules.get(ruleKey);
}
+ @Override
+ public Collection<NewRule> rules() {
+ return newRules.values();
+ }
+
@Override
public NewRepositoryImpl loadAnnotatedClasses(Class... classes) {
new RuleDefinitionsFromAnnotations().loadRules(this, classes);
return new RuleDefinitionsFromAnnotations().loadRule(this, clazz);
}
- @Override
- public NewRepositoryImpl loadXml(InputStream xmlInput, String encoding) {
- new RuleDefinitionsFromXml().loadRules(this, xmlInput, encoding);
- return this;
- }
-
@Override
public void done() {
// note that some validations can be done here, for example for
return paramsByKey.get(paramKey);
}
+ public Collection<NewParam> params() {
+ return paramsByKey.values();
+ }
+
/**
* @see RuleTagFormat
*/
this.key = this.name = key;
}
+ public String key() {
+ return key;
+ }
+
public NewParam setName(@Nullable String s) {
// name must never be null.
this.name = StringUtils.defaultIfBlank(s, key);
--- /dev/null
+/*
+ * 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.
+ *
+ * <h3>XML Format</h3>
+ * <pre>
+ * <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>
+ * </pre>
+ *
+ * @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(); // <rules>
+
+ SMInputCursor rulesC = rootC.childElementCursor("rule");
+ while (rulesC.getNext() != null) {
+ // <rule>
+ 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<ParamStruct> params = new ArrayList<ParamStruct>();
+ List<String> tags = new ArrayList<String>();
+
+ /* 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;
+ }
+}
+++ /dev/null
-/*
- * 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.base.Charsets;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RulesDefinitionFromXmlTest {
-
- @org.junit.Rule
- public final ExpectedException thrown = ExpectedException.none();
-
- private RulesDefinition.Repository load(Reader reader) {
- RulesDefinition.Context context = new RulesDefinition.Context();
- RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java");
- new RuleDefinitionsFromXml().loadRules(newRepository, reader);
- newRepository.done();
- return context.repository("squid");
- }
-
- @Test
- public void should_parse_xml() throws Exception {
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/rules.xml"), Charsets.UTF_8.name());
- RulesDefinition.Repository repository = load(reader);
- assertThat(repository.rules()).hasSize(2);
-
- RulesDefinition.Rule rule = repository.rule("complete");
- assertThat(rule.key()).isEqualTo("complete");
- assertThat(rule.name()).isEqualTo("Complete");
- assertThat(rule.htmlDescription()).isEqualTo("Description of Complete");
- assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.template()).isTrue();
- assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
- assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/LocalVariableName");
- assertThat(rule.tags()).containsOnly("style", "security");
-
- assertThat(rule.params()).hasSize(2);
- RulesDefinition.Param ignore = rule.param("ignore");
- assertThat(ignore.key()).isEqualTo("ignore");
- assertThat(ignore.description()).isEqualTo("Ignore ?");
- assertThat(ignore.defaultValue()).isEqualTo("false");
-
- rule = repository.rule("minimal");
- assertThat(rule.key()).isEqualTo("minimal");
- assertThat(rule.name()).isEqualTo("Minimal");
- assertThat(rule.htmlDescription()).isEqualTo("Description of Minimal");
- assertThat(rule.params()).isEmpty();
- assertThat(rule.status()).isEqualTo(RuleStatus.READY);
- assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
- }
-
- @Test
- public void should_fail_if_missing_rule_key() {
- thrown.expect(IllegalStateException.class);
- load(new StringReader("<rules><rule><name>Foo</name></rule></rules>"));
- }
-
- @Test
- public void should_fail_if_missing_property_key() {
- thrown.expect(IllegalStateException.class);
- load(new StringReader("<rules><rule><key>foo</key><name>Foo</name><param></param></rule></rules>"));
- }
-
- @Test
- public void should_fail_on_invalid_rule_parameter_type() {
- thrown.expect(IllegalStateException.class);
- load(new StringReader("<rules><rule><key>foo</key><name>Foo</name><param><key>key</key><type>INVALID</type></param></rule></rules>"));
- }
-
- @Test
- public void test_utf8_encoding() throws UnsupportedEncodingException {
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/utf8.xml"), Charsets.UTF_8.name());
- RulesDefinition.Repository repository = load(reader);
-
- assertThat(repository.rules()).hasSize(1);
- RulesDefinition.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck");
- assertThat(rule.name()).isEqualTo("M & M");
- assertThat(rule.htmlDescription().charAt(0)).isEqualTo('\u00E9');
- assertThat(rule.htmlDescription().charAt(1)).isEqualTo('\u00E0');
- assertThat(rule.htmlDescription().charAt(2)).isEqualTo('\u0026');
- }
-
- @Test
- public void should_support_deprecated_format() throws UnsupportedEncodingException {
- // the deprecated format uses some attributes instead of nodes
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/deprecated.xml"), Charsets.UTF_8.name());
- RulesDefinition.Repository repository = load(reader);
-
- assertThat(repository.rules()).hasSize(1);
- RulesDefinition.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck");
- assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck");
- assertThat(rule.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(rule.htmlDescription()).isEqualTo("Count methods");
- assertThat(rule.param("minMethodsCount")).isNotNull();
- }
-}
--- /dev/null
+/*
+ * 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.base.Charsets;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RulesDefinitionXmlLoaderTest {
+
+ @org.junit.Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ private RulesDefinition.Repository load(InputStream input, String encoding) {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java");
+ new RulesDefinitionXmlLoader().load(newRepository, input, encoding);
+ newRepository.done();
+ return context.repository("squid");
+ }
+
+ @Test
+ public void parse_xml() throws Exception {
+ InputStream input = getClass().getResourceAsStream("/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest/rules.xml");
+ RulesDefinition.Repository repository = load(input, Charsets.UTF_8.name());
+ assertThat(repository.rules()).hasSize(2);
+
+ RulesDefinition.Rule rule = repository.rule("complete");
+ assertThat(rule.key()).isEqualTo("complete");
+ assertThat(rule.name()).isEqualTo("Complete");
+ assertThat(rule.htmlDescription()).isEqualTo("Description of Complete");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.template()).isTrue();
+ assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/LocalVariableName");
+ assertThat(rule.tags()).containsOnly("style", "security");
+
+ assertThat(rule.params()).hasSize(2);
+ RulesDefinition.Param ignore = rule.param("ignore");
+ assertThat(ignore.key()).isEqualTo("ignore");
+ assertThat(ignore.description()).isEqualTo("Ignore ?");
+ assertThat(ignore.defaultValue()).isEqualTo("false");
+
+ rule = repository.rule("minimal");
+ assertThat(rule.key()).isEqualTo("minimal");
+ assertThat(rule.name()).isEqualTo("Minimal");
+ assertThat(rule.htmlDescription()).isEqualTo("Description of Minimal");
+ assertThat(rule.params()).isEmpty();
+ assertThat(rule.status()).isEqualTo(RuleStatus.READY);
+ assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
+ }
+
+ @Test
+ public void fail_if_missing_rule_key() {
+ thrown.expect(IllegalStateException.class);
+ load(IOUtils.toInputStream("<rules><rule><name>Foo</name></rule></rules>"), Charsets.UTF_8.name());
+ }
+
+ @Test
+ public void fail_if_missing_property_key() {
+ thrown.expect(IllegalStateException.class);
+ load(IOUtils.toInputStream("<rules><rule><key>foo</key><name>Foo</name><param></param></rule></rules>"), Charsets.UTF_8.name());
+ }
+
+ @Test
+ public void fail_on_invalid_rule_parameter_type() {
+ thrown.expect(IllegalStateException.class);
+ load(IOUtils.toInputStream("<rules><rule><key>foo</key><name>Foo</name><param><key>key</key><type>INVALID</type></param></rule></rules>"), Charsets.UTF_8.name());
+ }
+
+ @Test
+ public void fail_if_invalid_xml() throws UnsupportedEncodingException {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("XML is not valid");
+
+ InputStream input = getClass().getResourceAsStream("/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest/invalid.xml");
+ load(input, Charsets.UTF_8.name());
+ }
+
+ @Test
+ public void test_utf8_encoding() throws UnsupportedEncodingException {
+ InputStream input = getClass().getResourceAsStream("/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest/utf8.xml");
+ RulesDefinition.Repository repository = load(input, Charsets.UTF_8.name());
+
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck");
+ assertThat(rule.name()).isEqualTo("M & M");
+ assertThat(rule.htmlDescription().charAt(0)).isEqualTo('\u00E9');
+ assertThat(rule.htmlDescription().charAt(1)).isEqualTo('\u00E0');
+ assertThat(rule.htmlDescription().charAt(2)).isEqualTo('\u0026');
+ }
+
+ @Test
+ public void support_deprecated_format() throws UnsupportedEncodingException {
+ // the deprecated format uses some attributes instead of nodes
+ InputStream input = getClass().getResourceAsStream("/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest/deprecated.xml");
+ RulesDefinition.Repository repository = load(input, Charsets.UTF_8.name());
+
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck");
+ assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck");
+ assertThat(rule.severity()).isEqualTo(Severity.CRITICAL);
+ assertThat(rule.htmlDescription()).isEqualTo("Count methods");
+ assertThat(rule.param("minMethodsCount")).isNotNull();
+ }
+}
+++ /dev/null
-<rules>
- <rule key="org.sonar.it.checkstyle.MethodsCountCheck" priority="CRITICAL">
- <name>Methods Count Check</name>
- <configKey>Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck</configKey>
- <description>Count methods</description>
- <param key="minMethodsCount" type="i">
- <description>description of param</description>
- </param>
- </rule>
-</rules>
\ No newline at end of file
+++ /dev/null
-<rules>
- <rule>
- <!-- with exhaustive fields -->
- <key>complete</key>
- <name>Complete</name>
- <description>
- <![CDATA[Description of Complete]]>
- </description>
- <internalKey>Checker/TreeWalker/LocalVariableName</internalKey>
- <severity>BLOCKER</severity>
- <cardinality>MULTIPLE</cardinality>
- <status>BETA</status>
- <tag>style</tag>
- <tag>security</tag>
- <param>
- <key>tokens</key>
- <description>
- <![CDATA[
- Controls whether the check applies to variable declarations or catch clause parameters
- ]]>
- </description>
- </param>
- <param>
- <key>ignore</key>
- <description>
- Ignore ?
- </description>
- <defaultValue>false</defaultValue>
- </param>
- </rule>
-
-
- <rule>
- <!-- with only required fields -->
- <key>minimal</key>
- <name>Minimal</name>
- <description>
- <![CDATA[Description of Minimal]]>
- </description>
- </rule>
-</rules>
+++ /dev/null
-<rules>
- <rule>
- <key>com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck</key>
- <priority>BLOCKER</priority>
- <configKey>Checker/TreeWalker/LocalVariableName</configKey>
- <name>M & M</name>
- <description>
- <![CDATA[éà&]]>
- </description>
- </rule>
-</rules>
--- /dev/null
+<rules>
+ <rule key="org.sonar.it.checkstyle.MethodsCountCheck" priority="CRITICAL">
+ <name>Methods Count Check</name>
+ <configKey>Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck</configKey>
+ <description>Count methods</description>
+ <param key="minMethodsCount" type="i">
+ <description>description of param</description>
+ </param>
+ </rule>
+</rules>
\ No newline at end of file
--- /dev/null
+<rules>
+ <rule>
--- /dev/null
+<rules>
+ <rule>
+ <!-- with exhaustive fields -->
+ <key>complete</key>
+ <name>Complete</name>
+ <description>
+ <![CDATA[Description of Complete]]>
+ </description>
+ <internalKey>Checker/TreeWalker/LocalVariableName</internalKey>
+ <severity>BLOCKER</severity>
+ <cardinality>MULTIPLE</cardinality>
+ <status>BETA</status>
+ <tag>style</tag>
+ <tag>security</tag>
+ <param>
+ <key>tokens</key>
+ <description>
+ <![CDATA[
+ Controls whether the check applies to variable declarations or catch clause parameters
+ ]]>
+ </description>
+ </param>
+ <param>
+ <key>ignore</key>
+ <description>
+ Ignore ?
+ </description>
+ <defaultValue>false</defaultValue>
+ </param>
+ </rule>
+
+
+ <rule>
+ <!-- with only required fields -->
+ <key>minimal</key>
+ <name>Minimal</name>
+ <description>
+ <![CDATA[Description of Minimal]]>
+ </description>
+ </rule>
+</rules>
--- /dev/null
+<rules>
+ <rule>
+ <key>com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck</key>
+ <priority>BLOCKER</priority>
+ <configKey>Checker/TreeWalker/LocalVariableName</configKey>
+ <name>M & M</name>
+ <description>
+ <![CDATA[éà&]]>
+ </description>
+ </rule>
+</rules>
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.rules.AnnotationRuleParser;
import org.sonar.api.rules.XMLRuleParser;
+import org.sonar.api.server.rule.RulesDefinitionI18nLoader;
+import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.UriReader;
pico.addSingleton(RuleSearchWsHandler.class);
pico.addSingleton(AddTagsWsHandler.class);
pico.addSingleton(RemoveTagsWsHandler.class);
+ pico.addSingleton(RulesDefinitionXmlLoader.class);
+ pico.addSingleton(RulesDefinitionI18nLoader.class);
// rule tags
pico.addSingleton(ESRuleTags.class);