*/
package org.sonar.plugins.xoo.rules;
-import org.sonar.api.rule.RuleDefinitions;
-import org.sonar.api.rule.RuleParamType;
+import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleParamType;
import org.sonar.plugins.xoo.base.XooConstants;
import org.sonar.plugins.xoo.base.XooRuleKeys;
package org.sonar.plugins.xoo.rules;
import org.junit.Test;
-import org.sonar.api.rule.RuleDefinitions;
-import org.sonar.api.rule.RuleDefinitions.Repository;
+import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions.Repository;
import static org.fest.assertions.Assertions.assertThat;
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import com.google.common.collect.*;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Defines the coding rules. For example the Java Findbugs plugin provides an implementation of
- * this extension point in order to define the rules that it supports.
- * <p/>
- * This interface replaces the deprecated class org.sonar.api.rules.RuleRepository.
- *
- * @since 4.2
- */
-public interface RuleDefinitions extends ServerExtension {
-
- /**
- * Instantiated by core but not by plugins
- */
- class Context {
- private final Map<String, Repository> repositoriesByKey = Maps.newHashMap();
- private final ListMultimap<String, ExtendedRepository> extendedRepositoriesByKey = ArrayListMultimap.create();
-
- public NewRepository newRepository(String key, String language) {
- return new NewRepositoryImpl(this, key, language, false);
- }
-
- public NewExtendedRepository extendRepository(String key, String language) {
- return new NewRepositoryImpl(this, key, language, true);
- }
-
- @CheckForNull
- public Repository repository(String key) {
- return repositoriesByKey.get(key);
- }
-
- public List<Repository> repositories() {
- return ImmutableList.copyOf(repositoriesByKey.values());
- }
-
- public List<ExtendedRepository> extendedRepositories(String repositoryKey) {
- return ImmutableList.copyOf(extendedRepositoriesByKey.get(repositoryKey));
- }
-
- public List<ExtendedRepository> extendedRepositories() {
- return ImmutableList.copyOf(extendedRepositoriesByKey.values());
- }
-
- private void registerRepository(NewRepositoryImpl newRepository) {
- if (repositoriesByKey.containsKey(newRepository.key)) {
- throw new IllegalStateException(String.format("The rule repository '%s' is defined several times", newRepository.key));
- }
- repositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
- }
-
- private void registerExtendedRepository(NewRepositoryImpl newRepository) {
- extendedRepositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
- }
- }
-
- interface NewExtendedRepository {
- NewRule newRule(String ruleKey);
-
- /**
- * Reads definitions of rules from the annotations provided by the library sonar-check-api.
- */
- void 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 -->
- <configKey>Checker/TreeWalker/LocalVariableName</configKey>
- <severity>BLOCKER</severity>
- <cardinality>MULTIPLE</cardinality>
- <status>BETA</status>
- <param>
- <key>the-param-key</key>
- <description>
- <![CDATA[
- the param-description
- ]]>
- </description>
- <defaultValue>42</defaultValue>
- </param>
- <param>
- <key>another-param</key>
- </param>
-
- <!-- deprecated fields -->
- <priority>BLOCKER</priority>
- </rule>
- </rules>
-
- * </pre>
- */
- void loadXml(InputStream xmlInput, String encoding);
-
- void done();
- }
-
- interface NewRepository extends NewExtendedRepository {
- NewRepository setName(String s);
- }
-
- class NewRepositoryImpl implements NewRepository {
- private final Context context;
- private final boolean extended;
- private final String key;
- private String language;
- private String name;
- private final Map<String, NewRule> newRules = Maps.newHashMap();
-
- private NewRepositoryImpl(Context context, String key, String language, boolean extended) {
- this.extended = extended;
- this.context = context;
- this.key = this.name = key;
- this.language = language;
- }
-
- @Override
- public NewRepositoryImpl setName(@Nullable String s) {
- if (StringUtils.isNotEmpty(s)) {
- this.name = s;
- }
- return this;
- }
-
- @Override
- public NewRule newRule(String ruleKey) {
- if (newRules.containsKey(ruleKey)) {
- // Should fail in a perfect world, but at the time being the Findbugs plugin
- // defines several times the rule EC_INCOMPATIBLE_ARRAY_COMPARE
- // See http://jira.codehaus.org/browse/SONARJAVA-428
- LoggerFactory.getLogger(getClass()).warn(String.format("The rule '%s' of repository '%s' is declared several times", ruleKey, key));
- }
- NewRule newRule = new NewRule(key, ruleKey);
- newRules.put(ruleKey, newRule);
- return newRule;
- }
-
- @Override
- public void loadAnnotatedClasses(Class... classes) {
- new RuleDefinitionsFromAnnotations().loadRules(this, classes);
- }
-
- @Override
- public void loadXml(InputStream xmlInput, String encoding) {
- new RuleDefinitionsFromXml().loadRules(this, xmlInput, encoding);
- }
-
- @Override
- public void done() {
- // note that some validations can be done here, for example for
- // verifying that at least one rule is declared
-
- if (extended) {
- context.registerExtendedRepository(this);
- } else {
- context.registerRepository(this);
- }
- }
- }
-
- interface ExtendedRepository {
- String key();
-
- String language();
-
- @CheckForNull
- Rule rule(String ruleKey);
-
- List<Rule> rules();
- }
-
- interface Repository extends ExtendedRepository {
- String name();
- }
-
- class RepositoryImpl implements Repository {
- private final String key, language, name;
- private final Map<String, Rule> rulesByKey;
-
- private RepositoryImpl(NewRepositoryImpl newRepository) {
- this.key = newRepository.key;
- this.language = newRepository.language;
- this.name = newRepository.name;
- ImmutableMap.Builder<String, Rule> ruleBuilder = ImmutableMap.builder();
- for (NewRule newRule : newRepository.newRules.values()) {
- newRule.validate();
- ruleBuilder.put(newRule.key, new Rule(this, newRule));
- }
- this.rulesByKey = ruleBuilder.build();
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String language() {
- return language;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- @CheckForNull
- public Rule rule(String ruleKey) {
- return rulesByKey.get(ruleKey);
- }
-
- @Override
- public List<Rule> rules() {
- return ImmutableList.copyOf(rulesByKey.values());
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- RepositoryImpl that = (RepositoryImpl) o;
- return key.equals(that.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
- }
-
-
- class NewRule {
- private final String repoKey, key;
- private String name, htmlDescription, metadata, defaultSeverity = Severity.MAJOR;
- private boolean template;
- private Status status = Status.READY;
- private final Set<String> tags = Sets.newTreeSet();
- private final Map<String, NewParam> paramsByKey = Maps.newHashMap();
-
- private NewRule(String repoKey, String key) {
- this.repoKey = repoKey;
- this.key = key;
- }
-
- public NewRule setName(String s) {
- this.name = s;
- return this;
- }
-
- public NewRule setTemplate(boolean template) {
- this.template = template;
- return this;
- }
-
- public NewRule setDefaultSeverity(String s) {
- if (!Severity.ALL.contains(s)) {
- throw new IllegalArgumentException(String.format("Default severity of rule %s is not correct: %s", this, s));
- }
- this.defaultSeverity = s;
- return this;
- }
-
- public NewRule setHtmlDescription(String s) {
- this.htmlDescription = s;
- return this;
- }
-
- public NewRule setStatus(Status status) {
- this.status = status;
- return this;
- }
-
- public NewParam newParam(String paramKey) {
- if (paramsByKey.containsKey(paramKey)) {
- throw new IllegalArgumentException(String.format("The parameter '%s' is declared several times on the rule %s", paramKey, this));
- }
- NewParam param = new NewParam(paramKey);
- paramsByKey.put(paramKey, param);
- return param;
- }
-
- /**
- * @see org.sonar.api.rule.RuleTagFormat
- */
- public NewRule addTags(String... list) {
- for (String tag : list) {
- RuleTagFormat.validate(tag);
- tags.add(tag);
- }
- return this;
- }
-
- /**
- * @see org.sonar.api.rule.RuleTagFormat
- */
- public NewRule setTags(String... list) {
- tags.clear();
- addTags(list);
- return this;
- }
-
- /**
- * Optional metadata that can be used by the rule engine. Not displayed
- * in webapp. For example the Java Checkstyle plugin feeds this field
- * with the internal path ("Checker/TreeWalker/AnnotationUseStyle").
- */
- public NewRule setMetadata(@Nullable String s) {
- this.metadata = s;
- return this;
- }
-
- private void validate() {
- if (StringUtils.isBlank(name)) {
- throw new IllegalStateException(String.format("Name of rule %s is empty", this));
- }
- if (StringUtils.isBlank(htmlDescription)) {
- throw new IllegalStateException(String.format("HTML description of rule %s is empty", this));
- }
- }
-
- @Override
- public String toString() {
- return String.format("[repository=%s, key=%s]", repoKey, key);
- }
- }
-
- enum Status {
- BETA, DEPRECATED, READY
- }
-
- class Rule {
- private final Repository repository;
- private final String repoKey, key, name, htmlDescription, metadata, defaultSeverity;
- private final boolean template;
- private final Set<String> tags;
- private final Map<String, Param> params;
- private final Status status;
-
- private Rule(Repository repository, NewRule newRule) {
- this.repository = repository;
- this.repoKey = newRule.repoKey;
- this.key = newRule.key;
- this.name = newRule.name;
- this.htmlDescription = newRule.htmlDescription;
- this.metadata = newRule.metadata;
- this.defaultSeverity = newRule.defaultSeverity;
- this.template = newRule.template;
- this.status = newRule.status;
- this.tags = ImmutableSortedSet.copyOf(newRule.tags);
- ImmutableMap.Builder<String, Param> paramsBuilder = ImmutableMap.builder();
- for (NewParam newParam : newRule.paramsByKey.values()) {
- paramsBuilder.put(newParam.key, new Param(newParam));
- }
- this.params = paramsBuilder.build();
- }
-
- public Repository repository() {
- return repository;
- }
-
- public String key() {
- return key;
- }
-
- public String name() {
- return name;
- }
-
- public String defaultSeverity() {
- return defaultSeverity;
- }
-
- @CheckForNull
- public String htmlDescription() {
- return htmlDescription;
- }
-
- public boolean template() {
- return template;
- }
-
- public Status status() {
- return status;
- }
-
- @CheckForNull
- public Param param(String key) {
- return params.get(key);
- }
-
- public List<Param> params() {
- return ImmutableList.copyOf(params.values());
- }
-
- public Set<String> tags() {
- return tags;
- }
-
- /**
- * @see org.sonar.api.rule.RuleDefinitions.NewRule#setMetadata(String)
- */
- @CheckForNull
- public String metadata() {
- return metadata;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- Rule other = (Rule) o;
- return key.equals(other.key) && repoKey.equals(other.repoKey);
- }
-
- @Override
- public int hashCode() {
- int result = repoKey.hashCode();
- result = 31 * result + key.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return String.format("[repository=%s, key=%s]", repoKey, key);
- }
- }
-
-
- class NewParam {
- private final String key;
- private String name, description, defaultValue;
- private RuleParamType type = RuleParamType.STRING;
-
- private NewParam(String key) {
- this.key = this.name = key;
- }
-
- public NewParam setName(@Nullable String s) {
- // name must never be null.
- this.name = StringUtils.defaultIfBlank(s, key);
- return this;
- }
-
- public NewParam setType(RuleParamType t) {
- this.type = t;
- return this;
- }
-
- /**
- * Plain-text description. Can be null.
- */
- public NewParam setDescription(@Nullable String s) {
- this.description = StringUtils.defaultIfBlank(s, null);
- return this;
- }
-
- public NewParam setDefaultValue(@Nullable String s) {
- this.defaultValue = s;
- return this;
- }
- }
-
- class Param {
- private final String key, name, description, defaultValue;
- private final RuleParamType type;
-
- private Param(NewParam newParam) {
- this.key = newParam.key;
- this.name = newParam.name;
- this.description = newParam.description;
- this.defaultValue = newParam.defaultValue;
- this.type = newParam.type;
- }
-
- public String key() {
- return key;
- }
-
- public String name() {
- return name;
- }
-
- @Nullable
- public String description() {
- return description;
- }
-
- @Nullable
- public String defaultValue() {
- return defaultValue;
- }
-
- public RuleParamType type() {
- return type;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- Param that = (Param) o;
- return key.equals(that.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
- }
-
- /**
- * This method is executed when server is started.
- */
- void define(Context context);
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.collect.ImmutableMap;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.utils.AnnotationUtils;
-import org.sonar.api.utils.FieldUtils2;
-import org.sonar.check.Cardinality;
-
-import java.lang.reflect.Field;
-import java.util.List;
-
-/**
- * Read definitions of rules based on the annotations provided by sonar-check-api.
- * </p>
- * It is internally used by {@link org.sonar.api.rule.RuleDefinitions} and can't be directly
- * used by plugins.
- *
- * @since 4.2
- */
-class RuleDefinitionsFromAnnotations {
-
- private static final Logger LOG = LoggerFactory.getLogger(RuleDefinitionsFromAnnotations.class);
-
- void loadRules(RuleDefinitions.NewRepository repo, Class... annotatedClasses) {
- for (Class annotatedClass : annotatedClasses) {
- loadRule(repo, annotatedClass);
- }
- }
-
- private void loadRule(RuleDefinitions.NewRepository repo, Class clazz) {
- org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getAnnotation(clazz, org.sonar.check.Rule.class);
- if (ruleAnnotation != null) {
- loadRule(repo, clazz, ruleAnnotation);
- } else {
- LOG.warn("The class " + clazz.getCanonicalName() + " should be annotated with " + org.sonar.check.Rule.class);
- }
- }
-
- private void loadRule(RuleDefinitions.NewRepository repo, Class clazz, org.sonar.check.Rule ruleAnnotation) {
- String ruleKey = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName());
- String ruleName = StringUtils.defaultIfEmpty(ruleAnnotation.name(), null);
- String description = StringUtils.defaultIfEmpty(ruleAnnotation.description(), null);
-
- RuleDefinitions.NewRule rule = repo.newRule(ruleKey);
- rule.setName(ruleName).setHtmlDescription(description);
- rule.setDefaultSeverity(ruleAnnotation.priority().name());
- rule.setTemplate(ruleAnnotation.cardinality() == Cardinality.MULTIPLE);
- rule.setStatus(RuleDefinitions.Status.valueOf(ruleAnnotation.status()));
-
- List<Field> fields = FieldUtils2.getFields(clazz, true);
- for (Field field : fields) {
- loadParameters(rule, field);
- }
- }
-
- private void loadParameters(RuleDefinitions.NewRule rule, Field field) {
- org.sonar.check.RuleProperty propertyAnnotation = field.getAnnotation(org.sonar.check.RuleProperty.class);
- if (propertyAnnotation != null) {
- String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
- RuleDefinitions.NewParam param = rule.newParam(fieldKey)
- .setDescription(propertyAnnotation.description())
- .setDefaultValue(propertyAnnotation.defaultValue());
-
- if (!StringUtils.isBlank(propertyAnnotation.type())) {
- try {
- param.setType(RuleParamType.parse(propertyAnnotation.type().trim()));
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Invalid property type [" + propertyAnnotation.type() + "]", e);
- }
- } else {
- param.setType(guessType(field.getType()));
- }
- }
- }
-
- private static final Function<Class<?>, RuleParamType> TYPE_FOR_CLASS = Functions.forMap(
- ImmutableMap.<Class<?>, RuleParamType>builder()
- .put(Integer.class, RuleParamType.INTEGER)
- .put(int.class, RuleParamType.INTEGER)
- .put(Float.class, RuleParamType.FLOAT)
- .put(float.class, RuleParamType.FLOAT)
- .put(Boolean.class, RuleParamType.BOOLEAN)
- .put(boolean.class, RuleParamType.BOOLEAN)
- .build(),
- RuleParamType.STRING);
-
- @VisibleForTesting
- static RuleParamType guessType(Class<?> type) {
- return TYPE_FOR_CLASS.apply(type);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.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.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(RuleDefinitions.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(RuleDefinitions.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(RuleDefinitions.NewRepository repo, SMInputCursor ruleC) throws XMLStreamException {
- String key = null, name = null, description = null, metadata = null, severity = Severity.MAJOR, status = null;
- Cardinality cardinality = Cardinality.SINGLE;
- List<ParamStruct> params = new ArrayList<ParamStruct>();
-
- /* 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)) {
- metadata = 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));
- }
- }
- RuleDefinitions.NewRule rule = repo.newRule(key)
- .setHtmlDescription(description)
- .setDefaultSeverity(severity)
- .setName(name)
- .setMetadata(metadata)
- .setTemplate(cardinality == Cardinality.MULTIPLE);
- if (status != null) {
- rule.setStatus(RuleDefinitions.Status.valueOf(status));
- }
- for (ParamStruct param : params) {
- rule.newParam(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-2013 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.rule;
-
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.PropertyType;
-
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * @since 4.2
- */
-public final class RuleParamType {
-
- private static final String FIELD_SEPARATOR = "|";
- private static final String OPTION_SEPARATOR = ",";
-
- public static final RuleParamType STRING = new RuleParamType("STRING");
- public static final RuleParamType TEXT = new RuleParamType("TEXT");
- public static final RuleParamType BOOLEAN = new RuleParamType("BOOLEAN");
- public static final RuleParamType INTEGER = new RuleParamType("INTEGER");
- public static final RuleParamType FLOAT = new RuleParamType("FLOAT");
-
- private final String type;
- private final List<String> options;
-
- // format is "type|comma-separated list of options", for example "INTEGER" or "SINGLE_SELECT_LIST|foo=one,bar,baz=two"
- private final String key;
-
- private RuleParamType(String type, String... options) {
- this.type = type;
- this.options = newArrayList(options);
- StringBuilder sb = new StringBuilder();
- sb.append(type);
- if (options.length > 0) {
- sb.append(FIELD_SEPARATOR);
- for (String option : options) {
- sb.append(StringEscapeUtils.escapeCsv(option));
- sb.append(OPTION_SEPARATOR);
- }
- }
- this.key = sb.toString();
- }
-
- public String type() {
- return type;
- }
-
- public List<String> options() {
- return options;
- }
-
- public static RuleParamType ofValues(String... acceptedValues) {
- // reuse the same type as plugin properties in order to
- // benefit from shared helpers (validation, HTML component)
- String type = PropertyType.SINGLE_SELECT_LIST.name();
- return new RuleParamType(type, acceptedValues);
- }
-
- // TODO validate format
- public static RuleParamType parse(String s) {
- // deprecated formats
- if ("i".equals(s) || "i{}".equals(s)) {
- return INTEGER;
- }
- if ("s".equals(s) || "s{}".equals(s) || "r".equals(s) || "REGULAR_EXPRESSION".equals(s)) {
- return STRING;
- }
- if ("b".equals(s)) {
- return BOOLEAN;
- }
- if (s.startsWith("s[")) {
- String values = StringUtils.substringBetween(s, "[", "]");
- return ofValues(StringUtils.split(values, ','));
- }
-
- // standard format
- String format = StringUtils.substringBefore(s, FIELD_SEPARATOR);
- String options = StringUtils.substringAfter(s, FIELD_SEPARATOR);
- if (StringUtils.isBlank(options)) {
- return new RuleParamType(format);
- }
- return new RuleParamType(format, options.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"));
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- RuleParamType that = (RuleParamType) o;
- return key.equals(that.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
-
- @Override
- public String toString() {
- return key;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import org.apache.commons.lang.StringUtils;
-
-/**
- * @since 4.2
- */
-public class RuleTagFormat {
-
- // Allowed characters are the same as those on StackOverflow
- // see http://meta.stackoverflow.com/questions/22624/what-symbols-characters-are-not-allowed-in-tags
- private static final String VALID_CHARACTERS_REGEX = "^[a-z0-9\\+#\\-\\.]+$";
-
- private RuleTagFormat() {
- // only static methods
- }
-
- public static boolean isValid(String tag) {
- return StringUtils.isNotBlank(tag) && tag.matches(VALID_CHARACTERS_REGEX);
- }
-
- public static void validate(String tag) {
- if (!isValid(tag)) {
- throw new IllegalArgumentException(String.format("Whitespaces are not allowed in rule tags: '%s'", tag));
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.collect.*;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rule.Severity;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Defines the coding rules. For example the Java Findbugs plugin provides an implementation of
+ * this extension point in order to define the rules that it supports.
+ * <p/>
+ * This interface replaces the deprecated class org.sonar.api.rules.RuleRepository.
+ *
+ * @since 4.2
+ */
+public interface RuleDefinitions extends ServerExtension {
+
+ /**
+ * Instantiated by core but not by plugins
+ */
+ class Context {
+ private final Map<String, Repository> repositoriesByKey = Maps.newHashMap();
+ private final ListMultimap<String, ExtendedRepository> extendedRepositoriesByKey = ArrayListMultimap.create();
+
+ public NewRepository newRepository(String key, String language) {
+ return new NewRepositoryImpl(this, key, language, false);
+ }
+
+ public NewExtendedRepository extendRepository(String key, String language) {
+ return new NewRepositoryImpl(this, key, language, true);
+ }
+
+ @CheckForNull
+ public Repository repository(String key) {
+ return repositoriesByKey.get(key);
+ }
+
+ public List<Repository> repositories() {
+ return ImmutableList.copyOf(repositoriesByKey.values());
+ }
+
+ public List<ExtendedRepository> extendedRepositories(String repositoryKey) {
+ return ImmutableList.copyOf(extendedRepositoriesByKey.get(repositoryKey));
+ }
+
+ public List<ExtendedRepository> extendedRepositories() {
+ return ImmutableList.copyOf(extendedRepositoriesByKey.values());
+ }
+
+ private void registerRepository(NewRepositoryImpl newRepository) {
+ if (repositoriesByKey.containsKey(newRepository.key)) {
+ throw new IllegalStateException(String.format("The rule repository '%s' is defined several times", newRepository.key));
+ }
+ repositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
+ }
+
+ private void registerExtendedRepository(NewRepositoryImpl newRepository) {
+ extendedRepositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
+ }
+ }
+
+ interface NewExtendedRepository {
+ NewRule newRule(String ruleKey);
+
+ /**
+ * Reads definitions of rules from the annotations provided by the library sonar-check-api.
+ */
+ void 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 -->
+ <configKey>Checker/TreeWalker/LocalVariableName</configKey>
+ <severity>BLOCKER</severity>
+ <cardinality>MULTIPLE</cardinality>
+ <status>BETA</status>
+ <param>
+ <key>the-param-key</key>
+ <description>
+ <![CDATA[
+ the param-description
+ ]]>
+ </description>
+ <defaultValue>42</defaultValue>
+ </param>
+ <param>
+ <key>another-param</key>
+ </param>
+
+ <!-- deprecated fields -->
+ <priority>BLOCKER</priority>
+ </rule>
+ </rules>
+
+ * </pre>
+ */
+ void loadXml(InputStream xmlInput, String encoding);
+
+ void done();
+ }
+
+ interface NewRepository extends NewExtendedRepository {
+ NewRepository setName(String s);
+ }
+
+ class NewRepositoryImpl implements NewRepository {
+ private final Context context;
+ private final boolean extended;
+ private final String key;
+ private String language;
+ private String name;
+ private final Map<String, NewRule> newRules = Maps.newHashMap();
+
+ private NewRepositoryImpl(Context context, String key, String language, boolean extended) {
+ this.extended = extended;
+ this.context = context;
+ this.key = this.name = key;
+ this.language = language;
+ }
+
+ @Override
+ public NewRepositoryImpl setName(@Nullable String s) {
+ if (StringUtils.isNotEmpty(s)) {
+ this.name = s;
+ }
+ return this;
+ }
+
+ @Override
+ public NewRule newRule(String ruleKey) {
+ if (newRules.containsKey(ruleKey)) {
+ // Should fail in a perfect world, but at the time being the Findbugs plugin
+ // defines several times the rule EC_INCOMPATIBLE_ARRAY_COMPARE
+ // See http://jira.codehaus.org/browse/SONARJAVA-428
+ LoggerFactory.getLogger(getClass()).warn(String.format("The rule '%s' of repository '%s' is declared several times", ruleKey, key));
+ }
+ NewRule newRule = new NewRule(key, ruleKey);
+ newRules.put(ruleKey, newRule);
+ return newRule;
+ }
+
+ @Override
+ public void loadAnnotatedClasses(Class... classes) {
+ new RuleDefinitionsFromAnnotations().loadRules(this, classes);
+ }
+
+ @Override
+ public void loadXml(InputStream xmlInput, String encoding) {
+ new RuleDefinitionsFromXml().loadRules(this, xmlInput, encoding);
+ }
+
+ @Override
+ public void done() {
+ // note that some validations can be done here, for example for
+ // verifying that at least one rule is declared
+
+ if (extended) {
+ context.registerExtendedRepository(this);
+ } else {
+ context.registerRepository(this);
+ }
+ }
+ }
+
+ interface ExtendedRepository {
+ String key();
+
+ String language();
+
+ @CheckForNull
+ Rule rule(String ruleKey);
+
+ List<Rule> rules();
+ }
+
+ interface Repository extends ExtendedRepository {
+ String name();
+ }
+
+ class RepositoryImpl implements Repository {
+ private final String key, language, name;
+ private final Map<String, Rule> rulesByKey;
+
+ private RepositoryImpl(NewRepositoryImpl newRepository) {
+ this.key = newRepository.key;
+ this.language = newRepository.language;
+ this.name = newRepository.name;
+ ImmutableMap.Builder<String, Rule> ruleBuilder = ImmutableMap.builder();
+ for (NewRule newRule : newRepository.newRules.values()) {
+ newRule.validate();
+ ruleBuilder.put(newRule.key, new Rule(this, newRule));
+ }
+ this.rulesByKey = ruleBuilder.build();
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String language() {
+ return language;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ @CheckForNull
+ public Rule rule(String ruleKey) {
+ return rulesByKey.get(ruleKey);
+ }
+
+ @Override
+ public List<Rule> rules() {
+ return ImmutableList.copyOf(rulesByKey.values());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RepositoryImpl that = (RepositoryImpl) o;
+ return key.equals(that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+ }
+
+
+ class NewRule {
+ private final String repoKey, key;
+ private String name, htmlDescription, metadata, defaultSeverity = Severity.MAJOR;
+ private boolean template;
+ private Status status = Status.READY;
+ private final Set<String> tags = Sets.newTreeSet();
+ private final Map<String, NewParam> paramsByKey = Maps.newHashMap();
+
+ private NewRule(String repoKey, String key) {
+ this.repoKey = repoKey;
+ this.key = key;
+ }
+
+ public NewRule setName(String s) {
+ this.name = s;
+ return this;
+ }
+
+ public NewRule setTemplate(boolean template) {
+ this.template = template;
+ return this;
+ }
+
+ public NewRule setDefaultSeverity(String s) {
+ if (!Severity.ALL.contains(s)) {
+ throw new IllegalArgumentException(String.format("Default severity of rule %s is not correct: %s", this, s));
+ }
+ this.defaultSeverity = s;
+ return this;
+ }
+
+ public NewRule setHtmlDescription(String s) {
+ this.htmlDescription = s;
+ return this;
+ }
+
+ public NewRule setStatus(Status status) {
+ this.status = status;
+ return this;
+ }
+
+ public NewParam newParam(String paramKey) {
+ if (paramsByKey.containsKey(paramKey)) {
+ throw new IllegalArgumentException(String.format("The parameter '%s' is declared several times on the rule %s", paramKey, this));
+ }
+ NewParam param = new NewParam(paramKey);
+ paramsByKey.put(paramKey, param);
+ return param;
+ }
+
+ /**
+ * @see RuleTagFormat
+ */
+ public NewRule addTags(String... list) {
+ for (String tag : list) {
+ RuleTagFormat.validate(tag);
+ tags.add(tag);
+ }
+ return this;
+ }
+
+ /**
+ * @see RuleTagFormat
+ */
+ public NewRule setTags(String... list) {
+ tags.clear();
+ addTags(list);
+ return this;
+ }
+
+ /**
+ * Optional metadata that can be used by the rule engine. Not displayed
+ * in webapp. For example the Java Checkstyle plugin feeds this field
+ * with the internal path ("Checker/TreeWalker/AnnotationUseStyle").
+ */
+ public NewRule setMetadata(@Nullable String s) {
+ this.metadata = s;
+ return this;
+ }
+
+ private void validate() {
+ if (StringUtils.isBlank(name)) {
+ throw new IllegalStateException(String.format("Name of rule %s is empty", this));
+ }
+ if (StringUtils.isBlank(htmlDescription)) {
+ throw new IllegalStateException(String.format("HTML description of rule %s is empty", this));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[repository=%s, key=%s]", repoKey, key);
+ }
+ }
+
+ enum Status {
+ BETA, DEPRECATED, READY
+ }
+
+ class Rule {
+ private final Repository repository;
+ private final String repoKey, key, name, htmlDescription, metadata, defaultSeverity;
+ private final boolean template;
+ private final Set<String> tags;
+ private final Map<String, Param> params;
+ private final Status status;
+
+ private Rule(Repository repository, NewRule newRule) {
+ this.repository = repository;
+ this.repoKey = newRule.repoKey;
+ this.key = newRule.key;
+ this.name = newRule.name;
+ this.htmlDescription = newRule.htmlDescription;
+ this.metadata = newRule.metadata;
+ this.defaultSeverity = newRule.defaultSeverity;
+ this.template = newRule.template;
+ this.status = newRule.status;
+ this.tags = ImmutableSortedSet.copyOf(newRule.tags);
+ ImmutableMap.Builder<String, Param> paramsBuilder = ImmutableMap.builder();
+ for (NewParam newParam : newRule.paramsByKey.values()) {
+ paramsBuilder.put(newParam.key, new Param(newParam));
+ }
+ this.params = paramsBuilder.build();
+ }
+
+ public Repository repository() {
+ return repository;
+ }
+
+ public String key() {
+ return key;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String defaultSeverity() {
+ return defaultSeverity;
+ }
+
+ @CheckForNull
+ public String htmlDescription() {
+ return htmlDescription;
+ }
+
+ public boolean template() {
+ return template;
+ }
+
+ public Status status() {
+ return status;
+ }
+
+ @CheckForNull
+ public Param param(String key) {
+ return params.get(key);
+ }
+
+ public List<Param> params() {
+ return ImmutableList.copyOf(params.values());
+ }
+
+ public Set<String> tags() {
+ return tags;
+ }
+
+ /**
+ * @see RuleDefinitions.NewRule#setMetadata(String)
+ */
+ @CheckForNull
+ public String metadata() {
+ return metadata;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Rule other = (Rule) o;
+ return key.equals(other.key) && repoKey.equals(other.repoKey);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = repoKey.hashCode();
+ result = 31 * result + key.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[repository=%s, key=%s]", repoKey, key);
+ }
+ }
+
+
+ class NewParam {
+ private final String key;
+ private String name, description, defaultValue;
+ private RuleParamType type = RuleParamType.STRING;
+
+ private NewParam(String key) {
+ this.key = this.name = key;
+ }
+
+ public NewParam setName(@Nullable String s) {
+ // name must never be null.
+ this.name = StringUtils.defaultIfBlank(s, key);
+ return this;
+ }
+
+ public NewParam setType(RuleParamType t) {
+ this.type = t;
+ return this;
+ }
+
+ /**
+ * Plain-text description. Can be null.
+ */
+ public NewParam setDescription(@Nullable String s) {
+ this.description = StringUtils.defaultIfBlank(s, null);
+ return this;
+ }
+
+ public NewParam setDefaultValue(@Nullable String s) {
+ this.defaultValue = s;
+ return this;
+ }
+ }
+
+ class Param {
+ private final String key, name, description, defaultValue;
+ private final RuleParamType type;
+
+ private Param(NewParam newParam) {
+ this.key = newParam.key;
+ this.name = newParam.name;
+ this.description = newParam.description;
+ this.defaultValue = newParam.defaultValue;
+ this.type = newParam.type;
+ }
+
+ public String key() {
+ return key;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ @Nullable
+ public String description() {
+ return description;
+ }
+
+ @Nullable
+ public String defaultValue() {
+ return defaultValue;
+ }
+
+ public RuleParamType type() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Param that = (Param) o;
+ return key.equals(that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+ }
+
+ /**
+ * This method is executed when server is started.
+ */
+ void define(Context context);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.AnnotationUtils;
+import org.sonar.api.utils.FieldUtils2;
+import org.sonar.check.Cardinality;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * Read definitions of rules based on the annotations provided by sonar-check-api.
+ * </p>
+ * It is internally used by {@link RuleDefinitions} and can't be directly
+ * used by plugins.
+ *
+ * @since 4.2
+ */
+class RuleDefinitionsFromAnnotations {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RuleDefinitionsFromAnnotations.class);
+
+ void loadRules(RuleDefinitions.NewRepository repo, Class... annotatedClasses) {
+ for (Class annotatedClass : annotatedClasses) {
+ loadRule(repo, annotatedClass);
+ }
+ }
+
+ private void loadRule(RuleDefinitions.NewRepository repo, Class clazz) {
+ org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getAnnotation(clazz, org.sonar.check.Rule.class);
+ if (ruleAnnotation != null) {
+ loadRule(repo, clazz, ruleAnnotation);
+ } else {
+ LOG.warn("The class " + clazz.getCanonicalName() + " should be annotated with " + org.sonar.check.Rule.class);
+ }
+ }
+
+ private void loadRule(RuleDefinitions.NewRepository repo, Class clazz, org.sonar.check.Rule ruleAnnotation) {
+ String ruleKey = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName());
+ String ruleName = StringUtils.defaultIfEmpty(ruleAnnotation.name(), null);
+ String description = StringUtils.defaultIfEmpty(ruleAnnotation.description(), null);
+
+ RuleDefinitions.NewRule rule = repo.newRule(ruleKey);
+ rule.setName(ruleName).setHtmlDescription(description);
+ rule.setDefaultSeverity(ruleAnnotation.priority().name());
+ rule.setTemplate(ruleAnnotation.cardinality() == Cardinality.MULTIPLE);
+ rule.setStatus(RuleDefinitions.Status.valueOf(ruleAnnotation.status()));
+
+ List<Field> fields = FieldUtils2.getFields(clazz, true);
+ for (Field field : fields) {
+ loadParameters(rule, field);
+ }
+ }
+
+ private void loadParameters(RuleDefinitions.NewRule rule, Field field) {
+ org.sonar.check.RuleProperty propertyAnnotation = field.getAnnotation(org.sonar.check.RuleProperty.class);
+ if (propertyAnnotation != null) {
+ String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
+ RuleDefinitions.NewParam param = rule.newParam(fieldKey)
+ .setDescription(propertyAnnotation.description())
+ .setDefaultValue(propertyAnnotation.defaultValue());
+
+ if (!StringUtils.isBlank(propertyAnnotation.type())) {
+ try {
+ param.setType(RuleParamType.parse(propertyAnnotation.type().trim()));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid property type [" + propertyAnnotation.type() + "]", e);
+ }
+ } else {
+ param.setType(guessType(field.getType()));
+ }
+ }
+ }
+
+ private static final Function<Class<?>, RuleParamType> TYPE_FOR_CLASS = Functions.forMap(
+ ImmutableMap.<Class<?>, RuleParamType>builder()
+ .put(Integer.class, RuleParamType.INTEGER)
+ .put(int.class, RuleParamType.INTEGER)
+ .put(Float.class, RuleParamType.FLOAT)
+ .put(float.class, RuleParamType.FLOAT)
+ .put(Boolean.class, RuleParamType.BOOLEAN)
+ .put(boolean.class, RuleParamType.BOOLEAN)
+ .build(),
+ RuleParamType.STRING);
+
+ @VisibleForTesting
+ static RuleParamType guessType(Class<?> type) {
+ return TYPE_FOR_CLASS.apply(type);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.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(RuleDefinitions.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(RuleDefinitions.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(RuleDefinitions.NewRepository repo, SMInputCursor ruleC) throws XMLStreamException {
+ String key = null, name = null, description = null, metadata = null, severity = Severity.MAJOR, status = null;
+ Cardinality cardinality = Cardinality.SINGLE;
+ List<ParamStruct> params = new ArrayList<ParamStruct>();
+
+ /* 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)) {
+ metadata = 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));
+ }
+ }
+ RuleDefinitions.NewRule rule = repo.newRule(key)
+ .setHtmlDescription(description)
+ .setDefaultSeverity(severity)
+ .setName(name)
+ .setMetadata(metadata)
+ .setTemplate(cardinality == Cardinality.MULTIPLE);
+ if (status != null) {
+ rule.setStatus(RuleDefinitions.Status.valueOf(status));
+ }
+ for (ParamStruct param : params) {
+ rule.newParam(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-2013 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 org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.PropertyType;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * @since 4.2
+ */
+public final class RuleParamType {
+
+ private static final String FIELD_SEPARATOR = "|";
+ private static final String OPTION_SEPARATOR = ",";
+
+ public static final RuleParamType STRING = new RuleParamType("STRING");
+ public static final RuleParamType TEXT = new RuleParamType("TEXT");
+ public static final RuleParamType BOOLEAN = new RuleParamType("BOOLEAN");
+ public static final RuleParamType INTEGER = new RuleParamType("INTEGER");
+ public static final RuleParamType FLOAT = new RuleParamType("FLOAT");
+
+ private final String type;
+ private final List<String> options;
+
+ // format is "type|comma-separated list of options", for example "INTEGER" or "SINGLE_SELECT_LIST|foo=one,bar,baz=two"
+ private final String key;
+
+ private RuleParamType(String type, String... options) {
+ this.type = type;
+ this.options = newArrayList(options);
+ StringBuilder sb = new StringBuilder();
+ sb.append(type);
+ if (options.length > 0) {
+ sb.append(FIELD_SEPARATOR);
+ for (String option : options) {
+ sb.append(StringEscapeUtils.escapeCsv(option));
+ sb.append(OPTION_SEPARATOR);
+ }
+ }
+ this.key = sb.toString();
+ }
+
+ public String type() {
+ return type;
+ }
+
+ public List<String> options() {
+ return options;
+ }
+
+ public static RuleParamType ofValues(String... acceptedValues) {
+ // reuse the same type as plugin properties in order to
+ // benefit from shared helpers (validation, HTML component)
+ String type = PropertyType.SINGLE_SELECT_LIST.name();
+ return new RuleParamType(type, acceptedValues);
+ }
+
+ // TODO validate format
+ public static RuleParamType parse(String s) {
+ // deprecated formats
+ if ("i".equals(s) || "i{}".equals(s)) {
+ return INTEGER;
+ }
+ if ("s".equals(s) || "s{}".equals(s) || "r".equals(s) || "REGULAR_EXPRESSION".equals(s)) {
+ return STRING;
+ }
+ if ("b".equals(s)) {
+ return BOOLEAN;
+ }
+ if (s.startsWith("s[")) {
+ String values = StringUtils.substringBetween(s, "[", "]");
+ return ofValues(StringUtils.split(values, ','));
+ }
+
+ // standard format
+ String format = StringUtils.substringBefore(s, FIELD_SEPARATOR);
+ String options = StringUtils.substringAfter(s, FIELD_SEPARATOR);
+ if (StringUtils.isBlank(options)) {
+ return new RuleParamType(format);
+ }
+ return new RuleParamType(format, options.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ RuleParamType that = (RuleParamType) o;
+ return key.equals(that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return key;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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 org.apache.commons.lang.StringUtils;
+
+/**
+ * @since 4.2
+ */
+public class RuleTagFormat {
+
+ // Allowed characters are the same as those on StackOverflow
+ // see http://meta.stackoverflow.com/questions/22624/what-symbols-characters-are-not-allowed-in-tags
+ private static final String VALID_CHARACTERS_REGEX = "^[a-z0-9\\+#\\-\\.]+$";
+
+ private RuleTagFormat() {
+ // only static methods
+ }
+
+ public static boolean isValid(String tag) {
+ return StringUtils.isNotBlank(tag) && tag.matches(VALID_CHARACTERS_REGEX);
+ }
+
+ public static void validate(String tag) {
+ if (!isValid(tag)) {
+ throw new IllegalArgumentException(String.format("Whitespaces are not allowed in rule tags: '%s'", tag));
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.server.rule;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * @since 4.2
+ */
+public abstract class Request {
+
+ @CheckForNull
+ public abstract String param(String key);
+
+ public abstract String mediaType();
+
+ public abstract boolean isPost();
+
+ @CheckForNull
+ public Integer intParam(String key) {
+ String s = param(key);
+ return s == null ? null : Integer.parseInt(s);
+ }
+
+ public int intParam(String key, int defaultValue) {
+ String s = param(key);
+ return s == null ? defaultValue : Integer.parseInt(s);
+ }
+
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import org.sonar.api.ServerExtension;
+
+/**
+ * @since 4.2
+ */
+public interface RequestHandler extends ServerExtension {
+
+ void handle(Request request, Response response) throws Exception;
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.utils.text.XmlWriter;
+
+import java.io.OutputStream;
+import java.io.Writer;
+
+/**
+ * HTTP response
+ *
+ * @since 4.2
+ */
+public interface Response {
+
+ int status();
+
+ Response setStatus(int httpStatus);
+
+ JsonWriter newJsonWriter();
+
+ XmlWriter newXmlWriter();
+
+ OutputStream output();
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import com.google.common.collect.Maps;
+
+import javax.annotation.CheckForNull;
+import java.util.Map;
+
+public class SimpleRequest extends Request {
+ private Map<String, String> params = Maps.newHashMap();
+
+ private String mediaType = "application/json";
+ private boolean post = false;
+
+ public SimpleRequest() {
+ }
+
+ public SimpleRequest setParams(Map<String, String> m) {
+ this.params = m;
+ return this;
+ }
+
+ public SimpleRequest setParams(String key, String value) {
+ this.params.put(key, value);
+ return this;
+ }
+
+ @Override
+ @CheckForNull
+ public String param(String key) {
+ return params.get(key);
+ }
+
+ @Override
+ public String mediaType() {
+ return mediaType;
+ }
+
+ public SimpleRequest setMediaType(String s) {
+ this.mediaType = s;
+ return this;
+ }
+
+ @Override
+ public boolean isPost() {
+ return post;
+ }
+
+ public SimpleRequest setPost(boolean b) {
+ this.post = b;
+ return this;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import org.apache.commons.io.Charsets;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.utils.text.XmlWriter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+public class SimpleResponse implements Response {
+ private int httpStatus = 200;
+ private final ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+ @Override
+ public JsonWriter newJsonWriter() {
+ return JsonWriter.of(new OutputStreamWriter(output, Charsets.UTF_8));
+ }
+
+ @Override
+ public XmlWriter newXmlWriter() {
+ return XmlWriter.of(new OutputStreamWriter(output, Charsets.UTF_8));
+ }
+
+ @Override
+ public OutputStream output() {
+ return output;
+ }
+
+ // for unit testing
+ public String outputAsString() {
+ return new String(output.toByteArray(), Charsets.UTF_8);
+ }
+
+ @Override
+ public int status() {
+ return httpStatus;
+ }
+
+ @Override
+ public Response setStatus(int httpStatus) {
+ this.httpStatus = httpStatus;
+ return this;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.ServerExtension;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @since 4.2
+ */
+public interface WebService extends ServerExtension {
+
+ class Context {
+ private final Map<String, Controller> controllers = Maps.newHashMap();
+
+ public NewController newController(String path) {
+ return new NewController(this, path);
+ }
+
+ private void register(NewController newController) {
+ if (controllers.containsKey(newController.path)) {
+ throw new IllegalStateException(
+ String.format("The web service '%s' is defined multiple times", newController.path)
+ );
+ }
+ controllers.put(newController.path, new Controller(newController));
+ }
+
+ @CheckForNull
+ public Controller controller(String key) {
+ return controllers.get(key);
+ }
+
+ public List<Controller> controllers() {
+ return ImmutableList.copyOf(controllers.values());
+ }
+ }
+
+ class NewController {
+ private final Context context;
+ private final String path;
+ private String description, since;
+ private final Map<String, NewAction> actions = Maps.newHashMap();
+
+ private NewController(Context context, String path) {
+ if (StringUtils.isBlank(path)) {
+ throw new IllegalArgumentException("Web service path can't be empty");
+ }
+ this.context = context;
+ this.path = path;
+ }
+
+ public void done() {
+ context.register(this);
+ }
+
+ public NewController setDescription(@Nullable String s) {
+ this.description = s;
+ return this;
+ }
+
+ public NewController setSince(@Nullable String s) {
+ this.since = s;
+ return this;
+ }
+
+ public NewAction newAction(String actionKey) {
+ if (actions.containsKey(actionKey)) {
+ throw new IllegalStateException(
+ String.format("The action '%s' is defined multiple times in the web service '%s'", actionKey, path)
+ );
+ }
+ NewAction action = new NewAction(actionKey);
+ actions.put(actionKey, action);
+ return action;
+ }
+ }
+
+ class Controller {
+ private final String path, description, since;
+ private final Map<String, Action> actions;
+
+ private Controller(NewController newController) {
+ if (newController.actions.isEmpty()) {
+ throw new IllegalStateException(
+ String.format("At least one action must be declared in the web service '%s'", newController.path)
+ );
+ }
+ this.path = newController.path;
+ this.description = newController.description;
+ this.since = newController.since;
+ ImmutableMap.Builder<String, Action> mapBuilder = ImmutableMap.builder();
+ for (NewAction newAction : newController.actions.values()) {
+ mapBuilder.put(newAction.key, new Action(this, newAction));
+ }
+ this.actions = mapBuilder.build();
+ }
+
+ public String path() {
+ return path;
+ }
+
+ @CheckForNull
+ public String description() {
+ return description;
+ }
+
+ public boolean isApi() {
+ return path.startsWith("api/");
+ }
+
+ @CheckForNull
+ public String since() {
+ return since;
+ }
+
+ @CheckForNull
+ public Action action(String actionKey) {
+ return actions.get(actionKey);
+ }
+
+ public Collection<Action> actions() {
+ return actions.values();
+ }
+ }
+
+ // TODO define supported parameters
+ class NewAction {
+ private final String key;
+ private String description, since;
+ private boolean post = false;
+ private RequestHandler handler;
+
+ private NewAction(String key) {
+ this.key = key;
+ }
+
+ public NewAction setDescription(@Nullable String s) {
+ this.description = s;
+ return this;
+ }
+
+ public NewAction setSince(@Nullable String s) {
+ this.since = s;
+ return this;
+ }
+
+ public NewAction setPost(boolean b) {
+ this.post = b;
+ return this;
+ }
+
+ public NewAction setHandler(RequestHandler h) {
+ this.handler = h;
+ return this;
+ }
+ }
+
+ class Action {
+ private final String key, path, description, since;
+ private final boolean post;
+ private final RequestHandler handler;
+
+ private Action(Controller controller, NewAction newAction) {
+ this.key = newAction.key;
+ this.path = String.format("%s/%s", controller.path(), key);
+ this.description = newAction.description;
+ this.since = StringUtils.defaultIfBlank(newAction.since, controller.since);
+ this.post = newAction.post;
+ if (newAction.handler == null) {
+ throw new IllegalStateException("RequestHandler is not set on action " + path);
+ }
+ this.handler = newAction.handler;
+ }
+
+ public String key() {
+ return key;
+ }
+
+ public String path() {
+ return path;
+ }
+
+ @CheckForNull
+ public String description() {
+ return description;
+ }
+
+ /**
+ * Set if different than controller.
+ */
+ @CheckForNull
+ public String since() {
+ return since;
+ }
+
+ public boolean isPost() {
+ return post;
+ }
+
+ public RequestHandler handler() {
+ return handler;
+ }
+
+ @Override
+ public String toString() {
+ return path;
+ }
+ }
+
+ /**
+ * Executed at server startup.
+ */
+ void define(Context context);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.server.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import javax.annotation.CheckForNull;
-
-/**
- * @since 4.2
- */
-public abstract class Request {
-
- @CheckForNull
- public abstract String param(String key);
-
- public abstract String mediaType();
-
- public abstract boolean isPost();
-
- @CheckForNull
- public Integer intParam(String key) {
- String s = param(key);
- return s == null ? null : Integer.parseInt(s);
- }
-
- public int intParam(String key, int defaultValue) {
- String s = param(key);
- return s == null ? defaultValue : Integer.parseInt(s);
- }
-
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import org.sonar.api.ServerExtension;
-
-/**
- * @since 4.2
- */
-public interface RequestHandler extends ServerExtension {
-
- void handle(Request request, Response response) throws Exception;
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.utils.text.XmlWriter;
-
-import java.io.OutputStream;
-import java.io.Writer;
-
-/**
- * HTTP response
- *
- * @since 4.2
- */
-public interface Response {
-
- int status();
-
- Response setStatus(int httpStatus);
-
- JsonWriter newJsonWriter();
-
- XmlWriter newXmlWriter();
-
- OutputStream output();
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import com.google.common.collect.Maps;
-
-import javax.annotation.CheckForNull;
-import java.util.Map;
-
-public class SimpleRequest extends Request {
- private Map<String, String> params = Maps.newHashMap();
-
- private String mediaType = "application/json";
- private boolean post = false;
-
- public SimpleRequest() {
- }
-
- public SimpleRequest setParams(Map<String, String> m) {
- this.params = m;
- return this;
- }
-
- public SimpleRequest setParams(String key, String value) {
- this.params.put(key, value);
- return this;
- }
-
- @Override
- @CheckForNull
- public String param(String key) {
- return params.get(key);
- }
-
- @Override
- public String mediaType() {
- return mediaType;
- }
-
- public SimpleRequest setMediaType(String s) {
- this.mediaType = s;
- return this;
- }
-
- @Override
- public boolean isPost() {
- return post;
- }
-
- public SimpleRequest setPost(boolean b) {
- this.post = b;
- return this;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import org.apache.commons.io.Charsets;
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.utils.text.XmlWriter;
-
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-
-public class SimpleResponse implements Response {
- private int httpStatus = 200;
- private final ByteArrayOutputStream output = new ByteArrayOutputStream();
-
- @Override
- public JsonWriter newJsonWriter() {
- return JsonWriter.of(new OutputStreamWriter(output, Charsets.UTF_8));
- }
-
- @Override
- public XmlWriter newXmlWriter() {
- return XmlWriter.of(new OutputStreamWriter(output, Charsets.UTF_8));
- }
-
- @Override
- public OutputStream output() {
- return output;
- }
-
- // for unit testing
- public String outputAsString() {
- return new String(output.toByteArray(), Charsets.UTF_8);
- }
-
- @Override
- public int status() {
- return httpStatus;
- }
-
- @Override
- public Response setStatus(int httpStatus) {
- this.httpStatus = httpStatus;
- return this;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.ServerExtension;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @since 4.2
- */
-public interface WebService extends ServerExtension {
-
- class Context {
- private final Map<String, Controller> controllers = Maps.newHashMap();
-
- public NewController newController(String path) {
- return new NewController(this, path);
- }
-
- private void register(NewController newController) {
- if (controllers.containsKey(newController.path)) {
- throw new IllegalStateException(
- String.format("The web service '%s' is defined multiple times", newController.path)
- );
- }
- controllers.put(newController.path, new Controller(newController));
- }
-
- @CheckForNull
- public Controller controller(String key) {
- return controllers.get(key);
- }
-
- public List<Controller> controllers() {
- return ImmutableList.copyOf(controllers.values());
- }
- }
-
- class NewController {
- private final Context context;
- private final String path;
- private String description, since;
- private final Map<String, NewAction> actions = Maps.newHashMap();
-
- private NewController(Context context, String path) {
- if (StringUtils.isBlank(path)) {
- throw new IllegalArgumentException("Web service path can't be empty");
- }
- this.context = context;
- this.path = path;
- }
-
- public void done() {
- context.register(this);
- }
-
- public NewController setDescription(@Nullable String s) {
- this.description = s;
- return this;
- }
-
- public NewController setSince(@Nullable String s) {
- this.since = s;
- return this;
- }
-
- public NewAction newAction(String actionKey) {
- if (actions.containsKey(actionKey)) {
- throw new IllegalStateException(
- String.format("The action '%s' is defined multiple times in the web service '%s'", actionKey, path)
- );
- }
- NewAction action = new NewAction(actionKey);
- actions.put(actionKey, action);
- return action;
- }
- }
-
- class Controller {
- private final String path, description, since;
- private final Map<String, Action> actions;
-
- private Controller(NewController newController) {
- if (newController.actions.isEmpty()) {
- throw new IllegalStateException(
- String.format("At least one action must be declared in the web service '%s'", newController.path)
- );
- }
- this.path = newController.path;
- this.description = newController.description;
- this.since = newController.since;
- ImmutableMap.Builder<String, Action> mapBuilder = ImmutableMap.builder();
- for (NewAction newAction : newController.actions.values()) {
- mapBuilder.put(newAction.key, new Action(this, newAction));
- }
- this.actions = mapBuilder.build();
- }
-
- public String path() {
- return path;
- }
-
- @CheckForNull
- public String description() {
- return description;
- }
-
- public boolean isApi() {
- return path.startsWith("api/");
- }
-
- @CheckForNull
- public String since() {
- return since;
- }
-
- @CheckForNull
- public Action action(String actionKey) {
- return actions.get(actionKey);
- }
-
- public Collection<Action> actions() {
- return actions.values();
- }
- }
-
- // TODO define supported parameters
- class NewAction {
- private final String key;
- private String description, since;
- private boolean post = false;
- private RequestHandler handler;
-
- private NewAction(String key) {
- this.key = key;
- }
-
- public NewAction setDescription(@Nullable String s) {
- this.description = s;
- return this;
- }
-
- public NewAction setSince(@Nullable String s) {
- this.since = s;
- return this;
- }
-
- public NewAction setPost(boolean b) {
- this.post = b;
- return this;
- }
-
- public NewAction setHandler(RequestHandler h) {
- this.handler = h;
- return this;
- }
- }
-
- class Action {
- private final String key, path, description, since;
- private final boolean post;
- private final RequestHandler handler;
-
- private Action(Controller controller, NewAction newAction) {
- this.key = newAction.key;
- this.path = String.format("%s/%s", controller.path(), key);
- this.description = newAction.description;
- this.since = StringUtils.defaultIfBlank(newAction.since, controller.since);
- this.post = newAction.post;
- if (newAction.handler == null) {
- throw new IllegalStateException("RequestHandler is not set on action " + path);
- }
- this.handler = newAction.handler;
- }
-
- public String key() {
- return key;
- }
-
- public String path() {
- return path;
- }
-
- @CheckForNull
- public String description() {
- return description;
- }
-
- /**
- * Set if different than controller.
- */
- @CheckForNull
- public String since() {
- return since;
- }
-
- public boolean isPost() {
- return post;
- }
-
- public RequestHandler handler() {
- return handler;
- }
-
- @Override
- public String toString() {
- return path;
- }
- }
-
- /**
- * Executed at server startup.
- */
- void define(Context context);
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.web.ws;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.check.Priority;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RuleDefinitionsFromAnnotationsTest {
-
- @org.junit.Rule
- public final ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void rule_with_property() {
- RuleDefinitions.Repository repository = load(RuleWithProperty.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("foo");
- assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
- assertThat(rule.name()).isEqualTo("bar");
- assertThat(rule.htmlDescription()).isEqualTo("Foo Bar");
- assertThat(rule.defaultSeverity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
- assertThat(rule.params()).hasSize(1);
-
- RuleDefinitions.Param prop = rule.param("property");
- assertThat(prop.key()).isEqualTo("property");
- assertThat(prop.description()).isEqualTo("Ignore ?");
- assertThat(prop.defaultValue()).isEqualTo("false");
- assertThat(prop.type()).isEqualTo(RuleParamType.STRING);
- }
-
- @Test
- public void rule_with_integer_property() {
- RuleDefinitions.Repository repository = load(RuleWithIntegerProperty.class);
-
- RuleDefinitions.Param prop = repository.rules().get(0).param("property");
- assertThat(prop.description()).isEqualTo("Max");
- assertThat(prop.defaultValue()).isEqualTo("12");
- assertThat(prop.type()).isEqualTo(RuleParamType.INTEGER);
- }
-
- @Test
- public void rule_with_text_property() {
- RuleDefinitions.Repository repository = load(RuleWithTextProperty.class);
-
- RuleDefinitions.Param prop = repository.rules().get(0).param("property");
- assertThat(prop.description()).isEqualTo("text");
- assertThat(prop.defaultValue()).isEqualTo("Long text");
- assertThat(prop.type()).isEqualTo(RuleParamType.TEXT);
- }
-
- @Test
- @Ignore("TODO list supported types in RuleParamType")
- public void should_reject_invalid_property_types() {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Invalid property type [INVALID]");
-
- load(RuleWithInvalidPropertyType.class);
- }
-
- @Test
- public void should_recognize_type() {
- assertThat(RuleDefinitionsFromAnnotations.guessType(Integer.class)).isEqualTo(RuleParamType.INTEGER);
- assertThat(RuleDefinitionsFromAnnotations.guessType(int.class)).isEqualTo(RuleParamType.INTEGER);
- assertThat(RuleDefinitionsFromAnnotations.guessType(Float.class)).isEqualTo(RuleParamType.FLOAT);
- assertThat(RuleDefinitionsFromAnnotations.guessType(float.class)).isEqualTo(RuleParamType.FLOAT);
- assertThat(RuleDefinitionsFromAnnotations.guessType(Boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
- assertThat(RuleDefinitionsFromAnnotations.guessType(boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
- assertThat(RuleDefinitionsFromAnnotations.guessType(String.class)).isEqualTo(RuleParamType.STRING);
- assertThat(RuleDefinitionsFromAnnotations.guessType(Object.class)).isEqualTo(RuleParamType.STRING);
- }
-
- @Test
- public void use_classname_when_missing_key() {
- RuleDefinitions.Repository repository = load(RuleWithoutKey.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo(RuleWithoutKey.class.getCanonicalName());
- assertThat(rule.name()).isEqualTo("foo");
- }
-
- @Test
- public void overridden_class() {
- RuleDefinitions.Repository repository = load(OverridingRule.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("overriding_foo");
- assertThat(rule.name()).isEqualTo("Overriding Foo");
- assertThat(rule.defaultSeverity()).isEqualTo(Severity.MAJOR);
- assertThat(rule.htmlDescription()).isEqualTo("Desc of Overriding Foo");
- assertThat(rule.params()).hasSize(2);
- }
-
- private RuleDefinitions.Repository load(Class annotatedClass) {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleDefinitions.NewRepository newRepository = context.newRepository("squid", "java");
- new RuleDefinitionsFromAnnotations().loadRules(newRepository, annotatedClass);
- newRepository.done();
- return context.repository("squid");
- }
-
- @org.sonar.check.Rule(name = "foo", description = "Foo")
- static class RuleWithoutKey {
- }
-
- @org.sonar.check.Rule(key = "foo")
- static class RuleWithoutNameNorDescription {
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER, status="BETA")
- static class RuleWithProperty {
- @org.sonar.check.RuleProperty(description = "Ignore ?", defaultValue = "false")
- private String property;
- }
-
- @org.sonar.check.Rule(key = "overriding_foo", name = "Overriding Foo", description = "Desc of Overriding Foo")
- static class OverridingRule extends RuleWithProperty {
- @org.sonar.check.RuleProperty
- private String additionalProperty;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
- static class RuleWithIntegerProperty {
- @org.sonar.check.RuleProperty(description = "Max", defaultValue = "12")
- private Integer property;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
- static class RuleWithTextProperty {
- @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "TEXT")
- protected String property;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
- static class RuleWithInvalidPropertyType {
- @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "INVALID")
- public String property;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import com.google.common.base.Charsets;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-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 RuleDefinitionsFromXmlTest {
-
- @org.junit.Rule
- public final ExpectedException thrown = ExpectedException.none();
-
- private RuleDefinitions.Repository load(Reader reader) {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleDefinitions.NewRepository newRepository = context.newRepository("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/rule/RuleDefinitionsFromXmlTest/rules.xml"), Charsets.UTF_8.name());
- RuleDefinitions.Repository repository = load(reader);
- assertThat(repository.rules()).hasSize(2);
-
- RuleDefinitions.Rule rule = repository.rule("complete");
- assertThat(rule.key()).isEqualTo("complete");
- assertThat(rule.name()).isEqualTo("Complete");
- assertThat(rule.htmlDescription()).isEqualTo("Description of Complete");
- assertThat(rule.defaultSeverity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.template()).isTrue();
- assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
- assertThat(rule.metadata()).isEqualTo("Checker/TreeWalker/LocalVariableName");
- assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
-
- assertThat(rule.params()).hasSize(2);
- RuleDefinitions.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(RuleDefinitions.Status.READY);
- assertThat(rule.defaultSeverity()).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/rule/RuleDefinitionsFromXmlTest/utf8.xml"), Charsets.UTF_8.name());
- RuleDefinitions.Repository repository = load(reader);
-
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.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/rule/RuleDefinitionsFromXmlTest/deprecated.xml"), Charsets.UTF_8.name());
- RuleDefinitions.Repository repository = load(reader);
-
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck");
- assertThat(rule.defaultSeverity()).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-2013 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.rule;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-
-public class RuleDefinitionsTest {
-
- RuleDefinitions.Context context = new RuleDefinitions.Context();
-
- @Test
- public void define_repositories() throws Exception {
- assertThat(context.repositories()).isEmpty();
-
- context.newRepository("findbugs", "java").setName("Findbugs").done();
- context.newRepository("checkstyle", "java").done();
-
- assertThat(context.repositories()).hasSize(2);
- RuleDefinitions.Repository findbugs = context.repository("findbugs");
- assertThat(findbugs).isNotNull();
- assertThat(findbugs.key()).isEqualTo("findbugs");
- assertThat(findbugs.language()).isEqualTo("java");
- assertThat(findbugs.name()).isEqualTo("Findbugs");
- assertThat(findbugs.rules()).isEmpty();
- RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
- assertThat(checkstyle).isNotNull();
- assertThat(checkstyle.key()).isEqualTo("checkstyle");
- assertThat(checkstyle.language()).isEqualTo("java");
-
- // default name is key
- assertThat(checkstyle.name()).isEqualTo("checkstyle");
- assertThat(checkstyle.rules()).isEmpty();
- assertThat(context.repository("unknown")).isNull();
-
- // test equals() and hashCode()
- assertThat(findbugs).isEqualTo(findbugs).isNotEqualTo(checkstyle).isNotEqualTo("findbugs").isNotEqualTo(null);
- assertThat(findbugs.hashCode()).isEqualTo(findbugs.hashCode());
- }
-
- @Test
- public void define_rules() {
- RuleDefinitions.NewRepository newFindbugs = context.newRepository("findbugs", "java");
- newFindbugs.newRule("NPE")
- .setName("Detect NPE")
- .setHtmlDescription("Detect <code>NPE</code>")
- .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
- .setDefaultSeverity(Severity.BLOCKER)
- .setMetadata("/something")
- .setStatus(RuleDefinitions.Status.BETA)
- .setTags("one", "two")
- .addTags("two", "three", "four");
- newFindbugs.newRule("ABC").setName("ABC").setHtmlDescription("ABC");
- newFindbugs.done();
-
- RuleDefinitions.Repository findbugs = context.repository("findbugs");
- assertThat(findbugs.rules()).hasSize(2);
-
- RuleDefinitions.Rule npeRule = findbugs.rule("NPE");
- assertThat(npeRule.key()).isEqualTo("NPE");
- assertThat(npeRule.name()).isEqualTo("Detect NPE");
- assertThat(npeRule.defaultSeverity()).isEqualTo(Severity.BLOCKER);
- assertThat(npeRule.htmlDescription()).isEqualTo("Detect <code>java.lang.NullPointerException</code>");
- assertThat(npeRule.tags()).containsOnly("one", "two", "three", "four");
- assertThat(npeRule.params()).isEmpty();
- assertThat(npeRule.metadata()).isEqualTo("/something");
- assertThat(npeRule.template()).isFalse();
- assertThat(npeRule.status()).isEqualTo(RuleDefinitions.Status.BETA);
- assertThat(npeRule.toString()).isEqualTo("[repository=findbugs, key=NPE]");
- assertThat(npeRule.repository()).isSameAs(findbugs);
-
- // test equals() and hashCode()
- RuleDefinitions.Rule otherRule = findbugs.rule("ABC");
- assertThat(npeRule).isEqualTo(npeRule).isNotEqualTo(otherRule).isNotEqualTo("NPE").isNotEqualTo(null);
- assertThat(npeRule.hashCode()).isEqualTo(npeRule.hashCode());
- }
-
- @Test
- public void define_rule_with_default_fields() {
- RuleDefinitions.NewRepository newFindbugs = context.newRepository("findbugs", "java");
- newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE");
- newFindbugs.done();
-
- RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
- assertThat(rule.key()).isEqualTo("NPE");
- assertThat(rule.defaultSeverity()).isEqualTo(Severity.MAJOR);
- assertThat(rule.params()).isEmpty();
- assertThat(rule.metadata()).isNull();
- assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.READY);
- assertThat(rule.tags()).isEmpty();
- }
-
- @Test
- public void define_rule_parameters() {
- RuleDefinitions.NewRepository newFindbugs = context.newRepository("findbugs", "java");
- RuleDefinitions.NewRule newNpe = newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE");
- newNpe.newParam("level").setDefaultValue("LOW").setName("Level").setDescription("The level").setType(RuleParamType.INTEGER);
- newNpe.newParam("effort");
- newFindbugs.done();
-
- RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
- assertThat(rule.params()).hasSize(2);
-
- RuleDefinitions.Param level = rule.param("level");
- assertThat(level.key()).isEqualTo("level");
- assertThat(level.name()).isEqualTo("Level");
- assertThat(level.description()).isEqualTo("The level");
- assertThat(level.defaultValue()).isEqualTo("LOW");
- assertThat(level.type()).isEqualTo(RuleParamType.INTEGER);
-
- RuleDefinitions.Param effort = rule.param("effort");
- assertThat(effort.key()).isEqualTo("effort").isEqualTo(effort.name());
- assertThat(effort.description()).isNull();
- assertThat(effort.defaultValue()).isNull();
- assertThat(effort.type()).isEqualTo(RuleParamType.STRING);
-
- // test equals() and hashCode()
- assertThat(level).isEqualTo(level).isNotEqualTo(effort).isNotEqualTo("level").isNotEqualTo(null);
- assertThat(level.hashCode()).isEqualTo(level.hashCode());
- }
-
- @Test
- public void extend_repository() {
- assertThat(context.extendedRepositories()).isEmpty();
-
- // for example fb-contrib
- RuleDefinitions.NewExtendedRepository newFindbugs = context.extendRepository("findbugs", "java");
- newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE");
- newFindbugs.done();
-
- assertThat(context.repositories()).isEmpty();
- assertThat(context.extendedRepositories()).hasSize(1);
- assertThat(context.extendedRepositories("other")).isEmpty();
- assertThat(context.extendedRepositories("findbugs")).hasSize(1);
-
- RuleDefinitions.ExtendedRepository findbugs = context.extendedRepositories("findbugs").get(0);
- assertThat(findbugs.language()).isEqualTo("java");
- assertThat(findbugs.rule("NPE")).isNotNull();
- }
-
- @Test
- public void cant_set_blank_repository_name() throws Exception {
- context.newRepository("findbugs", "java").setName(null).done();
-
- assertThat(context.repository("findbugs").name()).isEqualTo("findbugs");
- }
-
- @Test
- public void fail_if_duplicated_repo_keys() {
- context.newRepository("findbugs", "java").done();
- try {
- context.newRepository("findbugs", "whatever_the_language").done();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("The rule repository 'findbugs' is defined several times");
- }
- }
-
- @Test
- public void warning_if_duplicated_rule_keys() {
- RuleDefinitions.NewRepository findbugs = context.newRepository("findbugs", "java");
- findbugs.newRule("NPE");
- findbugs.newRule("NPE");
- // do not fail as long as http://jira.codehaus.org/browse/SONARJAVA-428 is not fixed
- }
-
- @Test
- public void fail_if_duplicated_rule_param_keys() {
- RuleDefinitions.NewRule rule = context.newRepository("findbugs", "java").newRule("NPE");
- rule.newParam("level");
- try {
- rule.newParam("level");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("The parameter 'level' is declared several times on the rule [repository=findbugs, key=NPE]");
- }
- }
-
- @Test
- public void fail_if_blank_rule_name() {
- RuleDefinitions.NewRepository newRepository = context.newRepository("findbugs", "java");
- newRepository.newRule("NPE").setName(null).setHtmlDescription("NPE");
- try {
- newRepository.done();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("Name of rule [repository=findbugs, key=NPE] is empty");
- }
- }
-
- @Test
- public void fail_if_bad_rule_tag() {
- try {
- // whitespaces are not allowed in tags
- context.newRepository("findbugs", "java").newRule("NPE").setTags("coding style");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Whitespaces are not allowed in rule tags: 'coding style'");
- }
- }
-
- @Test
- public void fail_if_blank_rule_html_description() {
- RuleDefinitions.NewRepository newRepository = context.newRepository("findbugs", "java");
- newRepository.newRule("NPE").setName("NPE").setHtmlDescription(null);
- try {
- newRepository.done();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("HTML description of rule [repository=findbugs, key=NPE] is empty");
- }
- }
-
- @Test
- public void fail_if_bad_rule_severity() {
- try {
- context.newRepository("findbugs", "java").newRule("NPE").setDefaultSeverity("VERY HIGH");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Default severity of rule [repository=findbugs, key=NPE] is not correct: VERY HIGH");
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import org.junit.Test;
-import org.sonar.api.PropertyType;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RuleParamTypeTest {
-
- @Test
- public void testEquals() throws Exception {
- RuleParamType noOptions = RuleParamType.INTEGER;
- RuleParamType withOptions1 = RuleParamType.ofValues("one", "two");
- RuleParamType withOptions2 = RuleParamType.ofValues("three", "four");
-
- assertThat(RuleParamType.INTEGER)
- .isEqualTo(RuleParamType.INTEGER)
- .isNotEqualTo(RuleParamType.STRING)
- .isNotEqualTo("INTEGER")
- .isNotEqualTo(withOptions1)
- .isNotEqualTo(null);
-
- assertThat(withOptions1)
- .isEqualTo(withOptions1)
- .isNotEqualTo(noOptions)
- .isNotEqualTo(withOptions2)
- .isNotEqualTo("SINGLE_SELECT_LIST|one,two,")
- .isNotEqualTo(null);
- }
-
- @Test
- public void testHashCode() throws Exception {
- assertThat(RuleParamType.INTEGER.hashCode()).isEqualTo(RuleParamType.INTEGER.hashCode());
- }
-
- @Test
- public void testInteger() throws Exception {
- RuleParamType type = RuleParamType.INTEGER;
- assertThat(type.toString()).isEqualTo("INTEGER");
- assertThat(RuleParamType.parse(type.toString()).type()).isEqualTo("INTEGER");
- assertThat(RuleParamType.parse(type.toString()).options()).isEmpty();
- assertThat(RuleParamType.parse(type.toString()).toString()).isEqualTo("INTEGER");
- }
-
- @Test
- public void testListOfValues() throws Exception {
- RuleParamType selectList = RuleParamType.parse("SINGLE_SELECT_LIST|foo,bar,");
- assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
- assertThat(selectList.options()).containsOnly("foo", "bar");
- assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST|foo,bar,");
-
- // escape values
- selectList = RuleParamType.ofValues("foo", "one,two|three,four");
- assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
- assertThat(selectList.options()).containsOnly("foo", "one,two|three,four");
- assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST|foo,\"one,two|three,four\",");
- }
-
- @Test
- public void support_deprecated_formats() throws Exception {
- assertThat(RuleParamType.parse("b")).isEqualTo(RuleParamType.BOOLEAN);
- assertThat(RuleParamType.parse("i")).isEqualTo(RuleParamType.INTEGER);
- assertThat(RuleParamType.parse("i{}")).isEqualTo(RuleParamType.INTEGER);
- assertThat(RuleParamType.parse("s")).isEqualTo(RuleParamType.STRING);
- assertThat(RuleParamType.parse("s{}")).isEqualTo(RuleParamType.STRING);
- assertThat(RuleParamType.parse("r")).isEqualTo(RuleParamType.STRING);
- assertThat(RuleParamType.parse("TEXT")).isEqualTo(RuleParamType.TEXT);
- assertThat(RuleParamType.parse("STRING")).isEqualTo(RuleParamType.STRING);
- assertThat(RuleParamType.parse("REGULAR_EXPRESSION")).isEqualTo(RuleParamType.STRING);
- RuleParamType list = RuleParamType.parse("s[FOO,BAR]");
- assertThat(list.type()).isEqualTo("SINGLE_SELECT_LIST");
- assertThat(list.options()).containsOnly("FOO", "BAR");
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-
-public class RuleTagFormatTest {
- @Test
- public void isValid() {
- assertThat(RuleTagFormat.isValid(null)).isFalse();
- assertThat(RuleTagFormat.isValid("")).isFalse();
- assertThat(RuleTagFormat.isValid(" ")).isFalse();
- assertThat(RuleTagFormat.isValid("coding style")).isFalse();
- assertThat(RuleTagFormat.isValid("Style")).isFalse();
- assertThat(RuleTagFormat.isValid("sTyle")).isFalse();
- assertThat(RuleTagFormat.isValid("@style")).isFalse();
-
- assertThat(RuleTagFormat.isValid("style")).isTrue();
- assertThat(RuleTagFormat.isValid("c++")).isTrue();
- assertThat(RuleTagFormat.isValid("f#")).isTrue();
- assertThat(RuleTagFormat.isValid("c++11")).isTrue();
- }
-
- @Test
- public void validate() {
- RuleTagFormat.validate("style");
- // no error
- }
-
- @Test
- public void validate_and_fail() {
- try {
- RuleTagFormat.validate(" ");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Whitespaces are not allowed in rule tags: ' '");
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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 org.junit.Ignore;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitionsFromAnnotations;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.check.Priority;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RuleDefinitionsFromAnnotationsTest {
+
+ @org.junit.Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void rule_with_property() {
+ RuleDefinitions.Repository repository = load(RuleWithProperty.class);
+ assertThat(repository.rules()).hasSize(1);
+ RuleDefinitions.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("foo");
+ assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
+ assertThat(rule.name()).isEqualTo("bar");
+ assertThat(rule.htmlDescription()).isEqualTo("Foo Bar");
+ assertThat(rule.defaultSeverity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
+ assertThat(rule.params()).hasSize(1);
+
+ RuleDefinitions.Param prop = rule.param("property");
+ assertThat(prop.key()).isEqualTo("property");
+ assertThat(prop.description()).isEqualTo("Ignore ?");
+ assertThat(prop.defaultValue()).isEqualTo("false");
+ assertThat(prop.type()).isEqualTo(RuleParamType.STRING);
+ }
+
+ @Test
+ public void rule_with_integer_property() {
+ RuleDefinitions.Repository repository = load(RuleWithIntegerProperty.class);
+
+ RuleDefinitions.Param prop = repository.rules().get(0).param("property");
+ assertThat(prop.description()).isEqualTo("Max");
+ assertThat(prop.defaultValue()).isEqualTo("12");
+ assertThat(prop.type()).isEqualTo(RuleParamType.INTEGER);
+ }
+
+ @Test
+ public void rule_with_text_property() {
+ RuleDefinitions.Repository repository = load(RuleWithTextProperty.class);
+
+ RuleDefinitions.Param prop = repository.rules().get(0).param("property");
+ assertThat(prop.description()).isEqualTo("text");
+ assertThat(prop.defaultValue()).isEqualTo("Long text");
+ assertThat(prop.type()).isEqualTo(RuleParamType.TEXT);
+ }
+
+ @Test
+ @Ignore("TODO list supported types in RuleParamType")
+ public void should_reject_invalid_property_types() {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Invalid property type [INVALID]");
+
+ load(RuleWithInvalidPropertyType.class);
+ }
+
+ @Test
+ public void should_recognize_type() {
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Integer.class)).isEqualTo(RuleParamType.INTEGER);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(int.class)).isEqualTo(RuleParamType.INTEGER);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Float.class)).isEqualTo(RuleParamType.FLOAT);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(float.class)).isEqualTo(RuleParamType.FLOAT);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(String.class)).isEqualTo(RuleParamType.STRING);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Object.class)).isEqualTo(RuleParamType.STRING);
+ }
+
+ @Test
+ public void use_classname_when_missing_key() {
+ RuleDefinitions.Repository repository = load(RuleWithoutKey.class);
+ assertThat(repository.rules()).hasSize(1);
+ RuleDefinitions.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo(RuleWithoutKey.class.getCanonicalName());
+ assertThat(rule.name()).isEqualTo("foo");
+ }
+
+ @Test
+ public void overridden_class() {
+ RuleDefinitions.Repository repository = load(OverridingRule.class);
+ assertThat(repository.rules()).hasSize(1);
+ RuleDefinitions.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("overriding_foo");
+ assertThat(rule.name()).isEqualTo("Overriding Foo");
+ assertThat(rule.defaultSeverity()).isEqualTo(Severity.MAJOR);
+ assertThat(rule.htmlDescription()).isEqualTo("Desc of Overriding Foo");
+ assertThat(rule.params()).hasSize(2);
+ }
+
+ private RuleDefinitions.Repository load(Class annotatedClass) {
+ RuleDefinitions.Context context = new RuleDefinitions.Context();
+ RuleDefinitions.NewRepository newRepository = context.newRepository("squid", "java");
+ new RuleDefinitionsFromAnnotations().loadRules(newRepository, annotatedClass);
+ newRepository.done();
+ return context.repository("squid");
+ }
+
+ @org.sonar.check.Rule(name = "foo", description = "Foo")
+ static class RuleWithoutKey {
+ }
+
+ @org.sonar.check.Rule(key = "foo")
+ static class RuleWithoutNameNorDescription {
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER, status="BETA")
+ static class RuleWithProperty {
+ @org.sonar.check.RuleProperty(description = "Ignore ?", defaultValue = "false")
+ private String property;
+ }
+
+ @org.sonar.check.Rule(key = "overriding_foo", name = "Overriding Foo", description = "Desc of Overriding Foo")
+ static class OverridingRule extends RuleWithProperty {
+ @org.sonar.check.RuleProperty
+ private String additionalProperty;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+ static class RuleWithIntegerProperty {
+ @org.sonar.check.RuleProperty(description = "Max", defaultValue = "12")
+ private Integer property;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+ static class RuleWithTextProperty {
+ @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "TEXT")
+ protected String property;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+ static class RuleWithInvalidPropertyType {
+ @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "INVALID")
+ public String property;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.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 RuleDefinitionsFromXmlTest {
+
+ @org.junit.Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ private RuleDefinitions.Repository load(Reader reader) {
+ RuleDefinitions.Context context = new RuleDefinitions.Context();
+ RuleDefinitions.NewRepository newRepository = context.newRepository("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());
+ RuleDefinitions.Repository repository = load(reader);
+ assertThat(repository.rules()).hasSize(2);
+
+ RuleDefinitions.Rule rule = repository.rule("complete");
+ assertThat(rule.key()).isEqualTo("complete");
+ assertThat(rule.name()).isEqualTo("Complete");
+ assertThat(rule.htmlDescription()).isEqualTo("Description of Complete");
+ assertThat(rule.defaultSeverity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.template()).isTrue();
+ assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
+ assertThat(rule.metadata()).isEqualTo("Checker/TreeWalker/LocalVariableName");
+ assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.BETA);
+
+ assertThat(rule.params()).hasSize(2);
+ RuleDefinitions.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(RuleDefinitions.Status.READY);
+ assertThat(rule.defaultSeverity()).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());
+ RuleDefinitions.Repository repository = load(reader);
+
+ assertThat(repository.rules()).hasSize(1);
+ RuleDefinitions.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());
+ RuleDefinitions.Repository repository = load(reader);
+
+ assertThat(repository.rules()).hasSize(1);
+ RuleDefinitions.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck");
+ assertThat(rule.defaultSeverity()).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-2013 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 org.junit.Test;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleParamType;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class RuleDefinitionsTest {
+
+ RuleDefinitions.Context context = new RuleDefinitions.Context();
+
+ @Test
+ public void define_repositories() throws Exception {
+ assertThat(context.repositories()).isEmpty();
+
+ context.newRepository("findbugs", "java").setName("Findbugs").done();
+ context.newRepository("checkstyle", "java").done();
+
+ assertThat(context.repositories()).hasSize(2);
+ RuleDefinitions.Repository findbugs = context.repository("findbugs");
+ assertThat(findbugs).isNotNull();
+ assertThat(findbugs.key()).isEqualTo("findbugs");
+ assertThat(findbugs.language()).isEqualTo("java");
+ assertThat(findbugs.name()).isEqualTo("Findbugs");
+ assertThat(findbugs.rules()).isEmpty();
+ RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
+ assertThat(checkstyle).isNotNull();
+ assertThat(checkstyle.key()).isEqualTo("checkstyle");
+ assertThat(checkstyle.language()).isEqualTo("java");
+
+ // default name is key
+ assertThat(checkstyle.name()).isEqualTo("checkstyle");
+ assertThat(checkstyle.rules()).isEmpty();
+ assertThat(context.repository("unknown")).isNull();
+
+ // test equals() and hashCode()
+ assertThat(findbugs).isEqualTo(findbugs).isNotEqualTo(checkstyle).isNotEqualTo("findbugs").isNotEqualTo(null);
+ assertThat(findbugs.hashCode()).isEqualTo(findbugs.hashCode());
+ }
+
+ @Test
+ public void define_rules() {
+ RuleDefinitions.NewRepository newFindbugs = context.newRepository("findbugs", "java");
+ newFindbugs.newRule("NPE")
+ .setName("Detect NPE")
+ .setHtmlDescription("Detect <code>NPE</code>")
+ .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
+ .setDefaultSeverity(Severity.BLOCKER)
+ .setMetadata("/something")
+ .setStatus(RuleDefinitions.Status.BETA)
+ .setTags("one", "two")
+ .addTags("two", "three", "four");
+ newFindbugs.newRule("ABC").setName("ABC").setHtmlDescription("ABC");
+ newFindbugs.done();
+
+ RuleDefinitions.Repository findbugs = context.repository("findbugs");
+ assertThat(findbugs.rules()).hasSize(2);
+
+ RuleDefinitions.Rule npeRule = findbugs.rule("NPE");
+ assertThat(npeRule.key()).isEqualTo("NPE");
+ assertThat(npeRule.name()).isEqualTo("Detect NPE");
+ assertThat(npeRule.defaultSeverity()).isEqualTo(Severity.BLOCKER);
+ assertThat(npeRule.htmlDescription()).isEqualTo("Detect <code>java.lang.NullPointerException</code>");
+ assertThat(npeRule.tags()).containsOnly("one", "two", "three", "four");
+ assertThat(npeRule.params()).isEmpty();
+ assertThat(npeRule.metadata()).isEqualTo("/something");
+ assertThat(npeRule.template()).isFalse();
+ assertThat(npeRule.status()).isEqualTo(RuleDefinitions.Status.BETA);
+ assertThat(npeRule.toString()).isEqualTo("[repository=findbugs, key=NPE]");
+ assertThat(npeRule.repository()).isSameAs(findbugs);
+
+ // test equals() and hashCode()
+ RuleDefinitions.Rule otherRule = findbugs.rule("ABC");
+ assertThat(npeRule).isEqualTo(npeRule).isNotEqualTo(otherRule).isNotEqualTo("NPE").isNotEqualTo(null);
+ assertThat(npeRule.hashCode()).isEqualTo(npeRule.hashCode());
+ }
+
+ @Test
+ public void define_rule_with_default_fields() {
+ RuleDefinitions.NewRepository newFindbugs = context.newRepository("findbugs", "java");
+ newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE");
+ newFindbugs.done();
+
+ RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
+ assertThat(rule.key()).isEqualTo("NPE");
+ assertThat(rule.defaultSeverity()).isEqualTo(Severity.MAJOR);
+ assertThat(rule.params()).isEmpty();
+ assertThat(rule.metadata()).isNull();
+ assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.READY);
+ assertThat(rule.tags()).isEmpty();
+ }
+
+ @Test
+ public void define_rule_parameters() {
+ RuleDefinitions.NewRepository newFindbugs = context.newRepository("findbugs", "java");
+ RuleDefinitions.NewRule newNpe = newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE");
+ newNpe.newParam("level").setDefaultValue("LOW").setName("Level").setDescription("The level").setType(RuleParamType.INTEGER);
+ newNpe.newParam("effort");
+ newFindbugs.done();
+
+ RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
+ assertThat(rule.params()).hasSize(2);
+
+ RuleDefinitions.Param level = rule.param("level");
+ assertThat(level.key()).isEqualTo("level");
+ assertThat(level.name()).isEqualTo("Level");
+ assertThat(level.description()).isEqualTo("The level");
+ assertThat(level.defaultValue()).isEqualTo("LOW");
+ assertThat(level.type()).isEqualTo(RuleParamType.INTEGER);
+
+ RuleDefinitions.Param effort = rule.param("effort");
+ assertThat(effort.key()).isEqualTo("effort").isEqualTo(effort.name());
+ assertThat(effort.description()).isNull();
+ assertThat(effort.defaultValue()).isNull();
+ assertThat(effort.type()).isEqualTo(RuleParamType.STRING);
+
+ // test equals() and hashCode()
+ assertThat(level).isEqualTo(level).isNotEqualTo(effort).isNotEqualTo("level").isNotEqualTo(null);
+ assertThat(level.hashCode()).isEqualTo(level.hashCode());
+ }
+
+ @Test
+ public void extend_repository() {
+ assertThat(context.extendedRepositories()).isEmpty();
+
+ // for example fb-contrib
+ RuleDefinitions.NewExtendedRepository newFindbugs = context.extendRepository("findbugs", "java");
+ newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE");
+ newFindbugs.done();
+
+ assertThat(context.repositories()).isEmpty();
+ assertThat(context.extendedRepositories()).hasSize(1);
+ assertThat(context.extendedRepositories("other")).isEmpty();
+ assertThat(context.extendedRepositories("findbugs")).hasSize(1);
+
+ RuleDefinitions.ExtendedRepository findbugs = context.extendedRepositories("findbugs").get(0);
+ assertThat(findbugs.language()).isEqualTo("java");
+ assertThat(findbugs.rule("NPE")).isNotNull();
+ }
+
+ @Test
+ public void cant_set_blank_repository_name() throws Exception {
+ context.newRepository("findbugs", "java").setName(null).done();
+
+ assertThat(context.repository("findbugs").name()).isEqualTo("findbugs");
+ }
+
+ @Test
+ public void fail_if_duplicated_repo_keys() {
+ context.newRepository("findbugs", "java").done();
+ try {
+ context.newRepository("findbugs", "whatever_the_language").done();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("The rule repository 'findbugs' is defined several times");
+ }
+ }
+
+ @Test
+ public void warning_if_duplicated_rule_keys() {
+ RuleDefinitions.NewRepository findbugs = context.newRepository("findbugs", "java");
+ findbugs.newRule("NPE");
+ findbugs.newRule("NPE");
+ // do not fail as long as http://jira.codehaus.org/browse/SONARJAVA-428 is not fixed
+ }
+
+ @Test
+ public void fail_if_duplicated_rule_param_keys() {
+ RuleDefinitions.NewRule rule = context.newRepository("findbugs", "java").newRule("NPE");
+ rule.newParam("level");
+ try {
+ rule.newParam("level");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("The parameter 'level' is declared several times on the rule [repository=findbugs, key=NPE]");
+ }
+ }
+
+ @Test
+ public void fail_if_blank_rule_name() {
+ RuleDefinitions.NewRepository newRepository = context.newRepository("findbugs", "java");
+ newRepository.newRule("NPE").setName(null).setHtmlDescription("NPE");
+ try {
+ newRepository.done();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Name of rule [repository=findbugs, key=NPE] is empty");
+ }
+ }
+
+ @Test
+ public void fail_if_bad_rule_tag() {
+ try {
+ // whitespaces are not allowed in tags
+ context.newRepository("findbugs", "java").newRule("NPE").setTags("coding style");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Whitespaces are not allowed in rule tags: 'coding style'");
+ }
+ }
+
+ @Test
+ public void fail_if_blank_rule_html_description() {
+ RuleDefinitions.NewRepository newRepository = context.newRepository("findbugs", "java");
+ newRepository.newRule("NPE").setName("NPE").setHtmlDescription(null);
+ try {
+ newRepository.done();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("HTML description of rule [repository=findbugs, key=NPE] is empty");
+ }
+ }
+
+ @Test
+ public void fail_if_bad_rule_severity() {
+ try {
+ context.newRepository("findbugs", "java").newRule("NPE").setDefaultSeverity("VERY HIGH");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Default severity of rule [repository=findbugs, key=NPE] is not correct: VERY HIGH");
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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 org.junit.Test;
+import org.sonar.api.server.rule.RuleParamType;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RuleParamTypeTest {
+
+ @Test
+ public void testEquals() throws Exception {
+ RuleParamType noOptions = RuleParamType.INTEGER;
+ RuleParamType withOptions1 = RuleParamType.ofValues("one", "two");
+ RuleParamType withOptions2 = RuleParamType.ofValues("three", "four");
+
+ assertThat(RuleParamType.INTEGER)
+ .isEqualTo(RuleParamType.INTEGER)
+ .isNotEqualTo(RuleParamType.STRING)
+ .isNotEqualTo("INTEGER")
+ .isNotEqualTo(withOptions1)
+ .isNotEqualTo(null);
+
+ assertThat(withOptions1)
+ .isEqualTo(withOptions1)
+ .isNotEqualTo(noOptions)
+ .isNotEqualTo(withOptions2)
+ .isNotEqualTo("SINGLE_SELECT_LIST|one,two,")
+ .isNotEqualTo(null);
+ }
+
+ @Test
+ public void testHashCode() throws Exception {
+ assertThat(RuleParamType.INTEGER.hashCode()).isEqualTo(RuleParamType.INTEGER.hashCode());
+ }
+
+ @Test
+ public void testInteger() throws Exception {
+ RuleParamType type = RuleParamType.INTEGER;
+ assertThat(type.toString()).isEqualTo("INTEGER");
+ assertThat(RuleParamType.parse(type.toString()).type()).isEqualTo("INTEGER");
+ assertThat(RuleParamType.parse(type.toString()).options()).isEmpty();
+ assertThat(RuleParamType.parse(type.toString()).toString()).isEqualTo("INTEGER");
+ }
+
+ @Test
+ public void testListOfValues() throws Exception {
+ RuleParamType selectList = RuleParamType.parse("SINGLE_SELECT_LIST|foo,bar,");
+ assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
+ assertThat(selectList.options()).containsOnly("foo", "bar");
+ assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST|foo,bar,");
+
+ // escape values
+ selectList = RuleParamType.ofValues("foo", "one,two|three,four");
+ assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
+ assertThat(selectList.options()).containsOnly("foo", "one,two|three,four");
+ assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST|foo,\"one,two|three,four\",");
+ }
+
+ @Test
+ public void support_deprecated_formats() throws Exception {
+ assertThat(RuleParamType.parse("b")).isEqualTo(RuleParamType.BOOLEAN);
+ assertThat(RuleParamType.parse("i")).isEqualTo(RuleParamType.INTEGER);
+ assertThat(RuleParamType.parse("i{}")).isEqualTo(RuleParamType.INTEGER);
+ assertThat(RuleParamType.parse("s")).isEqualTo(RuleParamType.STRING);
+ assertThat(RuleParamType.parse("s{}")).isEqualTo(RuleParamType.STRING);
+ assertThat(RuleParamType.parse("r")).isEqualTo(RuleParamType.STRING);
+ assertThat(RuleParamType.parse("TEXT")).isEqualTo(RuleParamType.TEXT);
+ assertThat(RuleParamType.parse("STRING")).isEqualTo(RuleParamType.STRING);
+ assertThat(RuleParamType.parse("REGULAR_EXPRESSION")).isEqualTo(RuleParamType.STRING);
+ RuleParamType list = RuleParamType.parse("s[FOO,BAR]");
+ assertThat(list.type()).isEqualTo("SINGLE_SELECT_LIST");
+ assertThat(list.options()).containsOnly("FOO", "BAR");
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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 org.junit.Test;
+import org.sonar.api.server.rule.RuleTagFormat;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class RuleTagFormatTest {
+ @Test
+ public void isValid() {
+ assertThat(RuleTagFormat.isValid(null)).isFalse();
+ assertThat(RuleTagFormat.isValid("")).isFalse();
+ assertThat(RuleTagFormat.isValid(" ")).isFalse();
+ assertThat(RuleTagFormat.isValid("coding style")).isFalse();
+ assertThat(RuleTagFormat.isValid("Style")).isFalse();
+ assertThat(RuleTagFormat.isValid("sTyle")).isFalse();
+ assertThat(RuleTagFormat.isValid("@style")).isFalse();
+
+ assertThat(RuleTagFormat.isValid("style")).isTrue();
+ assertThat(RuleTagFormat.isValid("c++")).isTrue();
+ assertThat(RuleTagFormat.isValid("f#")).isTrue();
+ assertThat(RuleTagFormat.isValid("c++11")).isTrue();
+ }
+
+ @Test
+ public void validate() {
+ RuleTagFormat.validate("style");
+ // no error
+ }
+
+ @Test
+ public void validate_and_fail() {
+ try {
+ RuleTagFormat.validate(" ");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Whitespaces are not allowed in rule tags: ' '");
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class SimpleRequestTest {
+ @Test
+ public void string_params() {
+ Request request = new SimpleRequest().setParams(ImmutableMap.of("foo", "bar"));
+ assertThat(request.param("none")).isNull();
+ assertThat(request.param("foo")).isEqualTo("bar");
+ }
+
+ @Test
+ public void int_params() {
+ Request request = new SimpleRequest().setParams(ImmutableMap.of("foo", "123"));
+ assertThat(request.intParam("none")).isNull();
+ assertThat(request.intParam("foo")).isEqualTo(123);
+
+ assertThat(request.intParam("none", 456)).isEqualTo(456);
+ assertThat(request.intParam("foo", 456)).isEqualTo(123);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.ws;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.mock;
+
+public class WebServiceTest {
+
+ static class MetricWebService implements WebService {
+ boolean showCalled = false, createCalled = false;
+ @Override
+ public void define(Context context) {
+ NewController newController = context.newController("api/metric")
+ .setDescription("Metrics")
+ .setSince("3.2");
+ newController.newAction("show")
+ .setDescription("Show metric")
+ .setHandler(new RequestHandler() {
+ @Override
+ public void handle(Request request, Response response) {
+ show(request, response);
+ }
+ });
+ newController.newAction("create")
+ .setDescription("Create metric")
+ .setSince("4.1")
+ .setPost(true)
+ .setHandler(new RequestHandler() {
+ @Override
+ public void handle(Request request, Response response) {
+ create(request, response);
+ }
+ });
+ newController.done();
+ }
+
+ void show(Request request, Response response) {
+ showCalled = true;
+ }
+
+ void create(Request request, Response response) {
+ createCalled = true;
+ }
+ }
+
+
+ WebService.Context context = new WebService.Context();
+
+ @Test
+ public void no_web_services_by_default() {
+ assertThat(context.controllers()).isEmpty();
+ assertThat(context.controller("metric")).isNull();
+ }
+
+ @Test
+ public void define_web_service() {
+ MetricWebService metricWs = new MetricWebService();
+
+ metricWs.define(context);
+
+ WebService.Controller controller = context.controller("api/metric");
+ assertThat(controller).isNotNull();
+ assertThat(controller.path()).isEqualTo("api/metric");
+ assertThat(controller.description()).isEqualTo("Metrics");
+ assertThat(controller.since()).isEqualTo("3.2");
+ assertThat(controller.isApi()).isTrue();
+ assertThat(controller.actions()).hasSize(2);
+ WebService.Action showAction = controller.action("show");
+ assertThat(showAction).isNotNull();
+ assertThat(showAction.key()).isEqualTo("show");
+ assertThat(showAction.description()).isEqualTo("Show metric");
+ assertThat(showAction.handler()).isNotNull();
+ // same as controller
+ assertThat(showAction.since()).isEqualTo("3.2");
+ assertThat(showAction.isPost()).isFalse();
+ assertThat(showAction.path()).isEqualTo("api/metric/show");
+ WebService.Action createAction = controller.action("create");
+ assertThat(createAction).isNotNull();
+ assertThat(createAction.key()).isEqualTo("create");
+ assertThat(createAction.toString()).isEqualTo("api/metric/create");
+ // overrides controller version
+ assertThat(createAction.since()).isEqualTo("4.1");
+ assertThat(createAction.isPost()).isTrue();
+ }
+
+ @Test
+ public void non_api_ws() {
+ new WebService() {
+ @Override
+ public void define(Context context) {
+ NewController controller = context.newController("rule");
+ controller.newAction("index").setHandler(mock(RequestHandler.class));
+ controller.done();
+ }
+ }.define(context);
+ assertThat(context.controller("rule").isApi()).isFalse();
+ }
+
+ @Test
+ public void fail_if_duplicated_ws_keys() {
+ MetricWebService metricWs = new MetricWebService();
+ metricWs.define(context);
+ try {
+ new WebService() {
+ @Override
+ public void define(Context context) {
+ NewController newController = context.newController("api/metric");
+ newController.newAction("delete");
+ newController.done();
+ }
+ }.define(context);
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("The web service 'api/metric' is defined multiple times");
+ }
+ }
+
+ @Test
+ public void fail_if_no_action_handler() {
+ try {
+ new WebService() {
+ @Override
+ public void define(Context context) {
+ NewController controller = context.newController("rule");
+ controller.newAction("show");
+ controller.done();
+ }
+ }.define(context);
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("RequestHandler is not set on action rule/show");
+ }
+ }
+
+ @Test
+ public void fail_if_duplicated_action_keys() {
+ try {
+ new WebService() {
+ @Override
+ public void define(Context context) {
+ NewController newController = context.newController("rule");
+ newController.newAction("create");
+ newController.newAction("delete");
+ newController.newAction("delete");
+ newController.done();
+ }
+ }.define(context);
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("The action 'delete' is defined multiple times in the web service 'rule'");
+ }
+ }
+
+ @Test
+ public void fail_if_no_actions() {
+ try {
+ new WebService() {
+ @Override
+ public void define(Context context) {
+ context.newController("rule").done();
+ }
+ }.define(context);
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("At least one action must be declared in the web service 'rule'");
+ }
+ }
+
+ @Test
+ public void fail_if_no_ws_path() {
+ try {
+ new WebService() {
+ @Override
+ public void define(Context context) {
+ context.newController(null).done();
+ }
+ }.define(context);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Web service path can't be empty");
+ }
+ }
+
+ @Test
+ public void handle_request() throws Exception {
+ MetricWebService metricWs = new MetricWebService();
+ metricWs.define(context);
+
+ assertThat(metricWs.showCalled).isFalse();
+ assertThat(metricWs.createCalled).isFalse();
+ context.controller("api/metric").action("show").handler().handle(mock(Request.class), mock(Response.class));
+ assertThat(metricWs.showCalled).isTrue();
+ assertThat(metricWs.createCalled).isFalse();
+ context.controller("api/metric").action("create").handler().handle(mock(Request.class), mock(Response.class));
+ assertThat(metricWs.createCalled).isTrue();
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Test;
-import org.sonar.api.web.ws.Request;
-import org.sonar.api.web.ws.SimpleRequest;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class SimpleRequestTest {
- @Test
- public void string_params() {
- Request request = new SimpleRequest().setParams(ImmutableMap.of("foo", "bar"));
- assertThat(request.param("none")).isNull();
- assertThat(request.param("foo")).isEqualTo("bar");
- }
-
- @Test
- public void int_params() {
- Request request = new SimpleRequest().setParams(ImmutableMap.of("foo", "123"));
- assertThat(request.intParam("none")).isNull();
- assertThat(request.intParam("foo")).isEqualTo(123);
-
- assertThat(request.intParam("none", 456)).isEqualTo(456);
- assertThat(request.intParam("foo", 456)).isEqualTo(123);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.web.ws;
-
-import org.junit.Test;
-import org.sonar.api.web.ws.Request;
-import org.sonar.api.web.ws.RequestHandler;
-import org.sonar.api.web.ws.Response;
-import org.sonar.api.web.ws.WebService;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Mockito.mock;
-
-public class WebServiceTest {
-
- static class MetricWebService implements WebService {
- boolean showCalled = false, createCalled = false;
- @Override
- public void define(Context context) {
- NewController newController = context.newController("api/metric")
- .setDescription("Metrics")
- .setSince("3.2");
- newController.newAction("show")
- .setDescription("Show metric")
- .setHandler(new RequestHandler() {
- @Override
- public void handle(Request request, Response response) {
- show(request, response);
- }
- });
- newController.newAction("create")
- .setDescription("Create metric")
- .setSince("4.1")
- .setPost(true)
- .setHandler(new RequestHandler() {
- @Override
- public void handle(Request request, Response response) {
- create(request, response);
- }
- });
- newController.done();
- }
-
- void show(Request request, Response response) {
- showCalled = true;
- }
-
- void create(Request request, Response response) {
- createCalled = true;
- }
- }
-
-
- WebService.Context context = new WebService.Context();
-
- @Test
- public void no_web_services_by_default() {
- assertThat(context.controllers()).isEmpty();
- assertThat(context.controller("metric")).isNull();
- }
-
- @Test
- public void define_web_service() {
- MetricWebService metricWs = new MetricWebService();
-
- metricWs.define(context);
-
- WebService.Controller controller = context.controller("api/metric");
- assertThat(controller).isNotNull();
- assertThat(controller.path()).isEqualTo("api/metric");
- assertThat(controller.description()).isEqualTo("Metrics");
- assertThat(controller.since()).isEqualTo("3.2");
- assertThat(controller.isApi()).isTrue();
- assertThat(controller.actions()).hasSize(2);
- WebService.Action showAction = controller.action("show");
- assertThat(showAction).isNotNull();
- assertThat(showAction.key()).isEqualTo("show");
- assertThat(showAction.description()).isEqualTo("Show metric");
- assertThat(showAction.handler()).isNotNull();
- // same as controller
- assertThat(showAction.since()).isEqualTo("3.2");
- assertThat(showAction.isPost()).isFalse();
- assertThat(showAction.path()).isEqualTo("api/metric/show");
- WebService.Action createAction = controller.action("create");
- assertThat(createAction).isNotNull();
- assertThat(createAction.key()).isEqualTo("create");
- assertThat(createAction.toString()).isEqualTo("api/metric/create");
- // overrides controller version
- assertThat(createAction.since()).isEqualTo("4.1");
- assertThat(createAction.isPost()).isTrue();
- }
-
- @Test
- public void non_api_ws() {
- new WebService() {
- @Override
- public void define(Context context) {
- NewController controller = context.newController("rule");
- controller.newAction("index").setHandler(mock(RequestHandler.class));
- controller.done();
- }
- }.define(context);
- assertThat(context.controller("rule").isApi()).isFalse();
- }
-
- @Test
- public void fail_if_duplicated_ws_keys() {
- MetricWebService metricWs = new MetricWebService();
- metricWs.define(context);
- try {
- new WebService() {
- @Override
- public void define(Context context) {
- NewController newController = context.newController("api/metric");
- newController.newAction("delete");
- newController.done();
- }
- }.define(context);
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("The web service 'api/metric' is defined multiple times");
- }
- }
-
- @Test
- public void fail_if_no_action_handler() {
- try {
- new WebService() {
- @Override
- public void define(Context context) {
- NewController controller = context.newController("rule");
- controller.newAction("show");
- controller.done();
- }
- }.define(context);
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("RequestHandler is not set on action rule/show");
- }
- }
-
- @Test
- public void fail_if_duplicated_action_keys() {
- try {
- new WebService() {
- @Override
- public void define(Context context) {
- NewController newController = context.newController("rule");
- newController.newAction("create");
- newController.newAction("delete");
- newController.newAction("delete");
- newController.done();
- }
- }.define(context);
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("The action 'delete' is defined multiple times in the web service 'rule'");
- }
- }
-
- @Test
- public void fail_if_no_actions() {
- try {
- new WebService() {
- @Override
- public void define(Context context) {
- context.newController("rule").done();
- }
- }.define(context);
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("At least one action must be declared in the web service 'rule'");
- }
- }
-
- @Test
- public void fail_if_no_ws_path() {
- try {
- new WebService() {
- @Override
- public void define(Context context) {
- context.newController(null).done();
- }
- }.define(context);
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Web service path can't be empty");
- }
- }
-
- @Test
- public void handle_request() throws Exception {
- MetricWebService metricWs = new MetricWebService();
- metricWs.define(context);
-
- assertThat(metricWs.showCalled).isFalse();
- assertThat(metricWs.createCalled).isFalse();
- context.controller("api/metric").action("show").handler().handle(mock(Request.class), mock(Response.class));
- assertThat(metricWs.showCalled).isTrue();
- assertThat(metricWs.createCalled).isFalse();
- context.controller("api/metric").action("create").handler().handle(mock(Request.class), mock(Response.class));
- assertThat(metricWs.createCalled).isTrue();
- }
-}
+++ /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>
- <configKey>Checker/TreeWalker/LocalVariableName</configKey>
- <severity>BLOCKER</severity>
- <cardinality>MULTIPLE</cardinality>
- <status>BETA</status>
- <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>
\ No newline at end of file
+++ /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>
+ <!-- with exhaustive fields -->
+ <key>complete</key>
+ <name>Complete</name>
+ <description>
+ <![CDATA[Description of Complete]]>
+ </description>
+ <configKey>Checker/TreeWalker/LocalVariableName</configKey>
+ <severity>BLOCKER</severity>
+ <cardinality>MULTIPLE</cardinality>
+ <status>BETA</status>
+ <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>
\ No newline at end of file
--- /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.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.Iterables;
import org.sonar.api.ServerComponent;
-import org.sonar.api.rule.RuleParamType;
+import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.System2;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.collect.Maps;
import org.elasticsearch.common.joda.time.format.ISODateTimeFormat;
-import org.sonar.api.rule.RuleParamType;
+import org.sonar.api.server.rule.RuleParamType;
import org.sonar.check.Cardinality;
import org.sonar.server.rule.ActiveRuleDocument;
import org.sonar.server.rule.RuleDocument;
package org.sonar.server.qualityprofile;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.sonar.api.rule.RuleParamType;
+import org.sonar.api.server.rule.RuleParamType;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
package org.sonar.server.rule;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.rule.RuleDefinitions;
-import org.sonar.api.rule.RuleParamType;
+import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.rules.RuleParam;
import org.sonar.api.rules.RuleRepository;
import org.sonar.check.Cardinality;
package org.sonar.server.rule;
import org.sonar.api.ServerComponent;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
/**
* Loads all instances of RuleDefinitions and initializes RuleRepositories. Used at server startup.
import org.picocontainer.Startable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.SetMultimap;
import org.sonar.api.ServerComponent;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
import javax.annotation.CheckForNull;
import java.util.Collection;
*/
package org.sonar.server.rule;
-import org.sonar.api.web.ws.Request;
-import org.sonar.api.web.ws.RequestHandler;
-import org.sonar.api.web.ws.Response;
-import org.sonar.api.web.ws.WebService;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
public class RuleWebService implements WebService {
package org.sonar.server.ws;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.web.ws.Request;
-import org.sonar.api.web.ws.RequestHandler;
-import org.sonar.api.web.ws.Response;
-import org.sonar.api.web.ws.WebService;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
import java.util.List;
*/
package org.sonar.server.ws;
-import org.sonar.api.web.ws.Request;
+import org.sonar.api.server.ws.Request;
import javax.servlet.http.HttpServletRequest;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.utils.text.XmlWriter;
-import org.sonar.api.web.ws.Response;
+import org.sonar.api.server.ws.Response;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.picocontainer.Startable;
import org.sonar.api.ServerComponent;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.web.ws.Request;
-import org.sonar.api.web.ws.Response;
-import org.sonar.api.web.ws.WebService;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
package org.sonar.server.rule;
import org.junit.Test;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
package org.sonar.server.rule;
import org.junit.Test;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
import static org.fest.assertions.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.api.rule.Severity;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.MyBatis;
package org.sonar.server.rule;
import org.junit.Test;
-import org.sonar.api.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleDefinitions;
import static org.fest.assertions.Assertions.assertThat;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;
-import org.sonar.api.web.ws.RequestHandler;
-import org.sonar.api.web.ws.SimpleRequest;
-import org.sonar.api.web.ws.SimpleResponse;
-import org.sonar.api.web.ws.WebService;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.SimpleRequest;
+import org.sonar.api.server.ws.SimpleResponse;
+import org.sonar.api.server.ws.WebService;
import static org.fest.assertions.Assertions.assertThat;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;
-import org.sonar.api.web.ws.*;
+import org.sonar.api.server.ws.*;
import static org.fest.assertions.Assertions.assertThat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.web.ws.*;
+import org.sonar.api.server.ws.*;
import static org.fest.assertions.Assertions.assertThat;