]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7330 WS api/rules/show apply ES+DB pattern
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 25 Feb 2016 17:20:26 +0000 (18:20 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 26 Feb 2016 09:07:22 +0000 (10:07 +0100)
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/db/ActiveRuleDao.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/ActiveRuleCompleter.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/ShowAction.java
sonar-db/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java
sonar-db/src/main/java/org/sonar/db/qualityprofile/SqlActiveRuleKey.java [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml

index 4e331f4c81b1018fdee2f1b5e4741927fe4a2338..604f077a3013e2b99cfd6f9465433cafd6932218 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile.db;
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import java.util.ArrayList;
 import java.util.List;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
@@ -31,6 +32,7 @@ import org.sonar.db.DatabaseUtils;
 import org.sonar.db.DbSession;
 import org.sonar.db.qualityprofile.ActiveRuleDto;
 import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.db.qualityprofile.SqlActiveRuleKey;
 import org.sonar.db.qualityprofile.ActiveRuleMapper;
 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
 import org.sonar.db.qualityprofile.QualityProfileDao;
@@ -137,9 +139,14 @@ public class ActiveRuleDao extends BaseDao<ActiveRuleMapper, ActiveRuleDto, Acti
       return emptyList();
     }
 
-    return DatabaseUtils.executeLargeInputs(keys, new Function<List<ActiveRuleKey>, List<ActiveRuleDto>>() {
+    List<SqlActiveRuleKey> sqlKeys = new ArrayList<>();
+    for (ActiveRuleKey key : keys) {
+      sqlKeys.add(new SqlActiveRuleKey(key));
+    }
+
+    return DatabaseUtils.executeLargeInputs(sqlKeys, new Function<List<SqlActiveRuleKey>, List<ActiveRuleDto>>() {
       @Override
-      public List<ActiveRuleDto> apply(@Nonnull List<ActiveRuleKey> input) {
+      public List<ActiveRuleDto> apply(@Nonnull List<SqlActiveRuleKey> input) {
         return mapper(dbSession).selectByKeys(input);
       }
     });
index 7b5c496db02463a8c15010e7545e1683c37972b9..db51a5bd71271d8996caf78f2c481c8fb0c4057a 100644 (file)
@@ -26,7 +26,6 @@ import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -47,7 +46,6 @@ import org.sonar.db.rule.RuleDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.qualityprofile.ActiveRule;
 import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.rule.Rule;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonarqube.ws.Rules;
 import org.sonarqube.ws.Rules.SearchResponse;
@@ -125,9 +123,23 @@ public class ActiveRuleCompleter {
     return qProfileKeys;
   }
 
-  void completeShow(Rule rule, ShowResponse.Builder response) {
-    for (ActiveRule activeRule : loader.findActiveRulesByRule(rule.key())) {
-      response.addActives(buildActiveRuleResponse(activeRule, Collections.<ActiveRuleParamDto>emptyList()));
+  void completeShow(DbSession dbSession, RuleDto rule, ShowResponse.Builder response) {
+    List<ActiveRule> activeRules = loader.findActiveRulesByRule(rule.getKey());
+    List<ActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByActiveRuleKeys(dbSession, Lists.transform(activeRules, ActiveRuleToKey.INSTANCE));
+    Map<Integer, ActiveRuleKey> activeRuleIdsByKey = new HashMap<>();
+    for (ActiveRuleDto activeRuleDto : activeRuleDtos) {
+      activeRuleIdsByKey.put(activeRuleDto.getId(), activeRuleDto.getKey());
+    }
+
+    List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, Lists.transform(activeRuleDtos, ActiveRuleDtoToId.INSTANCE));
+    ListMultimap<ActiveRuleKey, ActiveRuleParamDto> activeRuleParamsByActiveRuleKey = ArrayListMultimap.create(activeRules.size(), 10);
+    for (ActiveRuleParamDto activeRuleParamDto : activeRuleParamDtos) {
+      ActiveRuleKey activeRuleKey = activeRuleIdsByKey.get(activeRuleParamDto.getId());
+      activeRuleParamsByActiveRuleKey.put(activeRuleKey, activeRuleParamDto);
+    }
+
+    for (ActiveRule activeRule : activeRules) {
+      response.addActives(buildActiveRuleResponse(activeRule, activeRuleParamsByActiveRuleKey.get(activeRule.key())));
     }
   }
 
index 415cf1d34e994dfd987e445142da149333f3fc07..ae4ea2e5343e9549e11fdd10b456f239338f1aa4 100644 (file)
@@ -54,6 +54,9 @@ public class RuleMapper {
     this.macroInterpreter = macroInterpreter;
   }
 
+  /**
+   * Convert a RuleDto to WsRule. If fieldsToReturn is empty all the fields are returned
+   */
   public Rules.Rule toWsRule(RuleDto ruleDto, SearchResult result, Set<String> fieldsToReturn) {
     Rules.Rule.Builder ruleResponse = Rules.Rule.newBuilder();
 
@@ -286,7 +289,7 @@ public class RuleMapper {
   private static DebtRemediationFunction debtRemediationFunction(final RuleDto ruleDto) {
     final String function = ruleDto.getRemediationFunction();
     if (function == null || function.isEmpty()) {
-      return null;
+      return defaultDebtRemediationFunction(ruleDto);
     } else {
       return new DebtRemediationFunction() {
         @Override
index 9d56a98f4262723e83b35bf0ac76d2d792c278e9..b1f389781ab62945dd14c6ed8cbd2b7344e13ebd 100644 (file)
@@ -386,10 +386,12 @@ public class SearchAction implements RulesWsAction {
       .toList();
     List<RuleDto> templateRules = dbClient.ruleDao().selectByIds(dbSession, templateRuleIds);
     List<RuleParamDto> ruleParamDtos = dbClient.ruleDao().selectRuleParamsByRuleIds(dbSession, ruleIds);
-    return new SearchResult(result)
+    return new SearchResult()
       .setRules(rules)
-      .setRuleParams(ruleParamDtos)
-      .setTemplateRules(templateRules);
+      .setRuleParameters(ruleParamDtos)
+      .setTemplateRules(templateRules)
+      .setFacets(result.getFacetsObject())
+      .setTotal(result.getTotal());
   }
 
   protected RuleQuery doQuery(Request request) {
@@ -482,15 +484,13 @@ public class SearchAction implements RulesWsAction {
     private List<RuleDto> rules;
     private final ListMultimap<Integer, RuleParamDto> ruleParamsByRuleId;
     private final Map<Integer, RuleDto> templateRulesByRuleId;
-    private final long total;
-    private final Facets facets;
+    private Long total;
+    private Facets facets;
 
-    public SearchResult(Result<Rule> result) {
+    public SearchResult() {
       this.rules = new ArrayList<>();
       this.ruleParamsByRuleId = ArrayListMultimap.create();
       this.templateRulesByRuleId = new HashMap<>();
-      this.total = result.getTotal();
-      this.facets = result.getFacetsObject();
     }
 
     public List<RuleDto> getRules() {
@@ -506,7 +506,7 @@ public class SearchAction implements RulesWsAction {
       return ruleParamsByRuleId;
     }
 
-    public SearchResult setRuleParams(List<RuleParamDto> ruleParams) {
+    public SearchResult setRuleParameters(List<RuleParamDto> ruleParams) {
       ruleParamsByRuleId.clear();
       for (RuleParamDto ruleParam : ruleParams) {
         ruleParamsByRuleId.put(ruleParam.getRuleId(), ruleParam);
@@ -526,13 +526,25 @@ public class SearchAction implements RulesWsAction {
       return this;
     }
 
-    public long getTotal() {
+    @CheckForNull
+    public Long getTotal() {
       return total;
     }
 
+    public SearchResult setTotal(Long total) {
+      this.total = total;
+      return this;
+    }
+
+    @CheckForNull
     public Facets getFacets() {
       return facets;
     }
+
+    public SearchResult setFacets(Facets facets) {
+      this.facets = facets;
+      return this;
+    }
   }
 
   private enum RuleDtoToId implements Function<RuleDto, Integer> {
index ee9edb6c978bc83af6986985fb116aaea95c2186..e07daf9cad40f91d0cadfb10ea0aaa37596f02ff 100644 (file)
  */
 package org.sonar.server.rule.ws;
 
+import com.google.common.base.Optional;
 import com.google.common.io.Resources;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.rule.Rule;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.db.rule.RuleParamDto;
 import org.sonar.server.rule.RuleService;
 import org.sonarqube.ws.Rules.ShowResponse;
 
+import static java.util.Collections.singletonList;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 /**
@@ -39,14 +47,18 @@ public class ShowAction implements RulesWsAction {
   public static final String PARAM_KEY = "key";
   public static final String PARAM_ACTIVES = "actives";
 
+  private final DbClient dbClient;
   private final RuleService service;
   private final RuleMapping mapping;
+  private final RuleMapper mapper;
   private final ActiveRuleCompleter activeRuleCompleter;
 
-  public ShowAction(RuleService service, ActiveRuleCompleter activeRuleCompleter, RuleMapping mapping) {
+  public ShowAction(DbClient dbClient, RuleService service, RuleMapping mapping, RuleMapper mapper, ActiveRuleCompleter activeRuleCompleter) {
+    this.dbClient = dbClient;
     this.service = service;
     this.mapping = mapping;
     this.activeRuleCompleter = activeRuleCompleter;
+    this.mapper = mapper;
   }
 
   @Override
@@ -74,21 +86,39 @@ public class ShowAction implements RulesWsAction {
   @Override
   public void handle(Request request, Response response) throws Exception {
     RuleKey key = RuleKey.parse(request.mandatoryParam(PARAM_KEY));
-    Rule rule = service.getByKey(key);
-    if (rule == null) {
-      throw new NotFoundException("Rule not found: " + key);
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<RuleDto> optionalRule = dbClient.ruleDao().selectByKey(dbSession, key);
+      checkFoundWithOptional(optionalRule, "Rule not found: " + key);
+      RuleDto rule = optionalRule.get();
+      List<RuleDto> templateRules = new ArrayList<>();
+      if (rule.getTemplateId() != null) {
+        Optional<RuleDto> templateRule = dbClient.ruleDao().selectById(rule.getTemplateId(), dbSession);
+        if (templateRule.isPresent()) {
+          templateRules.add(templateRule.get());
+        }
+      }
+      List<RuleParamDto> ruleParameters = dbClient.ruleDao().selectRuleParamsByRuleIds(dbSession, singletonList(rule.getId()));
+      ShowResponse showResponse = buildResponse(dbSession, request,
+        new SearchAction.SearchResult()
+          .setRules(singletonList(rule))
+          .setTemplateRules(templateRules)
+          .setRuleParameters(ruleParameters)
+          .setTotal(1L));
+      writeProtobuf(showResponse, request, response);
+    } finally {
+      dbClient.closeSession(dbSession);
     }
 
-    ShowResponse showResponse = buildResponse(request, rule);
-    writeProtobuf(showResponse, request, response);
   }
 
-  private ShowResponse buildResponse(Request request, Rule rule) {
+  private ShowResponse buildResponse(DbSession dbSession, Request request, SearchAction.SearchResult searchResult) {
     ShowResponse.Builder responseBuilder = ShowResponse.newBuilder();
-    responseBuilder.setRule(mapping.buildRuleResponse(rule, null /* TODO replace by SearchOptions immutable constant */));
+    RuleDto rule = searchResult.getRules().get(0);
+    responseBuilder.setRule(mapper.toWsRule(rule, searchResult, Collections.<String>emptySet()));
 
     if (request.mandatoryParamAsBoolean(PARAM_ACTIVES)) {
-      activeRuleCompleter.completeShow(rule, responseBuilder);
+      activeRuleCompleter.completeShow(dbSession, rule, responseBuilder);
     }
 
     return responseBuilder.build();
index d3c67a8abe1ae4bd62e82d93afabe617d024051b..cfe9e0d3c8cc68991709859efdec28590068f048 100644 (file)
@@ -38,7 +38,7 @@ public interface ActiveRuleMapper {
 
   ActiveRuleDto selectByKey(@Param("profileKey") String profileKey, @Param("repository") String repository, @Param("rule") String rule);
 
-  List<ActiveRuleDto> selectByKeys(@Param("keys") List<ActiveRuleKey> keys);
+  List<ActiveRuleDto> selectByKeys(@Param("keys") List<SqlActiveRuleKey> keys);
 
   List<ActiveRuleDto> selectByRuleId(int ruleId);
 
diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/SqlActiveRuleKey.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/SqlActiveRuleKey.java
new file mode 100644 (file)
index 0000000..3eeefc3
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.db.qualityprofile;
+
+public class SqlActiveRuleKey implements Comparable<SqlActiveRuleKey> {
+  private final String qProfile;
+  private final String rule;
+  private final String repository;
+
+  public SqlActiveRuleKey(ActiveRuleKey key) {
+    this.qProfile = key.qProfile();
+    this.rule = key.ruleKey().rule();
+    this.repository = key.ruleKey().repository();
+  }
+
+  @Override
+  public int compareTo(SqlActiveRuleKey o) {
+    int result = qProfile.compareTo(o.qProfile);
+    if (result != 0) {
+      return result;
+    }
+    result = rule.compareTo(o.rule);
+    if (result != 0) {
+      return result;
+    }
+
+    return repository.compareTo(o.repository);
+  }
+
+  public String getqProfile() {
+    return qProfile;
+  }
+
+  public String getRule() {
+    return rule;
+  }
+
+  public String getRepository() {
+    return repository;
+  }
+}
index c542ac5cb8e6b8fe07ed7c9db632e51671a5ae3c..00f008aca51099ec6f9563b603b6ef307875acde 100644 (file)
@@ -96,9 +96,9 @@
     <include refid="activeRuleKeyJoin"/>
     WHERE
     <foreach collection="keys" item="key" open="(" separator=" or " close=")">
-      (qp.kee = #{key.qProfile()}
-      AND r.plugin_rule_key = #{key.ruleKey().rule()}
-      AND r.plugin_name = #{key.ruleKey().repository()})
+      (qp.kee = #{key.qProfile}
+      AND r.plugin_rule_key = #{key.rule}
+      AND r.plugin_name = #{key.repository})
     </foreach>
   </select>