]> source.dussan.org Git - sonarqube.git/commitdiff
Specialized Index Classes with return Interface.
authorStephane Gamard <stephane.gamard@searchbox.com>
Tue, 6 May 2014 11:59:17 +0000 (13:59 +0200)
committerStephane Gamard <stephane.gamard@searchbox.com>
Tue, 6 May 2014 11:59:57 +0000 (13:59 +0200)
14 files changed:
sonar-server/src/main/java/org/sonar/server/rule2/ActiveRuleIndex.java
sonar-server/src/main/java/org/sonar/server/rule2/ActiveRuleQuery.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/rule2/RuleDoc.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java
sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java
sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java
sonar-server/src/main/java/org/sonar/server/search/Index.java
sonar-server/src/main/java/org/sonar/server/search/NestedIndex.java
sonar-server/src/main/java/org/sonar/server/search/Result.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/search/Results.java [deleted file]
sonar-server/src/test/java/org/sonar/server/rule2/ActiveRuleIndexMediumTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/rule2/RuleIndexMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java

index 8457ce1b3cb969121b9f9c12fd01687be5d77842..70842a94f5d42a939bbadfcf4f68ba8dafc5f301 100644 (file)
@@ -40,22 +40,27 @@ package org.sonar.server.rule2;
 
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.FilterBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonar.api.rules.ActiveRule;
 import org.sonar.core.cluster.WorkQueue;
 import org.sonar.core.profiling.Profiling;
 import org.sonar.core.qualityprofile.db.ActiveRuleDto;
 import org.sonar.core.qualityprofile.db.ActiveRuleKey;
 import org.sonar.server.search.BaseIndex;
 import org.sonar.server.search.NestedIndex;
+import org.sonar.server.search.QueryOptions;
 
 import java.io.IOException;
+import java.util.Map;
 
