]> source.dussan.org Git - sonarqube.git/blob
9da8e3244f867742ae7246fcbce2cbe272ece7e6
[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.ws;
21
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.stream.Collectors;
26 import org.sonar.api.resources.Languages;
27 import org.sonar.api.server.ws.Request;
28 import org.sonar.api.server.ws.Response;
29 import org.sonar.api.server.ws.WebService.NewAction;
30 import org.sonar.api.server.ws.WebService.NewController;
31 import org.sonar.db.DbClient;
32 import org.sonar.db.DbSession;
33 import org.sonar.db.qualityprofile.ActiveRuleCountQuery;
34 import org.sonar.db.qualityprofile.ActiveRuleDao;
35 import org.sonar.db.qualityprofile.QProfileDto;
36 import org.sonarqube.ws.Qualityprofiles.InheritanceWsResponse;
37 import org.sonarqube.ws.Qualityprofiles.InheritanceWsResponse.QualityProfile;
38
39 import static java.util.Collections.singleton;
40 import static java.util.Optional.ofNullable;
41 import static org.sonar.db.qualityprofile.ActiveRuleDto.OVERRIDES;
42 import static org.sonar.server.ws.WsUtils.writeProtobuf;
43
44 public class InheritanceAction implements QProfileWsAction {
45
46   private final DbClient dbClient;
47   private final QProfileWsSupport wsSupport;
48   private final Languages languages;
49
50   public InheritanceAction(DbClient dbClient, QProfileWsSupport wsSupport, Languages languages) {
51     this.dbClient = dbClient;
52     this.wsSupport = wsSupport;
53     this.languages = languages;
54   }
55
56   @Override
57   public void define(NewController context) {
58     NewAction inheritance = context.createAction("inheritance")
59       .setSince("5.2")
60       .setDescription("Show a quality profile's ancestors and children.")
61       .setHandler(this)
62       .setResponseExample(getClass().getResource("inheritance-example.json"));
63
64     QProfileReference.defineParams(inheritance, languages);
65   }
66
67   @Override
68   public void handle(Request request, Response response) throws Exception {
69     QProfileReference reference = QProfileReference.fromName(request);
70     try (DbSession dbSession = dbClient.openSession(false)) {
71       QProfileDto profile = wsSupport.getProfile(dbSession, reference);
72       List<QProfileDto> ancestors = ancestors(profile, dbSession);
73       List<QProfileDto> children = dbClient.qualityProfileDao().selectChildren(dbSession, singleton(profile));
74       List<QProfileDto> allProfiles = new ArrayList<>();
75       allProfiles.add(profile);
76       allProfiles.addAll(ancestors);
77       allProfiles.addAll(children);
78       Statistics statistics = new Statistics(dbSession, allProfiles);
79
80       writeProtobuf(buildResponse(profile, ancestors, children, statistics), request, response);
81     }
82   }
83
84   private List<QProfileDto> ancestors(QProfileDto profile, DbSession dbSession) {
85     List<QProfileDto> ancestors = new ArrayList<>();
86     collectAncestors(profile, ancestors, dbSession);
87     return ancestors;
88   }
89
90   private void collectAncestors(QProfileDto profile, List<QProfileDto> ancestors, DbSession session) {
91     if (profile.getParentKee() == null) {
92       return;
93     }
94
95     QProfileDto parent = getParent(session, profile);
96     ancestors.add(parent);
97     collectAncestors(parent, ancestors, session);
98   }
99
100   private QProfileDto getParent(DbSession dbSession, QProfileDto profile) {
101     QProfileDto parent = dbClient.qualityProfileDao().selectByUuid(dbSession, profile.getParentKee());
102     if (parent == null) {
103       throw new IllegalStateException("Cannot find parent of profile: " + profile.getKee());
104     }
105     return parent;
106   }
107
108   private static InheritanceWsResponse buildResponse(QProfileDto profile, List<QProfileDto> ancestors, List<QProfileDto> children, Statistics statistics) {
109     return InheritanceWsResponse.newBuilder()
110       .setProfile(buildProfile(profile, statistics))
111       .addAllAncestors(buildAncestors(ancestors, statistics))
112       .addAllChildren(buildChildren(children, statistics))
113       .build();
114   }
115
116   private static Iterable<QualityProfile> buildAncestors(List<QProfileDto> ancestors, Statistics statistics) {
117     return ancestors.stream()
118       .map(ancestor -> buildProfile(ancestor, statistics))
119       .collect(Collectors.toList());
120   }
121
122   private static Iterable<QualityProfile> buildChildren(List<QProfileDto> children, Statistics statistics) {
123     return children.stream()
124       .map(child -> buildProfile(child, statistics))
125       .collect(Collectors.toList());
126   }
127
128   private static QualityProfile buildProfile(QProfileDto qualityProfile, Statistics statistics) {
129     String key = qualityProfile.getKee();
130     QualityProfile.Builder builder = QualityProfile.newBuilder()
131       .setKey(key)
132       .setName(qualityProfile.getName())
133       .setActiveRuleCount(statistics.countRulesByProfileKey.getOrDefault(key, 0L))
134       .setOverridingRuleCount(statistics.countOverridingRulesByProfileKey.getOrDefault(key, 0L))
135       .setIsBuiltIn(qualityProfile.isBuiltIn());
136     ofNullable(qualityProfile.getParentKee()).ifPresent(builder::setParent);
137     return builder.build();
138   }
139
140   private class Statistics {
141     private final Map<String, Long> countRulesByProfileKey;
142     private final Map<String, Long> countOverridingRulesByProfileKey;
143
144     private Statistics(DbSession dbSession, List<QProfileDto> profiles) {
145       ActiveRuleDao dao = dbClient.activeRuleDao();
146       ActiveRuleCountQuery.Builder builder = ActiveRuleCountQuery.builder();
147       countRulesByProfileKey = dao.countActiveRulesByQuery(dbSession, builder.setProfiles(profiles).build());
148       countOverridingRulesByProfileKey = dao.countActiveRulesByQuery(dbSession, builder.setProfiles(profiles).setInheritance(OVERRIDES).build());
149     }
150   }
151 }