]> source.dussan.org Git - sonarqube.git/blob
568dc5eb9f3a42cd4a0e02ab7bf3d825083b04ca
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 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.pushapi.qualityprofile;
21
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Set;
30 import java.util.stream.Collectors;
31 import javax.annotation.Nullable;
32 import org.apache.commons.lang.StringUtils;
33 import org.jetbrains.annotations.NotNull;
34 import org.sonar.api.rule.RuleKey;
35 import org.sonar.api.server.ServerSide;
36 import org.sonar.core.util.ParamChange;
37 import org.sonar.core.util.RuleChange;
38 import org.sonar.core.util.RuleSetChangedEvent;
39 import org.sonar.db.DbClient;
40 import org.sonar.db.DbSession;
41 import org.sonar.db.project.ProjectDto;
42 import org.sonar.db.qualityprofile.ActiveRuleDto;
43 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
44 import org.sonar.db.qualityprofile.OrgActiveRuleDto;
45 import org.sonar.db.qualityprofile.ProjectQprofileAssociationDto;
46 import org.sonar.db.qualityprofile.QProfileDto;
47 import org.sonar.db.rule.RuleDto;
48 import org.sonar.server.qualityprofile.ActiveRuleChange;
49
50 import static java.util.function.Predicate.not;
51 import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED;
52 import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED;
53 import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED;
54
55 @ServerSide
56 public class QualityProfileChangeEventServiceImpl implements QualityProfileChangeEventService {
57
58   private final DbClient dbClient;
59   private final RuleActivatorEventsDistributor eventsDistributor;
60
61   public QualityProfileChangeEventServiceImpl(DbClient dbClient, RuleActivatorEventsDistributor eventsDistributor) {
62     this.dbClient = dbClient;
63     this.eventsDistributor = eventsDistributor;
64   }
65
66   @Override
67   public void publishRuleActivationToSonarLintClients(ProjectDto project, @Nullable QProfileDto activatedProfile, @Nullable QProfileDto deactivatedProfile) {
68     List<RuleChange> activatedRules = new ArrayList<>();
69     Set<String> deactivatedRules = new HashSet<>();
70
71     if (activatedProfile != null) {
72       activatedRules.addAll(createRuleChanges(activatedProfile));
73     }
74
75     if (deactivatedProfile != null) {
76       deactivatedRules.addAll(getRuleKeys(deactivatedProfile));
77     }
78
79     if (activatedRules.isEmpty() && deactivatedRules.isEmpty()) {
80       return;
81     }
82
83     String language = activatedProfile != null ? activatedProfile.getLanguage() : deactivatedProfile.getLanguage();
84     RuleSetChangedEvent event = new RuleSetChangedEvent(new String[] {project.getKey()}, activatedRules.toArray(new RuleChange[0]), deactivatedRules.toArray(new String[0]),
85       language);
86     eventsDistributor.pushEvent(event);
87   }
88
89   private List<RuleChange> createRuleChanges(@NotNull QProfileDto profileDto) {
90     List<RuleChange> ruleChanges = new ArrayList<>();
91
92     try (DbSession dbSession = dbClient.openSession(false)) {
93       List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByProfile(dbSession, profileDto);
94       List<String> activeRuleUuids = activeRuleDtos.stream().map(ActiveRuleDto::getUuid).collect(Collectors.toList());
95
96       Map<String, List<ActiveRuleParamDto>> paramsByActiveRuleUuid = dbClient.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, activeRuleUuids)
97         .stream().collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid));
98
99       Map<String, String> activeRuleUuidByRuleUuid = activeRuleDtos.stream().collect(Collectors.toMap(ActiveRuleDto::getRuleUuid, ActiveRuleDto::getUuid));
100
101       List<String> ruleUuids = activeRuleDtos.stream().map(ActiveRuleDto::getRuleUuid).collect(Collectors.toList());
102       List<RuleDto> ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, ruleUuids);
103
104       for (RuleDto ruleDto : ruleDtos) {
105         String activeRuleUuid = activeRuleUuidByRuleUuid.get(ruleDto.getUuid());
106         List<ActiveRuleParamDto> params = paramsByActiveRuleUuid.getOrDefault(activeRuleUuid, new ArrayList<>());
107         RuleChange ruleChange = toRuleChange(ruleDto, params);
108         ruleChanges.add(ruleChange);
109       }
110     }
111     return ruleChanges;
112   }
113
114   private Set<String> getRuleKeys(@NotNull QProfileDto profileDto) {
115     Set<String> ruleKeys = new HashSet<>();
116
117     try (DbSession dbSession = dbClient.openSession(false)) {
118       List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByProfile(dbSession, profileDto);
119
120       List<String> ruleUuids = activeRuleDtos.stream().map(ActiveRuleDto::getRuleUuid).collect(Collectors.toList());
121       List<RuleDto> ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, ruleUuids);
122
123       for (RuleDto ruleDto : ruleDtos) {
124         ruleKeys.add(ruleDto.getKey().toString());
125       }
126     }
127     return ruleKeys;
128   }
129
130   @NotNull
131   private RuleChange toRuleChange(RuleDto ruleDto, List<ActiveRuleParamDto> activeRuleParamDtos) {
132     RuleChange ruleChange = new RuleChange();
133     ruleChange.setKey(ruleDto.getKey().toString());
134     ruleChange.setLanguage(ruleDto.getLanguage());
135     ruleChange.setSeverity(ruleDto.getSeverityString());
136
137     List<ParamChange> paramChanges = new ArrayList<>();
138     for (ActiveRuleParamDto activeRuleParam : activeRuleParamDtos) {
139       paramChanges.add(new ParamChange(activeRuleParam.getKey(), activeRuleParam.getValue()));
140     }
141     ruleChange.setParams(paramChanges.toArray(new ParamChange[0]));
142
143     String templateUuid = ruleDto.getTemplateUuid();
144     if (templateUuid != null && !"".equals(templateUuid)) {
145       try (DbSession dbSession = dbClient.openSession(false)) {
146         RuleDto templateRule = dbClient.ruleDao().selectByUuid(templateUuid, dbSession)
147           .orElseThrow(() -> new IllegalStateException(String.format("Unknown Template Rule '%s'", templateUuid)));
148         ruleChange.setTemplateKey(templateRule.getKey().toString());
149       }
150     }
151
152     return ruleChange;
153   }
154
155   public void distributeRuleChangeEvent(Collection<QProfileDto> profiles, List<ActiveRuleChange> activeRuleChanges, String language) {
156     if (activeRuleChanges.isEmpty()) {
157       return;
158     }
159
160     Set<RuleChange> activatedRules = new HashSet<>();
161
162     for (ActiveRuleChange arc : activeRuleChanges) {
163       ActiveRuleDto activeRule = arc.getActiveRule();
164       if (activeRule == null) {
165         continue;
166       }
167
168       RuleChange ruleChange = new RuleChange();
169       ruleChange.setKey(activeRule.getRuleKey().toString());
170       ruleChange.setSeverity(arc.getSeverity());
171       ruleChange.setLanguage(language);
172
173       Optional<String> templateKey = templateKey(arc);
174       templateKey.ifPresent(ruleChange::setTemplateKey);
175
176       // params
177       List<ParamChange> paramChanges = new ArrayList<>();
178       for (Map.Entry<String, String> entry : arc.getParameters().entrySet()) {
179         paramChanges.add(new ParamChange(entry.getKey(), entry.getValue()));
180       }
181       ruleChange.setParams(paramChanges.toArray(new ParamChange[0]));
182
183       if (ACTIVATED.equals(arc.getType()) || UPDATED.equals(arc.getType())) {
184         activatedRules.add(ruleChange);
185       }
186     }
187
188     Set<String> deactivatedRules = activeRuleChanges.stream()
189       .filter(r -> DEACTIVATED.equals(r.getType()))
190       .map(ActiveRuleChange::getActiveRule)
191       .filter(not(Objects::isNull))
192       .map(ActiveRuleDto::getRuleKey)
193       .map(RuleKey::toString)
194       .collect(Collectors.toSet());
195
196     Set<String> projectKeys = getProjectKeys(profiles);
197
198     if (activatedRules.isEmpty() && deactivatedRules.isEmpty()) {
199       return;
200     }
201
202     RuleSetChangedEvent event = new RuleSetChangedEvent(projectKeys.toArray(new String[0]), activatedRules.toArray(new RuleChange[0]), deactivatedRules.toArray(new String[0]),
203       language);
204     eventsDistributor.pushEvent(event);
205   }
206
207   private Optional<String> templateKey(ActiveRuleChange arc) {
208     try (DbSession dbSession = dbClient.openSession(false)) {
209       String ruleUuid = arc.getRuleUuid();
210       RuleDto rule = dbClient.ruleDao().selectByUuid(ruleUuid, dbSession).orElseThrow(() -> new IllegalStateException("unknow rule"));
211       String templateUuid = rule.getTemplateUuid();
212
213       if (StringUtils.isNotEmpty(templateUuid)) {
214         RuleDto templateRule = dbClient.ruleDao().selectByUuid(templateUuid, dbSession)
215           .orElseThrow(() -> new IllegalStateException(String.format("Unknown Template Rule '%s'", templateUuid)));
216         return Optional.of(templateRule.getKey().toString());
217       }
218     }
219     return Optional.empty();
220   }
221
222   private Set<String> getProjectKeys(Collection<QProfileDto> profiles) {
223     Set<String> projectKeys = new HashSet<>();
224     try (DbSession dbSession = dbClient.openSession(false)) {
225       for (QProfileDto profileDto : profiles) {
226         List<ProjectQprofileAssociationDto> associationDtos = dbClient.qualityProfileDao().selectSelectedProjects(dbSession, profileDto, null);
227         for (ProjectQprofileAssociationDto associationDto : associationDtos) {
228           projectKeys.add(associationDto.getProjectKey());
229         }
230       }
231       return projectKeys;
232     }
233   }
234
235 }