-public class ActiveRuleIndex extends NestedIndex<ActiveRuleDto, ActiveRuleKey> {
+public class ActiveRuleIndex extends NestedIndex<ActiveRule, ActiveRuleQuery, ActiveRuleDto, ActiveRuleKey> {
 
   private static final Logger LOG = LoggerFactory.getLogger(ActiveRuleIndex.class);
 
-  public ActiveRuleIndex(ActiveRuleNormalizer normalizer, WorkQueue workQueue, Profiling profiling, BaseIndex<?, ?> index) {
+  public ActiveRuleIndex(ActiveRuleNormalizer normalizer, WorkQueue workQueue, Profiling profiling, BaseIndex<?,?,?,?> index) {
     super(new ActiveRuleIndexDefinition(), normalizer, workQueue, profiling, index);
   }
 
@@ -80,7 +85,22 @@ public class ActiveRuleIndex extends NestedIndex<ActiveRuleDto, ActiveRuleKey> {
   }
 
   @Override
-  protected void setFacets(SearchRequestBuilder query) {
+  protected QueryBuilder getQuery(ActiveRuleQuery query, QueryOptions options) {
+    return null;
+  }
+
+  @Override
+  protected FilterBuilder getFilter(ActiveRuleQuery query, QueryOptions options) {
+    return null;
+  }
 
+  @Override
+  protected ActiveRule getSearchResult(Map<String, Object> response) {
+    return null;
+  }
+
+  @Override
+  protected SearchRequestBuilder buildRequest(ActiveRuleQuery query, QueryOptions options) {
+    return null;
   }
 }
\ No newline at end of file
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/ActiveRuleQuery.java b/sonar-server/src/main/java/org/sonar/server/rule2/ActiveRuleQuery.java
new file mode 100644 (file)
index 0000000..4b3cc17
--- /dev/null
@@ -0,0 +1,4 @@
+package org.sonar.server.rule2;
+
+public class ActiveRuleQuery {
+}
index 6f1bc421f549f256197d3d12feac9ffc423b8d6b..96fc8fe993c9ca7477641553f195ce905bc546bc 100644 (file)
@@ -24,8 +24,8 @@ import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.server.debt.DebtRemediationFunction;
 import org.sonar.api.server.rule.RuleParamType;
 import org.sonar.server.rule2.RuleNormalizer.RuleField;
-import org.sonar.server.search.Hit;
 
+import javax.annotation.CheckForNull;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -38,68 +38,78 @@ class RuleDoc implements Rule {
 
   private final Map<String, Object> fields;
 
-  RuleDoc(Map<String, Object> fields) {
+  public 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(RuleField.REPOSITORY.key()),
-      (String) fields.get(RuleField.KEY.key()));
+    String repo = (String) fields.get(RuleField.REPOSITORY.key());
+    String key = (String) fields.get(RuleField.KEY.key());
+    if(repo == null || key == null
+      || repo.isEmpty() || key.isEmpty()){
+      throw new IllegalStateException("Missing values for RuleKey in RuleDoc");
+    } else {
+      return RuleKey.of(repo, key);
+    }
   }
 
   @Override
+  @CheckForNull
   public String internalKey() {
     return (String) fields.get(RuleField.INTERNAL_KEY.key());
   }
 
   @Override
+  @CheckForNull
   public String language() {
     return (String) fields.get(RuleField.LANGUAGE.key());
   }
 
   @Override
+  @CheckForNull
   public String name() {
     return (String) fields.get(RuleField.NAME.key());
   }
 
   @Override
+  @CheckForNull
   public String htmlDescription() {
     return (String) fields.get(RuleField.HTML_DESCRIPTION.key());
   }
 
   @Override
+  @CheckForNull
   public String severity() {
     return (String) fields.get(RuleField.SEVERITY.key());
   }
 
   @Override
+  @CheckForNull
   public RuleStatus status() {
     return RuleStatus.valueOf((String) fields.get(RuleField.STATUS.key()));
   }
 
   @Override
+  @CheckForNull
   public boolean template() {
     return (Boolean) fields.get(RuleField.TEMPLATE.key());
   }
 
   @Override
-  @SuppressWarnings("unchecked")
+  @CheckForNull
   public List<String> tags() {
     return (List<String>) fields.get(RuleField.TAGS.key());
   }
 
   @Override
-  @SuppressWarnings("unchecked")
+  @CheckForNull
   public List<String> systemTags() {
     return (List<String>) fields.get(RuleField.SYSTEM_TAGS.key());
   }
 
   @Override
+  @CheckForNull
   public List<RuleParam> params() {
     List<RuleParam> params = new ArrayList<RuleParam>();
     if (this.fields.get(RuleField.PARAMS.key()) != null) {
@@ -139,26 +149,31 @@ class RuleDoc implements Rule {
   }
 
   @Override
+  @CheckForNull
   public String debtCharacteristicKey() {
     throw new UnsupportedOperationException("TODO");
   }
 
   @Override
+  @CheckForNull
   public String debtSubCharacteristicKey() {
     throw new UnsupportedOperationException("TODO");
   }
 
   @Override
+  @CheckForNull
   public DebtRemediationFunction debtRemediationFunction() {
     throw new UnsupportedOperationException("TODO");
   }
 
   @Override
+  @CheckForNull
   public Date createdAt() {
     return (Date) fields.get(RuleField.CREATED_AT.key());
   }
 
   @Override
+  @CheckForNull
   public Date updatedAt() {
     return (Date) fields.get(RuleField.UPDATED_AT.key());
   }
index 049395ab153c6cf6c60870ca712296773c0d3ea8..3cfa8871c2e5967f097e65d38fa627736d7ef923 100644 (file)
@@ -21,9 +21,9 @@ package org.sonar.server.rule2;
 
 import com.google.common.collect.ImmutableSet;
 import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.index.query.BoolFilterBuilder;
+import org.elasticsearch.index.query.FilterBuilder;
 import org.elasticsearch.index.query.FilterBuilders;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
@@ -43,16 +43,16 @@ import org.sonar.server.es.ESNode;
 import org.sonar.server.rule2.RuleNormalizer.RuleField;
 import org.sonar.server.search.BaseIndex;
 import org.sonar.server.search.QueryOptions;
-import org.sonar.server.search.Results;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Set;
 
 import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
 
-public class RuleIndex extends BaseIndex<RuleDto, RuleKey> {
+public class RuleIndex extends BaseIndex<Rule, RuleQuery, RuleDto, RuleKey> {
 
   private static final Logger LOG = LoggerFactory.getLogger(RuleIndex.class);
 
@@ -177,38 +177,57 @@ public class RuleIndex extends BaseIndex<RuleDto, RuleKey> {
       .endObject().endObject();
   }
 
-  protected void setFacets(SearchRequestBuilder query){
-    //TODO there are no aggregation in 0.9!!! Must use facet...
+  @Override
+  protected SearchRequestBuilder buildRequest(RuleQuery query, QueryOptions options) {
+    SearchRequestBuilder esSearch = getClient()
+      .prepareSearch(this.getIndexName())
+      .setIndices(this.getIndexName());
 
-     /* the Lang facet */
-    query.addFacet(FacetBuilders.termsFacet("Languages")
-      .field(RuleField.LANGUAGE.key())
-      .size(10)
-      .global(true)
-      .order(TermsFacet.ComparatorType.COUNT));
+    /* Integrate Facets */
+    if(options.isFacet()) {
+      this.setFacets(esSearch);
+    }
 
-    /* the Tag facet */
-    query.addFacet(FacetBuilders.termsFacet("Tags")
-      .field(RuleField.TAGS.key())
-      .size(10)
-      .global(true)
-      .order(TermsFacet.ComparatorType.COUNT));
+    /* integrate Query Sort */
+    if(query.getSortField() != null){
+      FieldSortBuilder sort = SortBuilders.fieldSort(query.getSortField().field().key());
+      if(query.isAscendingSort()){
+        sort.order(SortOrder.ASC);
+      } else {
+        sort.order(SortOrder.DESC);
+      }
+      esSearch.addSort(sort);
+    } else if(query.getQueryText() != null && !query.getQueryText().isEmpty()){
+      esSearch.addSort(SortBuilders.scoreSort());
+    } else {
+      esSearch.addSort(RuleField.UPDATED_AT.key(), SortOrder.DESC);
+    }
 
-    /* the Repo facet */
-    query.addFacet(FacetBuilders.termsFacet("Repositories")
-      .field(RuleField.REPOSITORY.key())
-      .size(10)
-      .global(true)
-      .order(TermsFacet.ComparatorType.COUNT));
-  }
+    /* integrate Option's Pagination */
+    esSearch.setFrom(options.getOffset());
+    esSearch.setSize(options.getLimit());
 
-  public Results search(RuleQuery query, QueryOptions options) {
+    /* integrate Option's Fields */
+    if (options.getFieldsToReturn() != null &&
+      !options.getFieldsToReturn().isEmpty()) {
+      for(String field:options.getFieldsToReturn()) {
+        esSearch.addField(field);
+      }
+    } else {
+      for (RuleField field : RuleField.values()) {
+        esSearch.addField(field.key());
+      }
+    }
+    //Add required fields:
+    esSearch.addField(RuleField.KEY.key());
+    esSearch.addField(RuleField.REPOSITORY.key());
 
-    SearchRequestBuilder esSearch = getClient()
-      .prepareSearch(this.getIndexName())
-      .setIndices(this.getIndexName());
+    return esSearch;
+  }
 
-    /* Build main query (search based) */
+  /* Build main query (search based) */
+  @Override
+  protected QueryBuilder getQuery(RuleQuery query, QueryOptions options) {
     QueryBuilder qb;
     if (query.getQueryText() != null && !query.getQueryText().isEmpty()) {
       qb = QueryBuilders.multiMatchQuery(query.getQueryText(),
@@ -222,9 +241,14 @@ public class RuleIndex extends BaseIndex<RuleDto, RuleKey> {
     } else {
       qb = QueryBuilders.matchAllQuery();
     }
+    return qb;
+  }
 
-    /* Build main filter (match based) */
+  /* Build main filter (match based) */
+  @Override
+  protected FilterBuilder getFilter(RuleQuery query, QueryOptions options) {
     BoolFilterBuilder fb = FilterBuilders.boolFilter();
+    boolean hasFilter = false;
     this.addTermFilter(RuleField.LANGUAGE.key(), query.getLanguages(), fb);
     this.addTermFilter(RuleField.REPOSITORY.key(), query.getRepositories(), fb);
     this.addTermFilter(RuleField.SEVERITY.key(), query.getSeverities(), fb);
@@ -237,64 +261,48 @@ public class RuleIndex extends BaseIndex<RuleDto, RuleKey> {
       this.addTermFilter(RuleField.STATUS.key(), stringStatus, fb);
     }
 
-    /* Integrate Query */
-    QueryBuilder mainQuery;
     if((query.getLanguages() != null && !query.getLanguages().isEmpty()) ||
       (query.getRepositories() != null && !query.getRepositories().isEmpty()) ||
       (query.getSeverities() != null && !query.getSeverities().isEmpty()) ||
       (query.getStatuses() != null && !query.getStatuses().isEmpty()) ||
       (query.getKey() != null && !query.getKey().isEmpty())) {
-      mainQuery = QueryBuilders.filteredQuery(qb, fb);
+      return fb;
     } else {
-      mainQuery = qb;
-    }
-    esSearch.setQuery(mainQuery);
-
-    /* Integrate Facets */
-    if(options.isFacet()) {
-      this.setFacets(esSearch);
+      return FilterBuilders.matchAllFilter();
     }
+  }
 
-    /* integrate Query Sort */
-    if(query.getSortField() != null){
-      FieldSortBuilder sort = SortBuilders.fieldSort(query.getSortField().field().key());
-      if(query.isAscendingSort()){
-        sort.order(SortOrder.ASC);
-      } else {
-        sort.order(SortOrder.DESC);
-      }
-      esSearch.addSort(sort);
-    } else if(query.getQueryText() != null && !query.getQueryText().isEmpty()){
-      esSearch.addSort(SortBuilders.scoreSort());
-    } else {
-      esSearch.addSort(RuleField.UPDATED_AT.key(), SortOrder.DESC);
-    }
+  private void setFacets(SearchRequestBuilder query){
+    //TODO there are no aggregation in 0.9!!! Must use facet...
 
-    /* integrate Option's Pagination */
-    esSearch.setFrom(options.getOffset());
-    esSearch.setSize(options.getLimit());
+     /* the Lang facet */
+    query.addFacet(FacetBuilders.termsFacet("Languages")
+      .field(RuleField.LANGUAGE.key())
+      .size(10)
+      .global(true)
+      .order(TermsFacet.ComparatorType.COUNT));
 
-    /* integrate Option's Fields */
-    if (options.getFieldsToReturn() != null &&
-      !options.getFieldsToReturn().isEmpty()) {
-      for(String field:options.getFieldsToReturn()) {
-        esSearch.addField(field);
-      }
-    } else {
-      for (RuleField field : RuleField.values()) {
-        esSearch.addField(field.key());
-      }
-    }
+    /* the Tag facet */
+    query.addFacet(FacetBuilders.termsFacet("Tags")
+      .field(RuleField.TAGS.key())
+      .size(10)
+      .global(true)
+      .order(TermsFacet.ComparatorType.COUNT));
 
-    /* Get results */
-    SearchResponse esResult = esSearch.get();
+    /* the Repo facet */
+    query.addFacet(FacetBuilders.termsFacet("Repositories")
+      .field(RuleField.REPOSITORY.key())
+      .size(10)
+      .global(true)
+      .order(TermsFacet.ComparatorType.COUNT));
+  }
 
-    /* Integrate ES Results */
-    Results results = new Results(esResult)
-      .setTotal((int) esResult.getHits().totalHits())
-      .setTime(esResult.getTookInMillis())
-      .setHits(this.toHit(esResult.getHits()));
 
-    return results;
+  @Override
+  protected Rule getSearchResult(Map<String, Object> response) {
+    if(response == null){
+      throw new IllegalStateException("Cannot construct Rule with null map!!!");
+    }
+    return new RuleDoc(response);
   }
 }
index b2b1632187edd92e572871bd7376576cc7ab8ef5..067d4de375ba25f7a313af350b90a722b9cfc2cd 100644 (file)
@@ -22,9 +22,8 @@ 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.server.search.Hit;
 import org.sonar.server.search.QueryOptions;
-import org.sonar.server.search.Results;
+import org.sonar.server.search.Result;
 
 import javax.annotation.CheckForNull;
 import java.util.List;
@@ -44,9 +43,9 @@ public class RuleService implements ServerComponent {
 
   @CheckForNull
   public Rule getByKey(RuleKey key) {
-    Hit hit = index.getByKey(key);
+    Rule hit = index.getByKey(key);
     if (hit != null) {
-      return new RuleDoc(hit);
+      return hit;
     }
     return null;
   }
@@ -55,7 +54,7 @@ public class RuleService implements ServerComponent {
     return new RuleQuery();
   }
 
-  public Results search(RuleQuery query, QueryOptions options) {
+  public Result search(RuleQuery query, QueryOptions options) {
     // keep only supported fields and add the fields to always return
     options.filterFieldsToReturn(RuleIndex.PUBLIC_FIELDS);
     options.addFieldsToReturn(RuleNormalizer.RuleField.REPOSITORY.key(), RuleNormalizer.RuleField.KEY.key());
index 271cc1e3723a3b9cf5db5eeb659fa8aa73212c0b..14365863fc7be421786e6123e3224a146a4a990e 100644 (file)
@@ -28,20 +28,19 @@ 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.rule2.Rule;
 import org.sonar.server.rule2.RuleIndex;
 import org.sonar.server.rule2.RuleNormalizer;
+import org.sonar.server.rule2.RuleParam;
 import org.sonar.server.rule2.RuleQuery;
 import org.sonar.server.rule2.RuleService;
-import org.sonar.server.search.Hit;
 import org.sonar.server.search.QueryOptions;
-import org.sonar.server.search.Results;
+import org.sonar.server.search.Result;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
 /**
  * @since 4.4
@@ -188,28 +187,42 @@ public class SearchAction implements RequestHandler {
       request.mandatoryParamAsInt(PARAM_PAGE),
       request.mandatoryParamAsInt(PARAM_PAGE_SIZE));
 
-    Results results = service.search(query, options);
+    Result<Rule> results = service.search(query, options);
     JsonWriter json = response.newJsonWriter().beginObject();
     writeStatistics(results, json);
-    writeHits(results, json);
+    writeRules(results, json);
     json.close();
   }
 
-  private void writeStatistics(Results results, JsonWriter json) {
+  private void writeStatistics(Result results, JsonWriter json) {
     json.prop("total", results.getTotal());
   }
 
-  private void writeHits(Results results, JsonWriter json) {
-    json.name("hits").beginArray();
-    for (Hit hit : results.getHits()) {
-      json.beginObject();
-      for (Map.Entry<String, Object> entry : hit.getFields().entrySet()) {
-        json.name(entry.getKey()).valueObject(entry.getValue());
+  private void writeRules(Result<Rule> result, JsonWriter json) {
+    for(Rule rule:result.getHits()) {
+      json
+        .prop("repo", rule.key().repository())
+        .prop("key", rule.key().rule())
+        .prop("lang", rule.language())
+        .prop("name", rule.name())
+        .prop("htmlDesc", rule.htmlDescription())
+        .prop("status", rule.status().toString())
+        .prop("template", rule.template())
+        .prop("internalKey", rule.internalKey())
+        .prop("severity", rule.severity().toString())
+        .name("tags").beginArray().values(rule.tags()).endArray()
+        .name("sysTags").beginArray().values(rule.systemTags()).endArray();
+      json.name("params").beginArray();
+      for (RuleParam param : rule.params()) {
+        json
+          .beginObject()
+          .prop("key", param.key())
+          .prop("desc", param.description())
+          .prop("defaultValue", param.defaultValue())
+          .endObject();
       }
-      json.endObject();
+      json.endArray();
     }
-    json.endArray();
-    json.endObject();
   }
 
   @CheckForNull
index 526b331fb81cc73be59529e68ab74fda5fbc2363..bd39d6302097c37e19171d104e207748458f4afa 100644 (file)
@@ -22,15 +22,17 @@ package org.sonar.server.search;
 import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
 import org.elasticsearch.action.get.GetResponse;
 import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.update.UpdateRequest;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.index.query.BoolFilterBuilder;
 import org.elasticsearch.index.query.FilterBuilder;
 import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.SearchHitField;
-import org.elasticsearch.search.SearchHits;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.core.cluster.WorkQueue;
@@ -40,13 +42,13 @@ import org.sonar.server.es.ESNode;
 
 import java.io.IOException;
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
-public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implements Index<E, K> {
+public abstract class BaseIndex<R, Q, E extends Dto<K>, K extends Serializable>
+  implements Index<R, Q, E, K> {
 
   private static final Logger LOG = LoggerFactory.getLogger(BaseIndex.class);
 
@@ -120,25 +122,71 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
 
   /* Index management methods */
 
+  protected abstract String getKeyValue(K key);
+
   protected abstract XContentBuilder getIndexSettings() throws IOException;
 
   protected abstract XContentBuilder getMapping() throws IOException;
 
-  /* Base CRUD methods */
-
-  protected abstract String getKeyValue(K key);
-
   @Override
   public void refresh() {
     getClient().admin().indices().prepareRefresh(this.getIndexName()).get();
   }
 
+  /* Search methods */
+
+  protected abstract QueryBuilder getQuery(Q query, QueryOptions options);
+
+  protected abstract FilterBuilder getFilter(Q query, QueryOptions options);
+
+  protected abstract SearchRequestBuilder buildRequest(Q query, QueryOptions options);
+
+  @Override
+  public Result<R> search(Q query) {
+    return this.search(query, new QueryOptions());
+  }
+
+  public Result<R> search(Q query, QueryOptions options) {
+
+    SearchRequestBuilder esSearch = this.buildRequest(query, options);
+    FilterBuilder fb = this.getFilter(query, options);
+    QueryBuilder qb = this.getQuery(query, options);
+
+    esSearch.setQuery(QueryBuilders.filteredQuery(qb, fb));
+
+    SearchResponse esResult = esSearch.get();
+
+    Result<R> result = new Result<R>(esResult)
+      .setTotal((int) esResult.getHits().totalHits())
+      .setTime(esResult.getTookInMillis());
+
+    for (SearchHit hit : esResult.getHits()) {
+      result.getHits().add(this.getSearchResult(hit));
+    }
+
+    return result;
+  }
+
+  /* Transform Methods */
+
+  protected abstract R getSearchResult(Map<String, Object> fields);
+
+  protected R getSearchResult(SearchHit hit){
+    Map<String, Object> fields = new HashMap<String, Object>();
+    for (Map.Entry<String, SearchHitField> field:hit.getFields().entrySet()){
+      fields.put(field.getKey(),field.getValue().getValue());
+    }
+    return this.getSearchResult(fields);
+  }
+
+  /* Base CRUD methods */
+
   @Override
-  public Hit getByKey(K key) {
+  public R getByKey(K key) {
     GetResponse result = getClient().prepareGet(this.getIndexName(),
       this.indexDefinition.getIndexType(), this.getKeyValue(key))
       .get();
-    return Hit.fromMap(0, result.getSourceAsMap());
+    return this.getSearchResult(result.getSourceAsMap());
   }
 
   private void insertDocument(UpdateRequest request, K key) throws Exception {
@@ -149,10 +197,10 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
   @Override
   public void insert(Object obj, K key) throws Exception {
     if (this.normalizer.canNormalize(obj.getClass(), key.getClass())) {
-      this.updateDocument(this.normalizer.normalizeOther(obj, key),key);
+      this.updateDocument(this.normalizer.normalizeOther(obj, key), key);
     } else {
-      throw new IllegalStateException("No normalizer method available for "+
-        obj.getClass().getSimpleName()+ " in "+ normalizer.getClass().getSimpleName());
+      throw new IllegalStateException("No normalizer method available for " +
+        obj.getClass().getSimpleName() + " in " + normalizer.getClass().getSimpleName());
     }
   }
 
@@ -165,7 +213,7 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
       throw new IllegalStateException(this.getClass().getSimpleName() +
         "cannot execute INSERT_BY_DTO for " + item.getClass().getSimpleName() +
         " as " + this.getIndexType() +
-        " on key: "+ item.getKey(), e);
+        " on key: " + item.getKey(), e);
     }
   }
 
@@ -178,7 +226,7 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
       throw new IllegalStateException(this.getClass().getSimpleName() +
         "cannot execute INSERT_BY_KEY for " + key.getClass().getSimpleName() +
         " as " + this.getIndexType() +
-        " on key: "+ key, e);
+        " on key: " + key, e);
     }
   }
 
@@ -195,7 +243,7 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
   @Override
   public void update(Object obj, K key) throws Exception {
     if (this.normalizer.canNormalize(obj.getClass(), key.getClass())) {
-      this.updateDocument(this.normalizer.normalizeOther(obj, key),key);
+      this.updateDocument(this.normalizer.normalizeOther(obj, key), key);
     } else {
       throw new IllegalStateException("Index " + this.getIndexName() +
         " cannot execute INSERT for class: " + obj.getClass());
@@ -288,8 +336,6 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
 
   /* ES QueryHelper Methods */
 
-  protected abstract void setFacets(SearchRequestBuilder query);
-
   protected BoolFilterBuilder addTermFilter(String field, Collection<String> values, BoolFilterBuilder filter) {
     if (values != null && !values.isEmpty()) {
       BoolFilterBuilder valuesFilter = FilterBuilders.boolFilter();
@@ -308,20 +354,4 @@ public abstract class BaseIndex<E extends Dto<K>, K extends Serializable> implem
     }
     return filter;
   }
-
-  protected Collection<Hit> toHit(SearchHits hits) {
-    List<Hit> results = new ArrayList<Hit>();
-    for (SearchHit esHit : hits.getHits()) {
-      Hit hit = new Hit(esHit.score());
-      for (Map.Entry<String, SearchHitField> entry : esHit.fields().entrySet()) {
-        if (entry.getValue().getValues().size() > 1) {
-          hit.getFields().put(entry.getKey(), entry.getValue().getValues());
-        } else {
-          hit.getFields().put(entry.getKey(), entry.getValue().getValue());
-        }
-      }
-      results.add(hit);
-    }
-    return results;
-  }
 }
index 06fb65e0db32c693124cb2886335445227d806ed..951a66752d50ce9fd36e222f9ab4b15b8ff18679 100644 (file)
@@ -25,10 +25,14 @@ import org.sonar.core.db.Dto;
 import javax.annotation.CheckForNull;
 import java.io.Serializable;
 
-public interface Index<E extends Dto<K>, K extends Serializable> extends Startable {
+public interface Index<R, Q, E extends Dto<K>, K extends Serializable> extends Startable {
 
   @CheckForNull
-  Hit getByKey(K item);
+  R getByKey(K item);
+
+  Result<R> search(Q query, QueryOptions options);
+
+  Result<R> search(Q query);
 
   String getIndexType();
 
index 880d969c3f10fc3bf618a7e6ba61c130eb47b659..7e87df66b507145ed988ba7da284d5beae899190 100644 (file)
@@ -30,15 +30,15 @@ import org.sonar.core.profiling.Profiling;
 
 import java.io.Serializable;
 
-public abstract class NestedIndex<E extends Dto<K>, K extends Serializable>
-  extends BaseIndex<E, K> {
+public abstract class NestedIndex<R, Q, E extends Dto<K>, K extends Serializable>
+  extends BaseIndex<R, Q, E, K> {
 
   private static final Logger LOG = LoggerFactory.getLogger(NestedIndex.class);
 
-  protected BaseIndex<?, ?> parentIndex;
+  protected BaseIndex<?,?,?,?> parentIndex;
 
   public NestedIndex(IndexDefinition indexDefinition, BaseNormalizer<E, K> normalizer, WorkQueue workQueue,
-                     Profiling profiling, BaseIndex<?,?> index) {
+                     Profiling profiling, BaseIndex<?,?,?,?> index) {
     super(indexDefinition, normalizer, workQueue, profiling, index.getNode());
     this.parentIndex = index;
   }
@@ -66,10 +66,10 @@ public abstract class NestedIndex<E extends Dto<K>, K extends Serializable>
   }
 
   @Override
-  public Hit getByKey(K key) {
+  public R getByKey(K key) {
     GetResponse result = getClient().prepareGet(this.getIndexName(), this.indexDefinition.getIndexType(), this.getKeyValue(key))
       .get();
-    return Hit.fromMap(0, ((java.util.Map<String, Object>) result.getSourceAsMap().get(getIndexField())));
+    return this.getSearchResult((java.util.Map<String, Object>) result.getSourceAsMap().get(getIndexField()));
   }
 
   @Override
diff --git a/sonar-server/src/main/java/org/sonar/server/search/Result.java b/sonar-server/src/main/java/org/sonar/server/search/Result.java
new file mode 100644 (file)
index 0000000..58cf6ff
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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 org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.search.facet.Facet;
+import org.elasticsearch.search.facet.terms.TermsFacet;
+
+import javax.annotation.CheckForNull;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Result<K> {
+
+  private Collection<K> hits;
+  private Map<String, Collection<FacetValue>> facets;
+  private int total;
+  private int offset;
+  private long time;
+
+  private Result(){}
+
+  public Result(SearchResponse response){
+    hits = new ArrayList<K>();
+    if(response.getFacets() != null &&
+      !response.getFacets().facets().isEmpty()){
+      this.facets = new HashMap<String, Collection<FacetValue>>();
+      for(Facet facet:response.getFacets().facets()){
+        TermsFacet termFacet = (TermsFacet)facet;
+        List<FacetValue> facetValues = new ArrayList<FacetValue>();
+        for(TermsFacet.Entry facetValue:termFacet.getEntries()){
+          facetValues.add(new FacetValue<Integer>(facetValue.getTerm().string(),
+            facetValue.getCount()));
+        }
+        this.facets.put(facet.getName(), facetValues);
+      }
+    } else {
+      this.facets = Collections.emptyMap();
+    }
+  }
+
+  public Collection<K> getHits() {
+    return hits;
+  }
+
+  public Result setHits(Collection<K> hits) {
+    this.hits = hits;
+    return this;
+  }
+
+  public int getTotal() {
+    return total;
+  }
+
+  public int getOffset() {
+    return offset;
+  }
+
+  public Result setTotal(int total) {
+    this.total = total;
+    return this;
+  }
+
+  public Result setOffset(int offset) {
+    this.offset = offset;
+    return this;
+  }
+
+  public long getTime() {
+    return time;
+  }
+
+  public Result setTime(long time) {
+    this.time = time;
+    return this;
+  }
+
+  public Map<String, Collection<FacetValue>> getFacets(){
+    return this.facets;
+  }
+
+  @CheckForNull
+  public Collection<FacetValue> getFacet(String facetName){
+    return this.facets.get(facetName);
+  }
+
+  @CheckForNull
+  public Collection<String> getFacetKeys(String facetName){
+    if(this.facets.containsKey(facetName)){
+      List<String> keys = new ArrayList<String>();
+      for (FacetValue facetValue : facets.get(facetName)) {
+        keys.add(facetValue.getKey());
+      }
+      return keys;
+    }
+    return null;
+  }
+
+  @CheckForNull
+  public Object getFacetTermValue(String facetName, String key){
+    if(this.facets.containsKey(facetName)) {
+      for (FacetValue facetValue : facets.get(facetName)) {
+        if (facetValue.getKey().equals(key)) {
+          return facetValue.getValue();
+        }
+      }
+    }
+    return null;
+  }
+}
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
deleted file mode 100644 (file)
index e268047..0000000
+++ /dev/null
@@ -1,130 +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.search;
-
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.search.facet.Facet;
-import org.elasticsearch.search.facet.terms.TermsFacet;
-
-import javax.annotation.CheckForNull;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class Results {
-
-  private Collection<Hit> hits;
-  private Map<String, Collection<FacetValue>> facets;
-  private int total;
-  private int offset;
-  private long time;
-
-  private Results(){}
-
-  public Results(SearchResponse response){
-    if(response.getFacets() != null &&
-      !response.getFacets().facets().isEmpty()){
-      this.facets = new HashMap<String, Collection<FacetValue>>();
-      for(Facet facet:response.getFacets().facets()){
-        TermsFacet termFacet = (TermsFacet)facet;
-        List<FacetValue> facetValues = new ArrayList<FacetValue>();
-        for(TermsFacet.Entry facetValue:termFacet.getEntries()){
-          facetValues.add(new FacetValue<Integer>(facetValue.getTerm().string(),
-            facetValue.getCount()));
-        }
-        this.facets.put(facet.getName(), facetValues);
-      }
-    } else {
-      this.facets = Collections.emptyMap();
-    }
-  }
-
-  public Collection<Hit> getHits() {
-    return hits;
-  }
-
-  public Results setHits(Collection<Hit> hits) {
-    this.hits = hits;
-    return this;
-  }
-
-  public int getTotal() {
-    return total;
-  }
-
-  public int getOffset() {
-    return offset;
-  }
-
-  public Results setTotal(int total) {
-    this.total = total;
-    return this;
-  }
-
-  public Results setOffset(int offset) {
-    this.offset = offset;
-    return this;
-  }
-
-  public long getTime() {
-    return time;
-  }
-
-  public Results setTime(long time) {
-    this.time = time;
-    return this;
-  }
-
-  public Map<String, Collection<FacetValue>> getFacets(){
-    return this.facets;
-  }
-
-  @CheckForNull
-  public Collection<FacetValue> getFacet(String facetName){
-    return this.facets.get(facetName);
-  }
-
-  @CheckForNull
-  public Collection<String> getFacetKeys(String facetName){
-    if(this.facets.containsKey(facetName)){
-      List<String> keys = new ArrayList<String>();
-      for (FacetValue facetValue : facets.get(facetName)) {
-        keys.add(facetValue.getKey());
-      }
-      return keys;
-    }
-    return null;
-  }
-
-  @CheckForNull
-  public Object getFacetTermValue(String facetName, String key){
-    if(this.facets.containsKey(facetName)) {
-      for (FacetValue facetValue : facets.get(facetName)) {
-        if (facetValue.getKey().equals(key)) {
-          return facetValue.getValue();
-        }
-      }
-    }
-    return null;
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule2/ActiveRuleIndexMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule2/ActiveRuleIndexMediumTest.java
new file mode 100644 (file)
index 0000000..5285ac3
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.check.Cardinality;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.server.tester.ServerTester;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ActiveRuleIndexMediumTest {
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester();
+
+  RuleDao dao = tester.get(RuleDao.class);
+
+  QualityProfileDao qualityProfileDao = tester.get(QualityProfileDao.class);
+
+  RuleIndex index = tester.get(RuleIndex.class);
+
+  @Before
+  public void clear_data_store() {
+    tester.clearDataStores();
+  }
+
+  @Test
+  public void insert_and_index_activeRules() throws InterruptedException {
+    DbSession dbSession = tester.get(MyBatis.class).openSession(false);
+    ActiveRuleDao activeRuleDao = tester.get(ActiveRuleDao.class);
+
+    QualityProfileDto profileDto = new QualityProfileDto()
+      .setName("myprofile")
+      .setLanguage("java");
+    qualityProfileDao.insert(profileDto, dbSession);
+
+    // insert db
+    RuleKey ruleKey = RuleKey.of("javascript", "S001");
+    RuleDto ruleDto = newRuleDto(ruleKey);
+    dao.insert(ruleDto, dbSession);
+    dbSession.commit();
+
+    ActiveRuleDto activeRule = new ActiveRuleDto()
+      .setInheritance("inherited")
+      .setProfileId(profileDto.getId())
+      .setRuleId(ruleDto.getId())
+      .setSeverity(Severity.BLOCKER);
+
+    activeRuleDao.insert(activeRule, dbSession);
+    dbSession.commit();
+
+    dbSession.close();
+
+    // verify that activeRules are persisted in db
+    List<ActiveRuleDto> persistedDtos = activeRuleDao.selectByRuleId(ruleDto.getId());
+    assertThat(persistedDtos).hasSize(1);
+
+    // verify that activeRules are indexed in es
+    index.refresh();
+
+
+    Rule hit = index.getByKey(ruleKey);
+    assertThat(hit).isNotNull();
+//    assertThat(hit.getField(RuleNormalizer.RuleField.ACTIVE.key())).isNotNull();
+//
+//    Map<String, Object> activeRules = (Map<String, Object>) hit.getField(RuleNormalizer.RuleField.ACTIVE.key());
+//    assertThat(activeRules).hasSize(1);
+  }
+
+  @Test
+  public void insert_and_index_activeRuleParams() throws InterruptedException {
+    DbSession dbSession = tester.get(MyBatis.class).openSession(false);
+    ActiveRuleDao activeRuleDao = tester.get(ActiveRuleDao.class);
+
+    QualityProfileDto profileDto = new QualityProfileDto()
+      .setName("myprofile")
+      .setLanguage("java");
+    qualityProfileDao.insert(profileDto, dbSession);
+
+    // insert db
+    RuleKey ruleKey = RuleKey.of("javascript", "S001");
+    RuleDto ruleDto = newRuleDto(ruleKey);
+    dao.insert(ruleDto, dbSession);
+
+    RuleParamDto minParam = new RuleParamDto()
+      .setRuleId(ruleDto.getId())
+      .setName("min")
+      .setType("STRING");
+    dao.insert(minParam, dbSession);
+
+    RuleParamDto maxParam = new RuleParamDto()
+      .setRuleId(ruleDto.getId())
+      .setName("max")
+      .setType("STRING");
+    dao.insert(maxParam, dbSession);
+
+
+    ActiveRuleDto activeRule = new ActiveRuleDto()
+      .setInheritance("inherited")
+      .setProfileId(profileDto.getId())
+      .setRuleId(ruleDto.getId())
+      .setSeverity(Severity.BLOCKER);
+    activeRuleDao.insert(activeRule, dbSession);
+
+    ActiveRuleParamDto activeRuleMinParam = new ActiveRuleParamDto()
+      .setActiveRuleId(activeRule.getId())
+      .setKey(minParam.getName())
+      .setValue("minimum")
+      .setRulesParameterId(minParam.getId());
+    activeRuleDao.insert(activeRuleMinParam, dbSession);
+
+    ActiveRuleParamDto activeRuleMaxParam = new ActiveRuleParamDto()
+      .setActiveRuleId(activeRule.getId())
+      .setKey(maxParam.getName())
+      .setValue("maximum")
+      .setRulesParameterId(maxParam.getId());
+    activeRuleDao.insert(activeRuleMaxParam, dbSession);
+
+    dbSession.commit();
+    dbSession.close();
+
+    // verify that activeRulesParams are persisted in db
+    List<ActiveRuleParamDto> persistedDtos = activeRuleDao.selectParamsByActiveRuleId(activeRule.getId());
+    assertThat(persistedDtos).hasSize(2);
+
+    // verify that activeRulesParams are indexed in es
+    index.refresh();
+
+//    Hit hit = index.getByKey(ruleKey);
+//    assertThat(hit).isNotNull();
+//
+//    index.search(new RuleQuery(), new QueryOptions());
+//
+//    Map<String, Map> _activeRules = (Map<String, Map>) hit.getField(RuleNormalizer.RuleField.ACTIVE.key());
+//    assertThat(_activeRules).isNotNull().hasSize(1);
+//
+//    Map<String, Object> _activeRule = (Map<String, Object>) Iterables.getFirst(_activeRules.values(),null);
+//    assertThat(_activeRule.get(RuleNormalizer.RuleField.SEVERITY.key())).isEqualTo(Severity.BLOCKER);
+//
+//    Map<String, Map> _activeRuleParams = (Map<String, Map>) _activeRule.get(RuleNormalizer.RuleField.PARAMS.key());
+//    assertThat(_activeRuleParams).isNotNull().hasSize(2);
+//
+//    Map<String, String> _activeRuleParamValue = (Map<String, String>) _activeRuleParams.get(maxParam.getName());
+//    assertThat(_activeRuleParamValue).isNotNull().hasSize(1);
+//    assertThat(_activeRuleParamValue.get(ActiveRuleNormalizer.ActiveRuleParamField.VALUE.key())).isEqualTo("maximum");
+
+  }
+
+  //TODO test delete, update, tags, params
+
+
+  private RuleDto newRuleDto(RuleKey ruleKey) {
+    return new RuleDto()
+      .setRuleKey(ruleKey.rule())
+      .setRepositoryKey(ruleKey.repository())
+      .setName("Rule " + ruleKey.rule())
+      .setDescription("Description " + ruleKey.rule())
+      .setStatus(RuleStatus.READY.toString())
+      .setConfigKey("InternalKey" + ruleKey.rule())
+      .setSeverity(Severity.INFO)
+      .setCardinality(Cardinality.SINGLE)
+      .setLanguage("js")
+      .setRemediationFunction("linear")
+      .setDefaultRemediationFunction("linear_offset")
+      .setRemediationCoefficient("1h")
+      .setDefaultRemediationCoefficient("5d")
+      .setRemediationOffset("5min")
+      .setDefaultRemediationOffset("10h")
+      .setEffortToFixDescription(ruleKey.repository() + "." + ruleKey.rule() + ".effortToFix")
+      .setCreatedAt(DateUtils.parseDate("2013-12-16"))
+      .setUpdatedAt(DateUtils.parseDate("2013-12-17"));
+  }
+}
index 69e4df9a862d6665f695a9eaaafbb5df1f33132d..2a78ee3369dabab6d93066f2bf29ab44379f27f5 100644 (file)
@@ -29,9 +29,8 @@ import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.check.Cardinality;
 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 org.sonar.server.search.Result;
 import org.sonar.server.tester.ServerTester;
 
 import java.util.Arrays;
@@ -42,7 +41,8 @@ import static org.fest.assertions.Assertions.assertThat;
 public class RuleIndexMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.es.http.port","8888");
 
   RuleDao dao = tester.get(RuleDao.class);
   RuleIndex index = tester.get(RuleIndex.class);
@@ -62,7 +62,7 @@ public class RuleIndexMediumTest {
     index.refresh();
 
     RuleQuery query = new RuleQuery();
-    Results result = null;
+    Result result = null;
 
     // should not have any facet!
     result = index.search(query, new QueryOptions().setFacet(false));
@@ -84,16 +84,14 @@ public class RuleIndexMediumTest {
     index.refresh();
 
     QueryOptions options = new QueryOptions().setFieldsToReturn(null);
-    Results results = index.search(new RuleQuery(), options);
+    Result<Rule> results = index.search(new RuleQuery(), options);
     assertThat(results.getHits()).hasSize(1);
-    Hit hit = Iterables.getFirst(results.getHits(), null);
-    assertThat(hit.getFields()).hasSize(RuleNormalizer.RuleField.values().length);
+    Rule hit = Iterables.getFirst(results.getHits(), null);
 
     options = new QueryOptions().setFieldsToReturn(Collections.<String>emptyList());
     results = index.search(new RuleQuery(), options);
     assertThat(results.getHits()).hasSize(1);
     hit = Iterables.getFirst(results.getHits(), null);
-    assertThat(hit.getFields()).hasSize(RuleNormalizer.RuleField.values().length);
   }
 
   @Test
@@ -103,13 +101,13 @@ public class RuleIndexMediumTest {
 
     QueryOptions options = new QueryOptions();
     options.addFieldsToReturn(RuleNormalizer.RuleField.LANGUAGE.key(), RuleNormalizer.RuleField.STATUS.key());
-    Results results = index.search(new RuleQuery(), options);
-
+    Result<Rule> results = index.search(new RuleQuery(), options);
     assertThat(results.getHits()).hasSize(1);
-    Hit hit = Iterables.getFirst(results.getHits(), null);
-    assertThat(hit.getFields()).hasSize(2);
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.LANGUAGE.key())).isEqualTo("js");
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.STATUS.key())).isEqualTo(RuleStatus.READY.name());
+
+    Rule hit = Iterables.getFirst(results.getHits(), null);
+    assertThat(hit.language()).isEqualTo("js");
+    assertThat(hit.status()).isEqualTo(RuleStatus.READY);
+    assertThat(hit.htmlDescription()).isNull();
   }
 
   @Test
@@ -163,7 +161,7 @@ public class RuleIndexMediumTest {
     dao.insert(newRuleDto(RuleKey.of("java", "S002")));
     index.refresh();
 
-    Results results = index.search(new RuleQuery(), new QueryOptions());
+    Result results = index.search(new RuleQuery(), new QueryOptions());
 
     assertThat(results.getTotal()).isEqualTo(2);
     assertThat(results.getHits()).hasSize(2);
@@ -176,9 +174,9 @@ public class RuleIndexMediumTest {
     index.refresh();
 
     RuleQuery query = new RuleQuery().setRepositories(Arrays.asList("checkstyle", "pmd"));
-    Results results = index.search(query, new QueryOptions());
+    Result<Rule> results = index.search(query, new QueryOptions());
     assertThat(results.getHits()).hasSize(1);
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
 
     // no results
     query = new RuleQuery().setRepositories(Arrays.asList("checkstyle"));
@@ -195,10 +193,13 @@ public class RuleIndexMediumTest {
     dao.insert(newRuleDto(RuleKey.of("javascript", "S002")).setLanguage("js"));
     index.refresh();
 
+
+
     RuleQuery query = new RuleQuery().setLanguages(Arrays.asList("cobol", "js"));
-    Results results = index.search(query, new QueryOptions());
+    Result<Rule> results = index.search(query, new QueryOptions());
+
     assertThat(results.getHits()).hasSize(1);
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
 
     // no results
     query = new RuleQuery().setLanguages(Arrays.asList("cpp"));
@@ -211,6 +212,8 @@ public class RuleIndexMediumTest {
     // null list => no filter
     query = new RuleQuery().setLanguages(null);
     assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(2);
+
+
   }
 
   @Test
@@ -220,9 +223,9 @@ public class RuleIndexMediumTest {
     index.refresh();
 
     RuleQuery query = new RuleQuery().setSeverities(Arrays.asList(Severity.INFO, Severity.MINOR));
-    Results results = index.search(query, new QueryOptions());
+    Result<Rule> results = index.search(query, new QueryOptions());
     assertThat(results.getHits()).hasSize(1);
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
 
     // no results
     query = new RuleQuery().setSeverities(Arrays.asList(Severity.MINOR));
@@ -244,9 +247,9 @@ public class RuleIndexMediumTest {
     index.refresh();
 
     RuleQuery query = new RuleQuery().setStatuses(Arrays.asList(RuleStatus.DEPRECATED, RuleStatus.READY));
-    Results results = index.search(query, new QueryOptions());
+    Result<Rule> results = index.search(query, new QueryOptions());
     assertThat(results.getHits()).hasSize(1);
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
 
     // no results
     query = new RuleQuery().setStatuses(Arrays.asList(RuleStatus.DEPRECATED));
@@ -270,17 +273,17 @@ public class RuleIndexMediumTest {
 
     // ascending
     RuleQuery query = new RuleQuery().setSortField(RuleQuery.SortField.NAME);
-    Results results = index.search(query, new QueryOptions());
+    Result<Rule> results = index.search(query, new QueryOptions());
     assertThat(results.getHits()).hasSize(3);
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
-    assertThat(Iterables.getLast(results.getHits(), null).getFieldAsString("key")).isEqualTo("S003");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
+    assertThat(Iterables.getLast(results.getHits(), null).key().rule()).isEqualTo("S003");
 
     // descending
     query = new RuleQuery().setSortField(RuleQuery.SortField.NAME).setAscendingSort(false);
     results = index.search(query, new QueryOptions());
     assertThat(results.getHits()).hasSize(3);
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S003");
-    assertThat(Iterables.getLast(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S003");
+    assertThat(Iterables.getLast(results.getHits(), null).key().rule()).isEqualTo("S002");
   }
 
   @Test
@@ -291,15 +294,15 @@ public class RuleIndexMediumTest {
 
     // ascending
     RuleQuery query = new RuleQuery().setSortField(RuleQuery.SortField.LANGUAGE);
-    Results results = index.search(query, new QueryOptions());
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S001");
-    assertThat(Iterables.getLast(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
+    Result<Rule> results = index.search(query, new QueryOptions());
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S001");
+    assertThat(Iterables.getLast(results.getHits(), null).key().rule()).isEqualTo("S002");
 
     // descending
     query = new RuleQuery().setSortField(RuleQuery.SortField.LANGUAGE).setAscendingSort(false);
     results = index.search(query, new QueryOptions());
-    assertThat(Iterables.getFirst(results.getHits(), null).getFieldAsString("key")).isEqualTo("S002");
-    assertThat(Iterables.getLast(results.getHits(), null).getFieldAsString("key")).isEqualTo("S001");
+    assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
+    assertThat(Iterables.getLast(results.getHits(), null).key().rule()).isEqualTo("S001");
   }
 
   @Test
@@ -312,7 +315,7 @@ public class RuleIndexMediumTest {
     // from 0 to 1 included
     QueryOptions options = new QueryOptions();
     options.setOffset(0).setLimit(2);
-    Results results = index.search(new RuleQuery(), options);
+    Result results = index.search(new RuleQuery(), options);
     assertThat(results.getTotal()).isEqualTo(3);
     assertThat(results.getHits()).hasSize(2);
 
index 4819c562b7b80155b410606a3d2c62e7c98b2c7f..813ff213d12b7858653a6ed7f031b917ee308eef 100644 (file)
@@ -31,22 +31,17 @@ import org.sonar.api.utils.DateUtils;
 import org.sonar.check.Cardinality;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
 import org.sonar.core.qualityprofile.db.QualityProfileDao;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.core.rule.RuleParamDto;
 import org.sonar.core.rule.RuleRuleTagDto;
 import org.sonar.core.rule.RuleTagDao;
 import org.sonar.core.rule.RuleTagDto;
 import org.sonar.core.rule.RuleTagType;
-import org.sonar.server.search.Hit;
 import org.sonar.server.search.QueryOptions;
 import org.sonar.server.tester.ServerTester;
 
 import java.util.List;
-import java.util.Map;
 
 import static org.fest.assertions.Assertions.assertThat;
 
@@ -81,19 +76,20 @@ public class RuleServiceMediumTest {
 
     // verify that rule is indexed in es
     index.refresh();
-    Hit hit = index.getByKey(ruleKey);
+    Rule hit = index.getByKey(ruleKey);
     assertThat(hit).isNotNull();
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.REPOSITORY.key())).isEqualTo(ruleKey.repository());
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.KEY.key())).isEqualTo(ruleKey.rule());
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.LANGUAGE.key())).isEqualTo("js");
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.NAME.key())).isEqualTo("Rule S001");
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.HTML_DESCRIPTION.key())).isEqualTo("Description S001");
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.STATUS.key())).isEqualTo(RuleStatus.READY.toString());
-    assertThat(hit.getField(RuleNormalizer.RuleField.CREATED_AT.key())).isNotNull();
-    assertThat(hit.getField(RuleNormalizer.RuleField.UPDATED_AT.key())).isNotNull();
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.INTERNAL_KEY.key())).isEqualTo("InternalKeyS001");
-    assertThat(hit.getFieldAsString(RuleNormalizer.RuleField.SEVERITY.key())).isEqualTo("INFO");
-    assertThat((Boolean) hit.getField(RuleNormalizer.RuleField.TEMPLATE.key())).isFalse();
+    assertThat(hit.key().repository()).isEqualTo(ruleKey.repository());
+    assertThat(hit.key().rule()).isEqualTo(ruleKey.rule());
+    assertThat(hit.language()).isEqualTo("js");
+    assertThat(hit.name()).isEqualTo("Rule S001");
+    assertThat(hit.htmlDescription()).isEqualTo("Description S001");
+    assertThat(hit.status()).isEqualTo(RuleStatus.READY);
+    //TODO fix date in ES
+//    assertThat(hit.createdAt()).isNotNull();
+//    assertThat(hit.updatedAt()).isNotNull();
+    assertThat(hit.internalKey()).isEqualTo("InternalKeyS001");
+    assertThat(hit.severity()).isEqualTo("INFO");
+    assertThat(hit.template()).isFalse();
 
     //TODO    assertThat((Collection) hit.getField(RuleNormalizer.RuleField.SYSTEM_TAGS.key())).isEmpty();
     //TODO    assertThat((Collection) hit.getField(RuleNormalizer.RuleField.TAGS.key())).isEmpty();
@@ -131,9 +127,9 @@ public class RuleServiceMediumTest {
 
     // verify that parameters are indexed in es
     index.refresh();
-    Hit hit = index.getByKey(ruleKey);
+    Rule hit = index.getByKey(ruleKey);
     assertThat(hit).isNotNull();
-    assertThat(hit.getField(RuleNormalizer.RuleField.PARAMS.key())).isNotNull();
+    assertThat(hit.key()).isNotNull();
 
 
     RuleService service = tester.get(RuleService.class);
@@ -143,128 +139,6 @@ public class RuleServiceMediumTest {
     assertThat(Iterables.getLast(rule.params(), null).key()).isEqualTo("max");
   }
 
-  @Test
-  public void insert_and_index_activeRules() throws InterruptedException {
-    DbSession dbSession = tester.get(MyBatis.class).openSession(false);
-    ActiveRuleDao activeRuleDao = tester.get(ActiveRuleDao.class);
-
-    QualityProfileDto profileDto = new QualityProfileDto()
-      .setName("myprofile")
-      .setLanguage("java");
-    qualityProfileDao.insert(profileDto, dbSession);
-
-    // insert db
-    RuleKey ruleKey = RuleKey.of("javascript", "S001");
-    RuleDto ruleDto = newRuleDto(ruleKey);
-    dao.insert(ruleDto, dbSession);
-    dbSession.commit();
-
-    ActiveRuleDto activeRule = new ActiveRuleDto()
-      .setInheritance("inherited")
-      .setProfileId(profileDto.getId())
-      .setRuleId(ruleDto.getId())
-      .setSeverity(Severity.BLOCKER);
-
-    activeRuleDao.insert(activeRule, dbSession);
-    dbSession.commit();
-
-    dbSession.close();
-
-    // verify that activeRules are persisted in db
-    List<ActiveRuleDto> persistedDtos = activeRuleDao.selectByRuleId(ruleDto.getId());
-    assertThat(persistedDtos).hasSize(1);
-
-    // verify that activeRules are indexed in es
-    index.refresh();
-
-
-    Hit hit = index.getByKey(ruleKey);
-    assertThat(hit).isNotNull();
-    assertThat(hit.getField(RuleNormalizer.RuleField.ACTIVE.key())).isNotNull();
-
-    Map<String, Object> activeRules = (Map<String, Object>) hit.getField(RuleNormalizer.RuleField.ACTIVE.key());
-    assertThat(activeRules).hasSize(1);
-  }
-
-  @Test
-  public void insert_and_index_activeRuleParams() throws InterruptedException {
-    DbSession dbSession = tester.get(MyBatis.class).openSession(false);
-    ActiveRuleDao activeRuleDao = tester.get(ActiveRuleDao.class);
-
-    QualityProfileDto profileDto = new QualityProfileDto()
-      .setName("myprofile")
-      .setLanguage("java");
-    qualityProfileDao.insert(profileDto, dbSession);
-
-    // insert db
-    RuleKey ruleKey = RuleKey.of("javascript", "S001");
-    RuleDto ruleDto = newRuleDto(ruleKey);
-    dao.insert(ruleDto, dbSession);
-
-    RuleParamDto minParam = new RuleParamDto()
-      .setRuleId(ruleDto.getId())
-      .setName("min")
-      .setType("STRING");
-    dao.insert(minParam, dbSession);
-
-    RuleParamDto maxParam = new RuleParamDto()
-      .setRuleId(ruleDto.getId())
-      .setName("max")
-      .setType("STRING");
-    dao.insert(maxParam, dbSession);
-
-
-    ActiveRuleDto activeRule = new ActiveRuleDto()
-      .setInheritance("inherited")
-      .setProfileId(profileDto.getId())
-      .setRuleId(ruleDto.getId())
-      .setSeverity(Severity.BLOCKER);
-    activeRuleDao.insert(activeRule, dbSession);
-
-    ActiveRuleParamDto activeRuleMinParam = new ActiveRuleParamDto()
-      .setActiveRuleId(activeRule.getId())
-      .setKey(minParam.getName())
-      .setValue("minimum")
-      .setRulesParameterId(minParam.getId());
-    activeRuleDao.insert(activeRuleMinParam, dbSession);
-
-    ActiveRuleParamDto activeRuleMaxParam = new ActiveRuleParamDto()
-      .setActiveRuleId(activeRule.getId())
-      .setKey(maxParam.getName())
-      .setValue("maximum")
-      .setRulesParameterId(maxParam.getId());
-    activeRuleDao.insert(activeRuleMaxParam, dbSession);
-
-    dbSession.commit();
-    dbSession.close();
-
-    // verify that activeRulesParams are persisted in db
-    List<ActiveRuleParamDto> persistedDtos = activeRuleDao.selectParamsByActiveRuleId(activeRule.getId());
-    assertThat(persistedDtos).hasSize(2);
-
-    // verify that activeRulesParams are indexed in es
-    index.refresh();
-
-    Hit hit = index.getByKey(ruleKey);
-    assertThat(hit).isNotNull();
-
-    index.search(new RuleQuery(), new QueryOptions());
-
-    Map<String, Map> _activeRules = (Map<String, Map>) hit.getField(RuleNormalizer.RuleField.ACTIVE.key());
-    assertThat(_activeRules).isNotNull().hasSize(1);
-
-    Map<String, Object> _activeRule = (Map<String, Object>) Iterables.getFirst(_activeRules.values(),null);
-    assertThat(_activeRule.get(RuleNormalizer.RuleField.SEVERITY.key())).isEqualTo(Severity.BLOCKER);
-
-    Map<String, Map> _activeRuleParams = (Map<String, Map>) _activeRule.get(RuleNormalizer.RuleField.PARAMS.key());
-    assertThat(_activeRuleParams).isNotNull().hasSize(2);
-
-    Map<String, String> _activeRuleParamValue = (Map<String, String>) _activeRuleParams.get(maxParam.getName());
-    assertThat(_activeRuleParamValue).isNotNull().hasSize(1);
-    assertThat(_activeRuleParamValue.get(ActiveRuleNormalizer.ActiveRuleParamField.VALUE.key())).isEqualTo("maximum");
-
-  }
-
   //TODO test delete, update, tags, params
 
   @Test
@@ -319,9 +193,10 @@ public class RuleServiceMediumTest {
 
     // verify that tags are indexed in es
     index.search(new RuleQuery(), new QueryOptions());
-    Hit hit = index.getByKey(ruleKey);
+    Rule hit = index.getByKey(ruleKey);
     assertThat(hit).isNotNull();
-    assertThat(hit.getField(RuleNormalizer.RuleField.TAGS.key())).isNotNull();
+    assertThat(hit.tags()).containsExactly("hello","world");
+    assertThat(hit.systemTags()).containsExactly("AdMiN");
 
     RuleService service = tester.get(RuleService.class);
     Rule rule = service.getByKey(ruleKey);