]> source.dussan.org Git - sonarqube.git/blob
8c3b290b79ed2a4ff59bd9f53bbc264716ff429c
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2020 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     return ruleRepository.getRuleParams(activeRule.getRuleKey())
160       .stream()
161       .map(param -> {
162         String activeRuleValue = valuesByParamKey.get(param.getName());
163         return createParamDto(param, activeRuleValue == null ? param.getDefaultValue() : activeRuleValue);
164       })
165       .filter(Objects::nonNull)
166       .peek(paramDto -> dbClient.activeRuleDao().insertParam(session, activeRuleDto, paramDto))
167       .collect(MoreCollectors.toList());
168   }
169
170   @CheckForNull
171   private ActiveRuleParamDto createParamDto(RuleParamDto param, @Nullable String value) {
172     if (value == null) {
173       return null;
174     }
175     ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(param);
176     paramDto.setValue(validateParam(param, value));
177     return paramDto;
178   }
179
180   private String validateParam(RuleParamDto ruleParam, String value) {
181     RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
182     if (ruleParamType.multiple()) {
183       List<String> values = newArrayList(Splitter.on(",").split(value));
184       typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
185     } else {
186       typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
187     }
188     return value;
189   }
190
191   private static class RuleRepository {
192     private final Map<RuleKey, RuleDefinitionDto> definitions;
193     private final Map<RuleKey, Set<RuleParamDto>> params;
194
195     private RuleRepository(DbClient dbClient, DbSession session) {
196       this.definitions = dbClient.ruleDao().selectAllDefinitions(session)
197         .stream()
198         .collect(Collectors.toMap(RuleDefinitionDto::getKey, Function.identity()));
199       Map<String, RuleKey> ruleUuidsByKey = definitions.values()
200         .stream()
201         .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getUuid, RuleDefinitionDto::getKey));
202       this.params = new HashMap<>(ruleUuidsByKey.size());
203       dbClient.ruleDao().selectRuleParamsByRuleKeys(session, definitions.keySet())
204         .forEach(ruleParam -> params.compute(
205           ruleUuidsByKey.get(ruleParam.getRuleUuid()),
206           (key, value) -> {
207             if (value == null) {
208               return ImmutableSet.of(ruleParam);
209             }
210             return ImmutableSet.copyOf(Sets.union(value, Collections.singleton(ruleParam)));
211           }));
212     }
213
214     private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
215       return Optional.ofNullable(definitions.get(requireNonNull(ruleKey, "RuleKey can't be null")));
216     }
217
218     private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
219       Set<RuleParamDto> res = params.get(requireNonNull(ruleKey, "RuleKey can't be null"));
220       return res == null ? Collections.emptySet() : res;
221     }
222   }
223 }