]> source.dussan.org Git - sonarqube.git/commitdiff
Continue draft of search framework
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 29 Apr 2014 22:40:47 +0000 (00:40 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 29 Apr 2014 22:40:47 +0000 (00:40 +0200)
15 files changed:
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
sonar-server/src/main/java/org/sonar/server/rule2/Rule.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleDoc.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java [deleted file]
sonar-server/src/main/java/org/sonar/server/rule2/RuleQuery.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java
sonar-server/src/main/java/org/sonar/server/rule2/ws/RulesWebService.java
sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java
sonar-server/src/main/java/org/sonar/server/rule2/ws/ShowAction.java
sonar-server/src/main/java/org/sonar/server/search/Index.java
sonar-server/src/main/java/org/sonar/server/search/QueryOptions.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/search/Results.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/ws/ListingWs.java
sonar-server/src/test/java/org/sonar/server/rule2/ws/RulesWebServiceTest.java
sonar-server/src/test/resources/org/sonar/server/ws/ListingWsTest/response_example.json

index 3da8be70df17f2cff45e4937061e3f4864ca9382..94a41cf436edc350a5e4c5c6889b7ac6683f13f4 100644 (file)
@@ -32,6 +32,7 @@ import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 import java.io.IOException;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -408,7 +409,7 @@ public interface WebService extends ServerExtension {
     public String responseExampleAsString() {
       try {
         if (responseExample != null) {
-          return IOUtils.toString(responseExample, Charsets.UTF_8);
+          return StringUtils.trim(IOUtils.toString(responseExample, Charsets.UTF_8));
         }
         return null;
       } catch (IOException e) {
@@ -442,7 +443,7 @@ public interface WebService extends ServerExtension {
   class NewParam {
     private String key, description, exampleValue, defaultValue;
     private boolean required = false;
-    private String[] possibleValues = null;
+    private Collection<Object> possibleValues = null;
 
     private NewParam(String key) {
       this.key = key;
@@ -477,8 +478,19 @@ public interface WebService extends ServerExtension {
      *
      * @since 4.4
      */
-    public NewParam setPossibleValues(@Nullable String... s) {
-      this.possibleValues = s;
+    public NewParam setPossibleValues(@Nullable Object... s) {
+      this.possibleValues = (s == null ? null : Arrays.asList(s));
+      return this;
+    }
+
+    /**
+     * Exhaustive list of possible values when it makes sense, for example
+     * list of severities.
+     *
+     * @since 4.4
+     */
+    public NewParam setPossibleValues(@Nullable Collection c) {
+      this.possibleValues = c;
       return this;
     }
 
@@ -500,7 +512,7 @@ public interface WebService extends ServerExtension {
   class Param {
     private final String key, description, exampleValue, defaultValue;
     private final boolean required;
-    private final String[] possibleValues;
+    private final List<String> possibleValues;
 
     public Param(NewParam newParam) {
       this.key = newParam.key;
@@ -508,7 +520,15 @@ public interface WebService extends ServerExtension {
       this.exampleValue = newParam.exampleValue;
       this.defaultValue = newParam.defaultValue;
       this.required = newParam.required;
-      this.possibleValues = newParam.possibleValues;
+      if (newParam.possibleValues == null) {
+        this.possibleValues = null;
+      } else {
+        ImmutableList.Builder<String> builder = ImmutableList.builder();
+        for (Object possibleValue : newParam.possibleValues) {
+          builder.add(possibleValue.toString());
+        }
+        this.possibleValues = builder.build();
+      }
     }
 
     public String key() {
@@ -541,7 +561,7 @@ public interface WebService extends ServerExtension {
      * @since 4.4
      */
     @CheckForNull
-    public String[] possibleValues() {
+    public List<String> possibleValues() {
       return possibleValues;
     }
 
index e925ae2b09c6472cd0ca5e59eb061ce1deb9ef71..62f5c934c10b2f50b4462fa87a10c73f457aa3b5 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.rule2;
 
 import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
+import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.server.debt.DebtRemediationFunction;
 
 import javax.annotation.CheckForNull;
@@ -40,14 +40,30 @@ public interface Rule {
 
   String description();
 
-  Severity severity();
+  /**
+   * Default severity when activated on a Quality profile
+   *
+   * @see org.sonar.api.rule.Severity
+   */
+  String severity();
 
-  String status();
+  /**
+   * @see org.sonar.api.rule.RuleStatus
+   */
+  RuleStatus status();
 
   boolean template();
 
+  /**
+   * Tags that can be customized by administrators
+   */
   List<String> tags();
 
+  /**
+   * Read-only tags defined by plugins
+   */
+  List<String> systemTags();
+
   List<RuleParam> params();
 
   @CheckForNull
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleDoc.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleDoc.java
new file mode 100644 (file)
index 0000000..7916091
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+/*
+* SonarQube, open source software quality management tool.
+* Copyright (C) 2008-2014 SonarSource
+* mailto:contact AT sonarsource DOT com
+*
+* SonarQube is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or (at your option) any later version.
+*
+* SonarQube is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+package org.sonar.server.rule2;
+
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.server.search.Hit;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation of Rule based on an Elasticsearch document
+ */
+class RuleDoc implements Rule {
+
+  private final Map<String, Object> fields;
+
+  RuleDoc(Map<String, Object> fields) {
+    this.fields = fields;
+  }
+
+  RuleDoc(Hit hit) {
+    this.fields = hit.getFields();
+  }
+
+  @Override
+  public RuleKey key() {
+    return RuleKey.of((String) fields.get("repositoryKey"),
+      (String) fields.get("ruleKey"));
+  }
+
+  @Override
+  public String language() {
+    return (String) fields.get("language");
+  }
+
+  @Override
+  public String name() {
+    return (String) fields.get("name");
+  }
+
+  @Override
+  public String description() {
+    return (String) fields.get("description");
+  }
+
+  @Override
+  public String severity() {
+    return (String) fields.get("severity");
+  }
+
+  @Override
+  public RuleStatus status() {
+    return RuleStatus.valueOf((String) fields.get("status"));
+  }
+
+  @Override
+  public boolean template() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public List<String> tags() {
+    return (List<String>) fields.get("tags");
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public List<String> systemTags() {
+    return (List<String>) fields.get("sysTags");
+  }
+
+  @Override
+  public List<RuleParam> params() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public String debtCharacteristicKey() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public String debtSubCharacteristicKey() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public DebtRemediationFunction debtRemediationFunction() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public Date createdAt() {
+    return (Date) fields.get("createdAt");
+  }
+
+  @Override
+  public Date updatedAt() {
+    return (Date) fields.get("updatedAt");
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java
deleted file mode 100644 (file)
index c096b14..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.rule2;
-
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-
-import java.util.Date;
-import java.util.List;
-
-public class RuleImpl implements Rule {
-
-
-
-  @Override
-  public RuleKey key() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public String language() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public String name() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public String description() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public Severity severity() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public String status() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public boolean template() {
-    // TODO Auto-generated method stub
-    return false;
-  }
-
-  @Override
-  public List<String> tags() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public List<RuleParam> params() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public String debtCharacteristicKey() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public String debtSubCharacteristicKey() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public DebtRemediationFunction debtRemediationFunction() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public Date createdAt() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public Date updatedAt() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-}
index d526c2839ddb6a4565bf6e27c1ec280f00d36902..156b4503d942fbcc8f5f85e53251ec34fda5a6fa 100644 (file)
  */
 package org.sonar.server.rule2;
 
+import com.google.common.base.Preconditions;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
 public class RuleQuery {
 
+  private String key;
+  private String queryText;
+  private String[] languages;
+  private String[] repositories;
+  private String[] severities;
+  private RuleStatus[] statuses;
+  private String[] tags;
+  private String[] debtCharacteristics;
+  private Boolean hasDebtCharacteristic;
+
+  @CheckForNull
+  public String getKey() {
+    return key;
+  }
+
+  public RuleQuery setKey(@Nullable String key) {
+    this.key = key;
+    return this;
+  }
+
+  @CheckForNull
+  public String getQueryText() {
+    return queryText;
+  }
+
+  public RuleQuery setQueryText(@Nullable String queryText) {
+    this.queryText = queryText;
+    return this;
+  }
+
+  @CheckForNull
+  public String[] getLanguages() {
+    return languages;
+  }
+
+  public RuleQuery setLanguages(@Nullable String[] languages) {
+    this.languages = languages;
+    return this;
+  }
+
+  @CheckForNull
+  public String[] getRepositories() {
+    return repositories;
+  }
+
+  public RuleQuery setRepositories(@Nullable String[] repositories) {
+    this.repositories = repositories;
+    return this;
+  }
+
+  @CheckForNull
+  public String[] getSeverities() {
+    return severities;
+  }
+
+  public RuleQuery setSeverities(@Nullable String[] severities) {
+    if (severities != null) {
+      for (String severity : severities) {
+        Preconditions.checkArgument(Severity.ALL.contains(severity), "Unknown severity: " + severity);
+      }
+    }
+    this.severities = severities;
+    return this;
+  }
+
+  @CheckForNull
+  public RuleStatus[] getStatuses() {
+    return statuses;
+  }
+
+  public RuleQuery setStatuses(@Nullable RuleStatus[] statuses) {
+    this.statuses = statuses;
+    return this;
+  }
+
+  @CheckForNull
+  public String[] getTags() {
+    return tags;
+  }
+
+  public RuleQuery setTags(@Nullable String[] tags) {
+    this.tags = tags;
+    return this;
+  }
+
+  @CheckForNull
+  public String[] getDebtCharacteristics() {
+    return debtCharacteristics;
+  }
+
+  public RuleQuery setDebtCharacteristics(@Nullable String[] debtCharacteristics) {
+    this.debtCharacteristics = debtCharacteristics;
+    return this;
+  }
+
+  @CheckForNull
+  public Boolean getHasDebtCharacteristic() {
+    return hasDebtCharacteristic;
+  }
+
+  public RuleQuery setHasDebtCharacteristic(@Nullable Boolean hasDebtCharacteristic) {
+    this.hasDebtCharacteristic = hasDebtCharacteristic;
+    return this;
+  }
 }
index 35d1c0ee18bbd7d9c416506f5303eb8fcf53639f..c712d96d2a572460c3db035926e2f084942b4ece 100644 (file)
@@ -22,12 +22,11 @@ package org.sonar.server.rule2;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.rule.RuleDao;
-import org.sonar.core.rule.RuleDto;
 import org.sonar.server.search.Hit;
+import org.sonar.server.search.QueryOptions;
+import org.sonar.server.search.Results;
 
 import javax.annotation.CheckForNull;
-import java.util.Collection;
-import java.util.Collections;
 
 /**
  * @since 4.4
@@ -46,23 +45,12 @@ public class RuleService implements ServerComponent {
   public Rule getByKey(RuleKey key) {
     Hit hit = index.getByKey(key);
     if (hit != null) {
-      return toRule(hit);
-    } else {
-      return null;
+      return new RuleDoc(hit);
     }
+    return null;
   }
 
-  public Collection<Hit> search(RuleQuery query) {
-
-    return Collections.emptyList();
-  }
-
-  public static Rule toRule(RuleDto ruleDto) {
-    return new RuleImpl();
-  }
-
-  public static Rule toRule(Hit hit) {
-//    BeanUtils.setProperty(bean, name, value);
-    return new RuleImpl();
+  public Results search(RuleQuery query, QueryOptions options) {
+    throw new UnsupportedOperationException("TODO");
   }
 }
index 7b54490d79ea56b8bb2fde2bfc7dce1aa7493588..923aac0800494b280efe7d2a949cf15af9fabd5a 100644 (file)
@@ -35,8 +35,7 @@ public class RulesWebService implements WebService {
   public void define(Context context) {
     NewController controller = context
       .createController("api/rules2")
-      .setDescription("Coding rules")
-      .setSince("4.4");
+      .setDescription("Coding rules");
 
     search.define(controller);
     show.define(controller);
index ccd61ea14b4fb104e2a0cb368542c10f37ff1b67..30dff403069e9cad33724ed70d74eec082df2036 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.rule2.ws;
 
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
@@ -39,7 +41,7 @@ public class SearchAction implements RequestHandler {
   void define(WebService.NewController controller) {
     WebService.NewAction action = controller
       .createAction("search")
-      .setDescription("Returns a collection of relevant rules matching a specified query")
+      .setDescription("Search for a collection of relevant rules matching a specified query")
       .setSince("4.4")
       .setHandler(this);
 
@@ -48,6 +50,23 @@ public class SearchAction implements RequestHandler {
       .setDescription("UTF-8 search query")
       .setExampleValue("null pointer");
 
+    action
+      .createParam("severities")
+      .setDescription("Comma-separated list of default severities. Not the same than severity of rules in Quality profiles.")
+      .setPossibleValues(Severity.ALL)
+      .setExampleValue("CRITICAL,BLOCKER");
+
+    action
+      .createParam("statuses")
+      .setDescription("Comma-separated list of status codes")
+      .setPossibleValues(RuleStatus.values())
+      .setExampleValue("BETA,DEPRECATED");
+
+    action
+      .createParam("tags")
+      .setDescription("Comma-separated list of tags")
+      .setExampleValue("security,java8");
+
     action
       .createParam("qProfile")
       .setDescription("Key of Quality profile")
index 0c9b75b1a49ccfbcb53c9a78bf63867e8ff738b3..6d7f71ca1199867c62a492920d015585a62d8749 100644 (file)
  */
 package org.sonar.server.rule2.ws;
 
+import org.sonar.api.rule.RuleKey;
 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 org.sonar.api.utils.text.JsonWriter;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.rule2.Rule;
 import org.sonar.server.rule2.RuleService;
 
 /**
@@ -39,7 +43,7 @@ public class ShowAction implements RequestHandler {
   void define(WebService.NewController controller) {
     WebService.NewAction action = controller
       .createAction("show")
-      .setDescription("Returns detailed information about a rule")
+      .setDescription("Get detailed information about a rule")
       .setSince("4.4")
       .setHandler(this);
 
@@ -58,6 +62,28 @@ public class ShowAction implements RequestHandler {
 
   @Override
   public void handle(Request request, Response response) {
+    String repoKey = request.mandatoryParam("repo");
+    String ruleKey = request.mandatoryParam("key");
+    Rule rule = service.getByKey(RuleKey.of(repoKey, ruleKey));
+    if (rule == null) {
+      throw new NotFoundException("Rule not found");
+    }
+    JsonWriter json = response.newJsonWriter().beginObject().name("rule").beginObject();
+    writeRule(rule, json);
+    json.endObject().endObject().close();
+  }
 
+  private void writeRule(Rule rule, JsonWriter json) {
+    json.prop("repo", rule.key().repository());
+    json.prop("key", rule.key().rule());
+    json.prop("lang", rule.language());
+    json.prop("name", rule.name());
+    json.prop("desc", rule.description());
+    json.prop("status", rule.status().toString());
+    json.prop("template", rule.template());
+    json.prop("severity", rule.severity().toString());
+    json.name("tags").beginArray().values(rule.tags()).endArray();
+    json.name("sysTags").beginArray().values(rule.systemTags()).endArray();
+    //TODO debt, params
   }
 }
index 1eb8de436ff8757f3146d3fd5c2cfefbf7e58989..6a45b550ddea4ae4d5e4ebcbc3f1c2f005b63e75 100644 (file)
@@ -23,6 +23,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.picocontainer.Startable;
 import org.sonar.core.cluster.IndexAction;
 
+import javax.annotation.CheckForNull;
 import java.io.Serializable;
 
 public interface Index<K extends Serializable> extends Startable {
@@ -31,6 +32,7 @@ public interface Index<K extends Serializable> extends Startable {
 
   void executeAction(IndexAction<K> action);
 
+  @CheckForNull
   Hit getByKey(K key);
 
   void insert(K key);
diff --git a/sonar-server/src/main/java/org/sonar/server/search/QueryOptions.java b/sonar-server/src/main/java/org/sonar/server/search/QueryOptions.java
new file mode 100644 (file)
index 0000000..7fb3647
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.search;
+
+import com.google.common.base.Preconditions;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+/**
+ * Options about paging, sorting and fields to return
+ */
+public class QueryOptions {
+
+  public static final int DEFAULT_OFFSET = 0;
+  public static final int DEFAULT_LIMIT = 10;
+  public static final boolean DEFAULT_ASCENDING = true;
+
+  private int offset = DEFAULT_OFFSET;
+  private int limit = DEFAULT_LIMIT;
+  private boolean ascending = DEFAULT_ASCENDING;
+  private String sortField;
+  private String[] fieldsToReturn;
+
+  /**
+   * Offset of the first result to return. Defaults to {@link #DEFAULT_OFFSET}
+   */
+  public int getOffset() {
+    return offset;
+  }
+
+  /**
+   * Sets the offset of the first result to return (zero-based).
+   */
+  public QueryOptions setOffset(int offset) {
+    Preconditions.checkArgument(offset >= 0, "Offset must be positive");
+    this.offset = offset;
+    return this;
+  }
+
+  /**
+   * Limit on the number of results to return. Defaults to {@link #DEFAULT_LIMIT}.
+   */
+  public int getLimit() {
+    return limit;
+  }
+
+  /**
+   * Sets the limit on the number of results to return.
+   */
+  public QueryOptions setLimit(int limit) {
+    this.limit = limit;
+    return this;
+  }
+
+  /**
+   * Is ascending sort ? Defaults to {@link #DEFAULT_ASCENDING}
+   */
+  public boolean isAscending() {
+    return ascending;
+  }
+
+  public QueryOptions setAscending(boolean ascending) {
+    this.ascending = ascending;
+    return this;
+  }
+
+  @CheckForNull
+  public String getSortField() {
+    return sortField;
+  }
+
+  public QueryOptions setSortField(@Nullable String sortField) {
+    this.sortField = sortField;
+    return this;
+  }
+
+  @CheckForNull
+  public String[] getFieldsToReturn() {
+    return fieldsToReturn;
+  }
+
+  public QueryOptions setFieldsToReturn(@Nullable String[] fieldsToReturn) {
+    this.fieldsToReturn = fieldsToReturn;
+    return this;
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/search/Results.java b/sonar-server/src/main/java/org/sonar/server/search/Results.java
new file mode 100644 (file)
index 0000000..3504fb2
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.search;
+
+import java.util.Collection;
+
+public class Results {
+
+  private Collection<Hit> hits;
+
+  private int total;
+
+  private int offset;
+
+  public Collection<Hit> getHits() {
+    return hits;
+  }
+
+  public int getTotal() {
+    return total;
+  }
+
+  public int getOffset() {
+    return offset;
+  }
+}
index c67c5f107f24534b33527bf05855198eeb98e8c4..87a256700b87a91ef25c9c24a9986d570caac1ed 100644 (file)
  */
 package org.sonar.server.ws;
 
-import com.google.common.base.Charsets;
 import com.google.common.base.Function;
 import com.google.common.collect.Ordering;
-import org.apache.commons.io.IOUtils;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
@@ -83,7 +81,7 @@ public class ListingWs implements WebService {
         .newJsonWriter()
         .beginObject()
         .prop("format", action.responseExampleFormat())
-        .prop("example", IOUtils.toString(action.responseExample(), Charsets.UTF_8))
+        .prop("example", action.responseExampleAsString())
         .endObject()
         .close();
     } else {
@@ -136,7 +134,7 @@ public class ListingWs implements WebService {
     writer.prop("since", action.since());
     writer.prop("internal", action.isInternal());
     writer.prop("post", action.isPost());
-    writer.prop("hasResponseExample", action.responseExample()!=null);
+    writer.prop("hasResponseExample", action.responseExample() != null);
     if (!action.params().isEmpty()) {
       // sort parameters by key
       Ordering<Param> ordering = Ordering.natural().onResultOf(new Function<Param, String>() {
index c61a550609ec4a36cecec39711d114267f65919a..a2c0b409b275821dfb43081cb8d144ddde1b0320 100644 (file)
@@ -40,7 +40,6 @@ public class RulesWebServiceTest {
 
     WebService.Controller controller = context.controller("api/rules2");
     assertThat(controller).isNotNull();
-    assertThat(controller.since()).isEqualTo("4.4");
     assertThat(controller.actions()).hasSize(2);
     assertThat(controller.action("search")).isNotNull();
     assertThat(controller.action("show")).isNotNull();