]> source.dussan.org Git - sonarqube.git/blob
82f9c27d338bd385dd54a4b129b07dffc1fcd74c
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 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.builtin;
21
22 import com.google.common.base.Splitter;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.Optional;
30 import java.util.Set;
31 import java.util.stream.Collectors;
32 import javax.annotation.CheckForNull;
33 import javax.annotation.Nullable;
34 import org.sonar.api.rule.RuleKey;
35 import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
36 import org.sonar.api.server.rule.RuleParamType;
37 import org.sonar.api.utils.System2;
38 import org.sonar.core.util.UuidFactory;
39 import org.sonar.core.util.stream.MoreCollectors;
40 import org.sonar.db.DbClient;
41 import org.sonar.db.DbSession;
42 import org.sonar.db.qualityprofile.ActiveRuleDto;
43 import org.sonar.db.qualityprofile.ActiveRuleKey;
44 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
45 import org.sonar.db.qualityprofile.DefaultQProfileDto;
46 import org.sonar.db.qualityprofile.OrgQProfileDto;
47 import org.sonar.db.qualityprofile.RulesProfileDto;
48 import org.sonar.db.rule.RuleDto;
49 import org.sonar.db.rule.RuleParamDto;
50 import org.sonar.server.qualityprofile.ActiveRuleChange;
51 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
52 import org.sonar.server.rule.ServerRuleFinder;
53 import org.sonar.server.util.TypeValidations;
54
55 import static com.google.common.base.MoreObjects.firstNonNull;
56 import static com.google.common.collect.Lists.newArrayList;
57 import static java.util.Collections.emptySet;
58 import static java.util.Objects.requireNonNull;
59
60 public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
61   private final DbClient dbClient;
62   private final ServerRuleFinder ruleFinder;
63   private final System2 system2;
64   private final UuidFactory uuidFactory;
65   private final TypeValidations typeValidations;
66   private final ActiveRuleIndexer activeRuleIndexer;
67   private RuleRepository ruleRepository;
68
69   public BuiltInQProfileInsertImpl(DbClient dbClient, ServerRuleFinder ruleFinder, System2 system2, UuidFactory uuidFactory,
70     TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) {
71     this.dbClient = dbClient;
72     this.ruleFinder = ruleFinder;
73     this.system2 = system2;
74     this.uuidFactory = uuidFactory;
75     this.typeValidations = typeValidations;
76     this.activeRuleIndexer = activeRuleIndexer;
77   }
78
79   @Override
80   public void create(DbSession batchDbSession, BuiltInQProfile builtInQProfile) {
81     initRuleRepository(batchDbSession);
82
83     Date now = new Date(system2.now());
84     RulesProfileDto ruleProfile = insertRulesProfile(batchDbSession, builtInQProfile, now);
85
86     List<ActiveRuleChange> changes = builtInQProfile.getActiveRules().stream()
87       .map(activeRule -> insertActiveRule(batchDbSession, ruleProfile, activeRule, now.getTime()))
88       .collect(MoreCollectors.toList());
89
90     changes.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null)));
91
92     createDefaultAndOrgQProfiles(batchDbSession, builtInQProfile, ruleProfile);
93
94     activeRuleIndexer.commitAndIndex(batchDbSession, changes);
95   }
96
97
98   private void createDefaultAndOrgQProfiles(DbSession batchDbSession, BuiltInQProfile builtIn, RulesProfileDto rulesProfileDto) {
99     Optional<String> qProfileUuid = dbClient.defaultQProfileDao().selectDefaultQProfileUuid(batchDbSession, builtIn.getLanguage());
100
101     OrgQProfileDto dto = new OrgQProfileDto()
102       .setRulesProfileUuid(rulesProfileDto.getUuid())
103       .setUuid(uuidFactory.create());
104
105     if (builtIn.isDefault() && qProfileUuid.isEmpty()) {
106       DefaultQProfileDto defaultQProfileDto = new DefaultQProfileDto()
107         .setQProfileUuid(dto.getUuid())
108         .setLanguage(builtIn.getLanguage());
109       dbClient.defaultQProfileDao().insert(batchDbSession, defaultQProfileDto);
110     }
111
112     dbClient.qualityProfileDao().insert(batchDbSession, dto);
113   }
114
115   private void initRuleRepository(DbSession dbSession) {
116     if (ruleRepository == null) {
117       ruleRepository = new RuleRepository(dbClient, dbSession, ruleFinder);
118     }
119   }
120
121   private RulesProfileDto insertRulesProfile(DbSession dbSession, BuiltInQProfile builtIn, Date now) {
122     RulesProfileDto dto = new RulesProfileDto()
123       .setUuid(uuidFactory.create())
124       .setName(builtIn.getName())
125       .setLanguage(builtIn.getLanguage())
126       .setIsBuiltIn(true)
127       .setRulesUpdatedAtAsDate(now);
128     dbClient.qualityProfileDao().insert(dbSession, dto);
129     return dto;
130   }
131
132   private ActiveRuleChange insertActiveRule(DbSession batchDbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) {
133     RuleKey ruleKey = activeRule.getRuleKey();
134     RuleDto ruleDefinitionDto = ruleRepository.getDefinition(ruleKey)
135       .orElseThrow(() -> new IllegalStateException("RuleDefinition not found for key " + ruleKey));
136
137     ActiveRuleDto dto = new ActiveRuleDto();
138     dto.setProfileUuid(rulesProfileDto.getUuid());
139     dto.setRuleUuid(ruleDefinitionDto.getUuid());
140     dto.setKey(ActiveRuleKey.of(rulesProfileDto, ruleDefinitionDto.getKey()));
141     dto.setSeverity(firstNonNull(activeRule.getSeverity(), ruleDefinitionDto.getSeverityString()));
142     dto.setUpdatedAt(now);
143     dto.setCreatedAt(now);
144     dbClient.activeRuleDao().insert(batchDbSession, dto);
145
146     List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(batchDbSession, activeRule, dto);
147
148     ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, dto, ruleDefinitionDto);
149     change.setSeverity(dto.getSeverityString());
150     paramDtos.forEach(paramDto -> change.setParameter(paramDto.getKey(), paramDto.getValue()));
151     return change;
152   }
153
154   private List<ActiveRuleParamDto> insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule, ActiveRuleDto activeRuleDto) {
155     Map<String, String> valuesByParamKey = activeRule.getParams().stream()
156       .collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue));
157     List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey()).stream()
158       .map(param -> createParamDto(param, Optional.ofNullable(valuesByParamKey.get(param.getName())).orElse(param.getDefaultValue())))
159       .filter(Objects::nonNull)
160       .collect(Collectors.toList());
161
162     rules.forEach(paramDto -> dbClient.activeRuleDao().insertParam(session, activeRuleDto, paramDto));
163     return rules;
164   }
165
166   @CheckForNull
167   private ActiveRuleParamDto createParamDto(RuleParamDto param, @Nullable String value) {
168     if (value == null) {
169       return null;
170     }
171     ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(param);
172     paramDto.setValue(validateParam(param, value));
173     return paramDto;
174   }
175
176   private String validateParam(RuleParamDto ruleParam, String value) {
177     RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
178     if (ruleParamType.multiple()) {
179       List<String> values = newArrayList(Splitter.on(",").split(value));
180       typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
181     } else {
182       typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
183     }
184     return value;
185   }
186
187   private static class RuleRepository {
188     private final Map<RuleKey, Set<RuleParamDto>> params;
189     private final ServerRuleFinder ruleFinder;
190
191     private RuleRepository(DbClient dbClient, DbSession session, ServerRuleFinder ruleFinder) {
192       this.ruleFinder = ruleFinder;
193       this.params = new HashMap<>();
194
195       for (RuleParamDto ruleParam : dbClient.ruleDao().selectAllRuleParams(session)) {
196         Optional<RuleKey> ruleKey = ruleFinder.findDtoByUuid(ruleParam.getRuleUuid())
197           .map(r -> RuleKey.of(r.getRepositoryKey(), r.getRuleKey()));
198
199         if (ruleKey.isPresent()) {
200           params.computeIfAbsent(ruleKey.get(), r -> new HashSet<>()).add(ruleParam);
201         }
202       }
203     }
204
205     private Optional<RuleDto> getDefinition(RuleKey ruleKey) {
206       return ruleFinder.findDtoByKey(requireNonNull(ruleKey, "RuleKey can't be null"));
207     }
208
209     private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
210       return params.getOrDefault(requireNonNull(ruleKey, "RuleKey can't be null"), emptySet());
211     }
212   }
213 }