3 * Copyright (C) 2009-2016 SonarSource SA
4 * mailto:contact AT sonarsource DOT com
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.
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.
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.
21 package org.sonar.server.computation.task.projectanalysis.qualitymodel;
23 import com.google.common.base.Optional;
24 import com.google.common.collect.ImmutableMap;
26 import org.sonar.api.ce.measure.Issue;
27 import org.sonar.api.measures.CoreMetrics;
28 import org.sonar.server.computation.task.projectanalysis.component.Component;
29 import org.sonar.server.computation.task.projectanalysis.component.PathAwareVisitorAdapter;
30 import org.sonar.server.computation.task.projectanalysis.formula.counter.RatingVariationValue;
31 import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepository;
32 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
33 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
34 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
35 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
37 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
38 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
39 import static org.sonar.api.rule.Severity.BLOCKER;
40 import static org.sonar.api.rule.Severity.CRITICAL;
41 import static org.sonar.api.rule.Severity.INFO;
42 import static org.sonar.api.rule.Severity.MAJOR;
43 import static org.sonar.api.rule.Severity.MINOR;
44 import static org.sonar.api.rules.RuleType.BUG;
45 import static org.sonar.api.rules.RuleType.VULNERABILITY;
46 import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
47 import static org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit.LEAVES;
48 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
49 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating;
50 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.A;
51 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.B;
52 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.C;
53 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.D;
54 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.E;
55 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.valueOf;
58 * Compute following measures :
59 * {@link CoreMetrics#RELIABILITY_RATING_KEY}
60 * {@link CoreMetrics#SECURITY_RATING_KEY}
62 public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<ReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
64 private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
71 private final MeasureRepository measureRepository;
72 private final ComponentIssuesRepository componentIssuesRepository;
75 private final Metric reliabilityRatingMetric;
76 private final Metric securityRatingMetric;
78 private final Map<String, Metric> metricsByKey;
80 public ReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ComponentIssuesRepository componentIssuesRepository) {
81 super(LEAVES, POST_ORDER, CounterFactory.INSTANCE);
82 this.measureRepository = measureRepository;
83 this.componentIssuesRepository = componentIssuesRepository;
86 this.reliabilityRatingMetric = metricRepository.getByKey(RELIABILITY_RATING_KEY);
87 this.securityRatingMetric = metricRepository.getByKey(SECURITY_RATING_KEY);
89 this.metricsByKey = ImmutableMap.of(
90 RELIABILITY_RATING_KEY, reliabilityRatingMetric,
91 SECURITY_RATING_KEY, securityRatingMetric);
95 public void visitProject(Component project, Path<Counter> path) {
96 computeAndSaveMeasures(project, path);
100 public void visitDirectory(Component directory, Path<Counter> path) {
101 computeAndSaveMeasures(directory, path);
105 public void visitModule(Component module, Path<Counter> path) {
106 computeAndSaveMeasures(module, path);
110 public void visitFile(Component file, Path<Counter> path) {
111 computeAndSaveMeasures(file, path);
115 public void visitView(Component view, Path<Counter> path) {
116 computeAndSaveMeasures(view, path);
120 public void visitSubView(Component subView, Path<Counter> path) {
121 computeAndSaveMeasures(subView, path);
125 public void visitProjectView(Component projectView, Path<Counter> path) {
126 path.parent().ratingValueByMetric.entrySet().forEach(entry -> {
127 Optional<Measure> ratingMeasure = measureRepository.getRawMeasure(projectView, metricsByKey.get(entry.getKey()));
128 if (ratingMeasure.isPresent()) {
129 entry.getValue().increment(valueOf(ratingMeasure.get().getData()));
134 private void computeAndSaveMeasures(Component component, Path<Counter> path) {
135 processIssues(component, path);
136 path.current().ratingValueByMetric.entrySet().forEach(
137 entry -> measureRepository.add(component, metricsByKey.get(entry.getKey()), createRatingMeasure(entry.getValue().getValue())));
141 private void processIssues(Component component, Path<Counter> path) {
142 componentIssuesRepository.getIssues(component)
144 .filter(issue -> issue.resolution() == null)
145 .filter(issue -> issue.type().equals(BUG) || issue.type().equals(VULNERABILITY))
146 .forEach(path.current()::processIssue);
149 private static void addToParent(Path<Counter> path) {
150 if (!path.isRoot()) {
151 path.parent().add(path.current());
155 private static Measure createRatingMeasure(Rating rating) {
156 return newMeasureBuilder().create(rating.getIndex(), rating.name());
159 static final class Counter {
160 private Map<String, RatingVariationValue> ratingValueByMetric = ImmutableMap.of(
161 RELIABILITY_RATING_KEY, new RatingVariationValue(),
162 SECURITY_RATING_KEY, new RatingVariationValue());
165 // prevents instantiation
168 void add(Counter otherCounter) {
169 ratingValueByMetric.entrySet().forEach(e -> e.getValue().increment(otherCounter.ratingValueByMetric.get(e.getKey())));
172 void processIssue(Issue issue) {
173 Rating rating = RATING_BY_SEVERITY.get(issue.severity());
174 if (issue.type().equals(BUG)) {
175 ratingValueByMetric.get(RELIABILITY_RATING_KEY).increment(rating);
176 } else if (issue.type().equals(VULNERABILITY)) {
177 ratingValueByMetric.get(SECURITY_RATING_KEY).increment(rating);
182 private static final class CounterFactory extends PathAwareVisitorAdapter.SimpleStackElementFactory<ReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
183 public static final CounterFactory INSTANCE = new CounterFactory();
185 private CounterFactory() {
186 // prevents instantiation
190 public Counter createForAny(Component component) {
191 return new Counter();
195 * Counter is not used at ProjectView level, saves on instantiating useless objects
198 public Counter createForProjectView(Component projectView) {