]> source.dussan.org Git - sonarqube.git/blob
8eab984a5fd8a88812c24a33715f77f05dacd4e9
[sonarqube.git] /
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
22 import com.google.common.base.Splitter;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Sets;
25 import java.util.Collections;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.Optional;
32 import java.util.Set;
33 import java.util.function.Function;
34 import java.util.stream.Collectors;
35 import javax.annotation.CheckForNull;
36 import javax.annotation.Nullable;
37 import org.sonar.api.rule.RuleKey;
38 import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
39 import org.sonar.api.server.rule.RuleParamType;
40 import org.sonar.api.utils.System2;
41 import org.sonar.core.util.UuidFactory;
42 import org.sonar.core.util.stream.MoreCollectors;
43 import org.sonar.db.DbClient;
44 import org.sonar.db.DbSession;
45 import org.sonar.db.qualityprofile.ActiveRuleDto;
46 import org.sonar.db.qualityprofile.ActiveRuleKey;
47 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
48 import org.sonar.db.qualityprofile.DefaultQProfileDto;
49 import org.sonar.db.qualityprofile.OrgQProfileDto;
50 import org.sonar.db.qualityprofile.RulesProfileDto;
51 import org.sonar.db.rule.RuleDefinitionDto;
52 import org.sonar.db.rule.RuleParamDto;
53 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
54 import org.sonar.server.util.TypeValidations;
55
56 import static com.google.common.base.MoreObjects.firstNonNull;
57 import static com.google.common.collect.Lists.newArrayList;
58 import static java.util.Objects.requireNonNull;
59
60 public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
61   private final DbClient dbClient;
62   private final System2 system2;
63   private final UuidFactory uuidFactory;
64   private final TypeValidations typeValidations;
65   private final ActiveRuleIndexer activeRuleIndexer;
66   private RuleRepository ruleRepository;
67
68   public BuiltInQProfileInsertImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory, TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) {
69     this.dbClient = dbClient;
70     this.system2 = system2;
71     this.uuidFactory = uuidFactory;
72     this.typeValidations = typeValidations;
73     this.activeRuleIndexer = activeRuleIndexer;
74   }
75
76   @Override
77   public void create(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtInQProfile) {
78     initRuleRepository(batchDbSession);
79
80     Date now = new Date(system2.now());
81     RulesProfileDto ruleProfile = insertRulesProfile(dbSession, builtInQProfile, now);
82
83     List<ActiveRuleChange> changes = builtInQProfile.getActiveRules()
84       .stream()
85       .map(activeRule -> insertActiveRule(dbSession, ruleProfile, activeRule, now.getTime()))
86       .collect(MoreCollectors.toList());
87
88     changes.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null)));
89
90     createDefaultAndOrgQProfiles(dbSession, batchDbSession, builtInQProfile, ruleProfile);
91
92     // TODO batch statements should be executed through dbSession
93     batchDbSession.commit();
94
95     activeRuleIndexer.commitAndIndex(dbSession, changes);
96   }
97
98   private void createDefaultAndOrgQProfiles(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtIn, RulesProfileDto rulesProfileDto) {
99     Optional<String> qProfileUuid = dbClient.defaultQProfileDao().selectDefaultQProfileUuid(dbSession, builtIn.getLanguage());
100
101     OrgQProfileDto dto = new OrgQProfileDto()
102       .setRulesProfileUuid(rulesProfileDto.getUuid())
103       .setUuid(uuidFactory.create());
104
105     if (builtIn.isDefault() && !qProfileUuid.isPresent()) {
106       DefaultQProfileDto defaultQProfileDto = new DefaultQProfileDto()
107         .setQProfileUuid(dto.getUuid())
108         .setLanguage(builtIn.getLanguage());
109       dbClient.defaultQProfileDao().insertOrUpdate(dbSession, 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);
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 dbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) {
133     RuleKey ruleKey = activeRule.getRuleKey();
134     RuleDefinitionDto 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(dbSession, dto);
145
146     List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(dbSession, 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,
155     ActiveRuleDto activeRuleDto) {
156     Map<String, String> valuesByParamKey = activeRule.getParams()
157       .stream()
158       .collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue));
159     List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey())
160       .stream()
161       .map(param -> createParamDto(param, Optional.ofNullable(valuesByParamKey.get(param.getName())).orElse(param.getDefaultValue())))
162       .filter(Objects::nonNull)
163       .collect(Collectors.toList());
164
165     rules.forEach(paramDto -> dbClient.activeRuleDao().insertParam(session, activeRuleDto, paramDto));
166     return rules;
167   }
168
169   @CheckForNull
170   private ActiveRuleParamDto createParamDto(RuleParamDto param, @Nullable String value) {
171     if (value == null) {
172       return null;
173     }
174     ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(param);
175     paramDto.setValue(validateParam(param, value));
176     return paramDto;
177   }
178
179   private String validateParam(RuleParamDto ruleParam, String value) {
180     RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
181     if (ruleParamType.multiple()) {
182       List<String> values = newArrayList(Splitter.on(",").split(value));
183       typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
184     } else {
185       typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
186     }
187     return value;
188   }
189
190   private static class RuleRepository {
191     private final Map<RuleKey, RuleDefinitionDto> definitions;
192     private final Map<RuleKey, Set<RuleParamDto>> params;
193
194     private RuleRepository(DbClient dbClient, DbSession session) {
195       this.definitions = dbClient.ruleDao().selectAllDefinitions(session)
196         .stream()
197         .collect(Collectors.toMap(RuleDefinitionDto::getKey, Function.identity()));
198       Map<String, RuleKey> ruleUuidsByKey = definitions.values()
199         .stream()
200         .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getUuid, RuleDefinitionDto::getKey));
201       this.params = new HashMap<>(ruleUuidsByKey.size());
202       dbClient.ruleDao().selectRuleParamsByRuleKeys(session, definitions.keySet())
203         .forEach(ruleParam -> params.compute(
204           ruleUuidsByKey.get(ruleParam.getRuleUuid()),
205           (key, value) -> {
206             if (value == null) {
207               return ImmutableSet.of(ruleParam);
208             }
209             return ImmutableSet.copyOf(Sets.union(value, Collections.singleton(ruleParam)));
210           }));
211     }
212
213     private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
214       return Optional.ofNullable(definitions.get(requireNonNull(ruleKey, "RuleKey can't be null")));
215     }
216
217     private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
218       Set<RuleParamDto> res = params.get(requireNonNull(ruleKey, "RuleKey can't be null"));
219       return res == null ? Collections.emptySet() : res;
220     }
221   }
222 }