You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BuiltInQProfileInsertImpl.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.qualityprofile;
  21. import com.google.common.base.Splitter;
  22. import com.google.common.collect.ImmutableSet;
  23. import com.google.common.collect.Sets;
  24. import java.util.Collections;
  25. import java.util.Date;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.Objects;
  30. import java.util.Optional;
  31. import java.util.Set;
  32. import java.util.function.Function;
  33. import java.util.stream.Collectors;
  34. import javax.annotation.CheckForNull;
  35. import javax.annotation.Nullable;
  36. import org.sonar.api.rule.RuleKey;
  37. import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
  38. import org.sonar.api.server.rule.RuleParamType;
  39. import org.sonar.api.utils.System2;
  40. import org.sonar.core.util.UuidFactory;
  41. import org.sonar.core.util.stream.MoreCollectors;
  42. import org.sonar.db.DbClient;
  43. import org.sonar.db.DbSession;
  44. import org.sonar.db.qualityprofile.ActiveRuleDto;
  45. import org.sonar.db.qualityprofile.ActiveRuleKey;
  46. import org.sonar.db.qualityprofile.ActiveRuleParamDto;
  47. import org.sonar.db.qualityprofile.DefaultQProfileDto;
  48. import org.sonar.db.qualityprofile.OrgQProfileDto;
  49. import org.sonar.db.qualityprofile.RulesProfileDto;
  50. import org.sonar.db.rule.RuleDefinitionDto;
  51. import org.sonar.db.rule.RuleParamDto;
  52. import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
  53. import org.sonar.server.util.TypeValidations;
  54. import static com.google.common.base.MoreObjects.firstNonNull;
  55. import static com.google.common.collect.Lists.newArrayList;
  56. import static java.util.Objects.requireNonNull;
  57. public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
  58. private final DbClient dbClient;
  59. private final System2 system2;
  60. private final UuidFactory uuidFactory;
  61. private final TypeValidations typeValidations;
  62. private final ActiveRuleIndexer activeRuleIndexer;
  63. private RuleRepository ruleRepository;
  64. public BuiltInQProfileInsertImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory, TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) {
  65. this.dbClient = dbClient;
  66. this.system2 = system2;
  67. this.uuidFactory = uuidFactory;
  68. this.typeValidations = typeValidations;
  69. this.activeRuleIndexer = activeRuleIndexer;
  70. }
  71. @Override
  72. public void create(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtInQProfile) {
  73. initRuleRepository(batchDbSession);
  74. Date now = new Date(system2.now());
  75. RulesProfileDto ruleProfile = insertRulesProfile(dbSession, builtInQProfile, now);
  76. List<ActiveRuleChange> changes = builtInQProfile.getActiveRules()
  77. .stream()
  78. .map(activeRule -> insertActiveRule(dbSession, ruleProfile, activeRule, now.getTime()))
  79. .collect(MoreCollectors.toList());
  80. changes.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null)));
  81. createDefaultAndOrgQProfiles(dbSession, batchDbSession, builtInQProfile, ruleProfile);
  82. // TODO batch statements should be executed through dbSession
  83. batchDbSession.commit();
  84. activeRuleIndexer.commitAndIndex(dbSession, changes);
  85. }
  86. private void createDefaultAndOrgQProfiles(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtIn, RulesProfileDto rulesProfileDto) {
  87. Optional<String> qProfileUuid = dbClient.defaultQProfileDao().selectDefaultQProfileUuid(dbSession, builtIn.getLanguage());
  88. OrgQProfileDto dto = new OrgQProfileDto()
  89. .setRulesProfileUuid(rulesProfileDto.getUuid())
  90. .setUuid(uuidFactory.create());
  91. if (builtIn.isDefault() && !qProfileUuid.isPresent()) {
  92. DefaultQProfileDto defaultQProfileDto = new DefaultQProfileDto()
  93. .setQProfileUuid(dto.getUuid())
  94. .setLanguage(builtIn.getLanguage());
  95. dbClient.defaultQProfileDao().insertOrUpdate(dbSession, defaultQProfileDto);
  96. }
  97. dbClient.qualityProfileDao().insert(batchDbSession, dto);
  98. }
  99. private void initRuleRepository(DbSession dbSession) {
  100. if (ruleRepository == null) {
  101. ruleRepository = new RuleRepository(dbClient, dbSession);
  102. }
  103. }
  104. private RulesProfileDto insertRulesProfile(DbSession dbSession, BuiltInQProfile builtIn, Date now) {
  105. RulesProfileDto dto = new RulesProfileDto()
  106. .setUuid(uuidFactory.create())
  107. .setName(builtIn.getName())
  108. .setLanguage(builtIn.getLanguage())
  109. .setIsBuiltIn(true)
  110. .setRulesUpdatedAtAsDate(now);
  111. dbClient.qualityProfileDao().insert(dbSession, dto);
  112. return dto;
  113. }
  114. private ActiveRuleChange insertActiveRule(DbSession dbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) {
  115. RuleKey ruleKey = activeRule.getRuleKey();
  116. RuleDefinitionDto ruleDefinitionDto = ruleRepository.getDefinition(ruleKey)
  117. .orElseThrow(() -> new IllegalStateException("RuleDefinition not found for key " + ruleKey));
  118. ActiveRuleDto dto = new ActiveRuleDto();
  119. dto.setProfileUuid(rulesProfileDto.getUuid());
  120. dto.setRuleUuid(ruleDefinitionDto.getUuid());
  121. dto.setKey(ActiveRuleKey.of(rulesProfileDto, ruleDefinitionDto.getKey()));
  122. dto.setSeverity(firstNonNull(activeRule.getSeverity(), ruleDefinitionDto.getSeverityString()));
  123. dto.setUpdatedAt(now);
  124. dto.setCreatedAt(now);
  125. dbClient.activeRuleDao().insert(dbSession, dto);
  126. List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(dbSession, activeRule, dto);
  127. ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, dto, ruleDefinitionDto);
  128. change.setSeverity(dto.getSeverityString());
  129. paramDtos.forEach(paramDto -> change.setParameter(paramDto.getKey(), paramDto.getValue()));
  130. return change;
  131. }
  132. private List<ActiveRuleParamDto> insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule,
  133. ActiveRuleDto activeRuleDto) {
  134. Map<String, String> valuesByParamKey = activeRule.getParams()
  135. .stream()
  136. .collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue));
  137. List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey())
  138. .stream()
  139. .map(param -> createParamDto(param, Optional.ofNullable(valuesByParamKey.get(param.getName())).orElse(param.getDefaultValue())))
  140. .filter(Objects::nonNull)
  141. .collect(Collectors.toList());
  142. rules.forEach(paramDto -> dbClient.activeRuleDao().insertParam(session, activeRuleDto, paramDto));
  143. return rules;
  144. }
  145. @CheckForNull
  146. private ActiveRuleParamDto createParamDto(RuleParamDto param, @Nullable String value) {
  147. if (value == null) {
  148. return null;
  149. }
  150. ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(param);
  151. paramDto.setValue(validateParam(param, value));
  152. return paramDto;
  153. }
  154. private String validateParam(RuleParamDto ruleParam, String value) {
  155. RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
  156. if (ruleParamType.multiple()) {
  157. List<String> values = newArrayList(Splitter.on(",").split(value));
  158. typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
  159. } else {
  160. typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
  161. }
  162. return value;
  163. }
  164. private static class RuleRepository {
  165. private final Map<RuleKey, RuleDefinitionDto> definitions;
  166. private final Map<RuleKey, Set<RuleParamDto>> params;
  167. private RuleRepository(DbClient dbClient, DbSession session) {
  168. this.definitions = dbClient.ruleDao().selectAllDefinitions(session)
  169. .stream()
  170. .collect(Collectors.toMap(RuleDefinitionDto::getKey, Function.identity()));
  171. Map<String, RuleKey> ruleUuidsByKey = definitions.values()
  172. .stream()
  173. .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getUuid, RuleDefinitionDto::getKey));
  174. this.params = new HashMap<>(ruleUuidsByKey.size());
  175. dbClient.ruleDao().selectRuleParamsByRuleKeys(session, definitions.keySet())
  176. .forEach(ruleParam -> params.compute(
  177. ruleUuidsByKey.get(ruleParam.getRuleUuid()),
  178. (key, value) -> {
  179. if (value == null) {
  180. return ImmutableSet.of(ruleParam);
  181. }
  182. return ImmutableSet.copyOf(Sets.union(value, Collections.singleton(ruleParam)));
  183. }));
  184. }
  185. private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
  186. return Optional.ofNullable(definitions.get(requireNonNull(ruleKey, "RuleKey can't be null")));
  187. }
  188. private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
  189. Set<RuleParamDto> res = params.get(requireNonNull(ruleKey, "RuleKey can't be null"));
  190. return res == null ? Collections.emptySet() : res;
  191. }
  192. }
  193. }