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