3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.ce.task.projectanalysis.issue;
22 import com.google.common.collect.Multimap;
23 import java.util.Collections;
24 import java.util.HashMap;
26 import java.util.Optional;
28 import java.util.function.Supplier;
29 import javax.annotation.CheckForNull;
30 import org.sonar.api.rule.RuleKey;
31 import org.sonar.api.rule.RuleStatus;
32 import org.sonar.api.rules.RuleType;
33 import org.sonar.api.server.debt.DebtRemediationFunction;
34 import org.sonar.core.util.stream.MoreCollectors;
35 import org.sonar.db.DbClient;
36 import org.sonar.db.DbSession;
37 import org.sonar.db.rule.DeprecatedRuleKeyDto;
38 import org.sonar.db.rule.RuleDto;
40 import static com.google.common.base.Preconditions.checkArgument;
41 import static java.util.Objects.requireNonNull;
43 public class RuleRepositoryImpl implements RuleRepository {
46 private Map<RuleKey, Rule> rulesByKey;
48 private Map<String, Rule> rulesByUuid;
50 private final AdHocRuleCreator creator;
51 private final DbClient dbClient;
53 private Map<RuleKey, NewAdHocRule> adHocRulesPersist = new HashMap<>();
55 public RuleRepositoryImpl(AdHocRuleCreator creator, DbClient dbClient) {
56 this.creator = creator;
57 this.dbClient = dbClient;
60 public void addOrUpdateAddHocRuleIfNeeded(RuleKey ruleKey, Supplier<NewAdHocRule> ruleSupplier) {
63 Rule existingRule = rulesByKey.get(ruleKey);
64 if (existingRule == null || (existingRule.isAdHoc() && !adHocRulesPersist.containsKey(ruleKey))) {
65 NewAdHocRule newAdHocRule = ruleSupplier.get();
66 adHocRulesPersist.put(ruleKey, newAdHocRule);
67 rulesByKey.put(ruleKey, new AdHocRuleWrapper(newAdHocRule));
72 public void saveOrUpdateAddHocRules(DbSession dbSession) {
75 adHocRulesPersist.values().forEach(r -> persistAndIndex(dbSession, r));
78 private void persistAndIndex(DbSession dbSession, NewAdHocRule adHocRule) {
79 Rule rule = new RuleImpl(creator.persistAndIndex(dbSession, adHocRule));
80 rulesByUuid.put(rule.getUuid(), rule);
81 rulesByKey.put(adHocRule.getKey(), rule);
85 public Rule getByKey(RuleKey key) {
86 verifyKeyArgument(key);
90 Rule rule = rulesByKey.get(key);
91 checkArgument(rule != null, "Can not find rule for key %s. This rule does not exist in DB", key);
96 public Optional<Rule> findByKey(RuleKey key) {
97 verifyKeyArgument(key);
101 return Optional.ofNullable(rulesByKey.get(key));
105 public Rule getByUuid(String uuid) {
108 Rule rule = rulesByUuid.get(uuid);
109 checkArgument(rule != null, "Can not find rule for uuid %s. This rule does not exist in DB", uuid);
114 public Optional<Rule> findByUuid(String uuid) {
117 return Optional.ofNullable(rulesByUuid.get(uuid));
120 private static void verifyKeyArgument(RuleKey key) {
121 requireNonNull(key, "RuleKey can not be null");
124 private void ensureInitialized() {
125 if (rulesByKey == null) {
126 try (DbSession dbSession = dbClient.openSession(false)) {
127 loadRulesFromDb(dbSession);
132 private void loadRulesFromDb(DbSession dbSession) {
133 this.rulesByKey = new HashMap<>();
134 this.rulesByUuid = new HashMap<>();
135 Multimap<String, DeprecatedRuleKeyDto> deprecatedRuleKeysByRuleUuid = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession).stream()
136 .collect(MoreCollectors.index(DeprecatedRuleKeyDto::getRuleUuid));
137 for (RuleDto ruleDto : dbClient.ruleDao().selectAll(dbSession)) {
138 Rule rule = new RuleImpl(ruleDto);
139 rulesByKey.put(ruleDto.getKey(), rule);
140 rulesByUuid.put(ruleDto.getUuid(), rule);
141 deprecatedRuleKeysByRuleUuid.get(ruleDto.getUuid()).forEach(t -> rulesByKey.put(RuleKey.of(t.getOldRepositoryKey(), t.getOldRuleKey()), rule));
145 private static class AdHocRuleWrapper implements Rule {
146 private final NewAdHocRule addHocRule;
148 private AdHocRuleWrapper(NewAdHocRule addHocRule) {
149 this.addHocRule = addHocRule;
152 public NewAdHocRule getDelegate() {
157 public String getUuid() {
158 throw new UnsupportedOperationException("Rule is not persisted, can't know the uuid");
162 public RuleKey getKey() {
163 return addHocRule.getKey();
167 public String getName() {
168 return addHocRule.getName();
173 public String getLanguage() {
178 public RuleStatus getStatus() {
179 return RuleStatus.defaultStatus();
184 public RuleType getType() {
189 public boolean isExternal() {
194 public boolean isAdHoc() {
199 public Set<String> getTags() {
200 return Collections.emptySet();
205 public DebtRemediationFunction getRemediationFunction() {
211 public String getPluginKey() {
216 public String getDefaultRuleDescription() {
217 return addHocRule.getDescription();
221 public String getSeverity() {
222 return addHocRule.getSeverity();