3 * Copyright (C) 2009-2017 SonarSource SA
4 * mailto:info 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.
20 package org.sonar.server.computation.task.projectanalysis.qualitymodel;
22 import com.google.common.collect.ImmutableMap;
24 import org.sonar.api.ce.measure.Issue;
25 import org.sonar.api.measures.CoreMetrics;
26 import org.sonar.core.issue.DefaultIssue;
27 import org.sonar.server.computation.task.projectanalysis.component.Component;
28 import org.sonar.server.computation.task.projectanalysis.component.PathAwareVisitorAdapter;
29 import org.sonar.server.computation.task.projectanalysis.formula.counter.RatingValue;
30 import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepository;
31 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
32 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
33 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
34 import org.sonar.server.computation.task.projectanalysis.period.Period;
35 import org.sonar.server.computation.task.projectanalysis.period.PeriodHolder;
37 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
38 import static org.sonar.api.measures.CoreMetrics.NEW_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;
57 * Compute following measures :
58 * {@link CoreMetrics#NEW_RELIABILITY_RATING_KEY}
59 * {@link CoreMetrics#NEW_SECURITY_RATING_KEY}
61 public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
63 private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
70 private final MeasureRepository measureRepository;
71 private final ComponentIssuesRepository componentIssuesRepository;
72 private final PeriodHolder periodHolder;
74 private final Map<String, Metric> metricsByKey;
76 public NewReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ComponentIssuesRepository componentIssuesRepository,
77 PeriodHolder periodHolder) {
78 super(LEAVES, POST_ORDER, CounterFactory.INSTANCE);
79 this.measureRepository = measureRepository;
80 this.componentIssuesRepository = componentIssuesRepository;
81 this.periodHolder = periodHolder;
84 this.metricsByKey = ImmutableMap.of(
85 NEW_RELIABILITY_RATING_KEY, metricRepository.getByKey(NEW_RELIABILITY_RATING_KEY),
86 NEW_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SECURITY_RATING_KEY));
90 public void visitProject(Component project, Path<Counter> path) {
91 computeAndSaveMeasures(project, path);
95 public void visitDirectory(Component directory, Path<Counter> path) {
96 computeAndSaveMeasures(directory, path);
100 public void visitModule(Component module, Path<Counter> path) {
101 computeAndSaveMeasures(module, path);
105 public void visitFile(Component file, Path<Counter> path) {
106 computeAndSaveMeasures(file, path);
109 private void computeAndSaveMeasures(Component component, Path<Counter> path) {
110 if (!periodHolder.hasPeriod()) {
113 initRatingsToA(path);
114 processIssues(component, path);
115 path.current().newRatingValueByMetric.entrySet()
117 .filter(entry -> entry.getValue().isSet())
119 entry -> measureRepository.add(
121 metricsByKey.get(entry.getKey()),
122 newMeasureBuilder().setVariation(entry.getValue().getValue().getIndex()).createNoValue()));
126 private static void initRatingsToA(Path<Counter> path) {
127 path.current().newRatingValueByMetric.values().forEach(entry -> entry.increment(A));
130 private void processIssues(Component component, Path<Counter> path) {
131 componentIssuesRepository.getIssues(component)
133 .filter(issue -> issue.resolution() == null)
134 .filter(issue -> issue.type().equals(BUG) || issue.type().equals(VULNERABILITY))
135 .forEach(issue -> path.current().processIssue(issue, periodHolder.getPeriod()));
138 private static void addToParent(Path<Counter> path) {
139 if (!path.isRoot()) {
140 path.parent().add(path.current());
144 static final class Counter {
145 private Map<String, RatingValue> newRatingValueByMetric = ImmutableMap.of(
146 NEW_RELIABILITY_RATING_KEY, new RatingValue(),
147 NEW_SECURITY_RATING_KEY, new RatingValue());
150 // prevents instantiation
153 void add(Counter otherCounter) {
154 newRatingValueByMetric.entrySet().forEach(e -> e.getValue().increment(otherCounter.newRatingValueByMetric.get(e.getKey())));
157 void processIssue(Issue issue, Period period) {
158 if (isOnPeriod((DefaultIssue) issue, period)) {
159 Rating rating = RATING_BY_SEVERITY.get(issue.severity());
160 if (issue.type().equals(BUG)) {
161 newRatingValueByMetric.get(NEW_RELIABILITY_RATING_KEY).increment(rating);
162 } else if (issue.type().equals(VULNERABILITY)) {
163 newRatingValueByMetric.get(NEW_SECURITY_RATING_KEY).increment(rating);
168 private static boolean isOnPeriod(DefaultIssue issue, Period period) {
169 // Add one second to not take into account issues created during current analysis
170 return issue.creationDate().getTime() >= period.getSnapshotDate() + 1000L;
174 private static final class CounterFactory extends SimpleStackElementFactory<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
175 public static final CounterFactory INSTANCE = new CounterFactory();
177 private CounterFactory() {
178 // prevents instantiation
182 public Counter createForAny(Component component) {
183 return new Counter();