From 5003d67caf574fdfda09b178575e64da88f34333 Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Thu, 25 Feb 2016 18:20:26 +0100 Subject: [PATCH] SONAR-7330 WS api/rules/show apply ES+DB pattern --- .../qualityprofile/db/ActiveRuleDao.java | 11 +++- .../server/rule/ws/ActiveRuleCompleter.java | 22 +++++-- .../org/sonar/server/rule/ws/RuleMapper.java | 5 +- .../sonar/server/rule/ws/SearchAction.java | 32 ++++++---- .../org/sonar/server/rule/ws/ShowAction.java | 52 ++++++++++++---- .../db/qualityprofile/ActiveRuleMapper.java | 2 +- .../db/qualityprofile/SqlActiveRuleKey.java | 59 +++++++++++++++++++ .../db/qualityprofile/ActiveRuleMapper.xml | 6 +- 8 files changed, 156 insertions(+), 33 deletions(-) create mode 100644 sonar-db/src/main/java/org/sonar/db/qualityprofile/SqlActiveRuleKey.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/db/ActiveRuleDao.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/db/ActiveRuleDao.java index 4e331f4c81b..604f077a301 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/db/ActiveRuleDao.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/db/ActiveRuleDao.java @@ -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, List>() { + List sqlKeys = new ArrayList<>(); + for (ActiveRuleKey key : keys) { + sqlKeys.add(new SqlActiveRuleKey(key)); + } + + return DatabaseUtils.executeLargeInputs(sqlKeys, new Function, List>() { @Override - public List apply(@Nonnull List input) { + public List apply(@Nonnull List input) { return mapper(dbSession).selectByKeys(input); } }); diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ActiveRuleCompleter.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ActiveRuleCompleter.java index 7b5c496db02..db51a5bd712 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ActiveRuleCompleter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ActiveRuleCompleter.java @@ -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.emptyList())); + void completeShow(DbSession dbSession, RuleDto rule, ShowResponse.Builder response) { + List activeRules = loader.findActiveRulesByRule(rule.getKey()); + List activeRuleDtos = dbClient.activeRuleDao().selectByActiveRuleKeys(dbSession, Lists.transform(activeRules, ActiveRuleToKey.INSTANCE)); + Map activeRuleIdsByKey = new HashMap<>(); + for (ActiveRuleDto activeRuleDto : activeRuleDtos) { + activeRuleIdsByKey.put(activeRuleDto.getId(), activeRuleDto.getKey()); + } + + List activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, Lists.transform(activeRuleDtos, ActiveRuleDtoToId.INSTANCE)); + ListMultimap 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()))); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java index 415cf1d34e9..ae4ea2e5343 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java @@ -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 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 diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java index 9d56a98f426..b1f389781ab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java @@ -386,10 +386,12 @@ public class SearchAction implements RulesWsAction { .toList(); List templateRules = dbClient.ruleDao().selectByIds(dbSession, templateRuleIds); List 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 rules; private final ListMultimap ruleParamsByRuleId; private final Map templateRulesByRuleId; - private final long total; - private final Facets facets; + private Long total; + private Facets facets; - public SearchResult(Result 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 getRules() { @@ -506,7 +506,7 @@ public class SearchAction implements RulesWsAction { return ruleParamsByRuleId; } - public SearchResult setRuleParams(List ruleParams) { + public SearchResult setRuleParameters(List 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 { diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ShowAction.java index ee9edb6c978..e07daf9cad4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ShowAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/ShowAction.java @@ -19,16 +19,24 @@ */ 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 optionalRule = dbClient.ruleDao().selectByKey(dbSession, key); + checkFoundWithOptional(optionalRule, "Rule not found: " + key); + RuleDto rule = optionalRule.get(); + List templateRules = new ArrayList<>(); + if (rule.getTemplateId() != null) { + Optional templateRule = dbClient.ruleDao().selectById(rule.getTemplateId(), dbSession); + if (templateRule.isPresent()) { + templateRules.add(templateRule.get()); + } + } + List 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.emptySet())); if (request.mandatoryParamAsBoolean(PARAM_ACTIVES)) { - activeRuleCompleter.completeShow(rule, responseBuilder); + activeRuleCompleter.completeShow(dbSession, rule, responseBuilder); } return responseBuilder.build(); diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java index d3c67a8abe1..cfe9e0d3c8c 100644 --- a/sonar-db/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java @@ -38,7 +38,7 @@ public interface ActiveRuleMapper { ActiveRuleDto selectByKey(@Param("profileKey") String profileKey, @Param("repository") String repository, @Param("rule") String rule); - List selectByKeys(@Param("keys") List keys); + List selectByKeys(@Param("keys") List keys); List 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 index 00000000000..3eeefc33e54 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/SqlActiveRuleKey.java @@ -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 { + 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; + } +} diff --git a/sonar-db/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml b/sonar-db/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml index c542ac5cb8e..00f008aca51 100644 --- a/sonar-db/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml @@ -96,9 +96,9 @@ WHERE - (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}) -- 2.39.5