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.collect.ImmutableMap;
25 import org.sonar.api.ce.measure.Issue;
26 import org.sonar.api.measures.CoreMetrics;
27 import org.sonar.core.issue.DefaultIssue;
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.RatingValue;
31 import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepository;
32 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
33 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
34 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
35 import org.sonar.server.computation.task.projectanalysis.period.Period;
36 import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolder;
38 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
39 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
40 import static org.sonar.api.rule.Severity.BLOCKER;
41 import static org.sonar.api.rule.Severity.CRITICAL;
42 import static org.sonar.api.rule.Severity.INFO;
43 import static org.sonar.api.rule.Severity.MAJOR;
44 import static org.sonar.api.rule.Severity.MINOR;
45 import static org.sonar.api.rules.RuleType.BUG;
46 import static org.sonar.api.rules.RuleType.VULNERABILITY;
47 import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
48 import static org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit.LEAVES;
49 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
50 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating;
51 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.A;
52 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.B;
53 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.C;
54 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.D;
55 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.E;
58 * Compute following measures :
59 * {@link CoreMetrics#NEW_RELIABILITY_RATING_KEY}
60 * {@link CoreMetrics#NEW_SECURITY_RATING_KEY}
62 public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
64 private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
71 private final MeasureRepository measureRepository;
72 private final ComponentIssuesRepository componentIssuesRepository;
73 private final PeriodsHolder periodsHolder;
75 private final Map<String, Metric> metricsByKey;
77 public NewReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ComponentIssuesRepository componentIssuesRepository,
78 PeriodsHolder periodsHolder) {
79 super(LEAVES, POST_ORDER, CounterFactory.INSTANCE);
80 this.measureRepository = measureRepository;
81 this.componentIssuesRepository = componentIssuesRepository;
82 this.periodsHolder = periodsHolder;
85 this.metricsByKey = ImmutableMap.of(
86 NEW_RELIABILITY_RATING_KEY, metricRepository.getByKey(NEW_RELIABILITY_RATING_KEY),
87 NEW_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SECURITY_RATING_KEY));
91 public void visitProject(Component project, Path<Counter> path) {
92 computeAndSaveMeasures(project, path);
96 public void visitDirectory(Component directory, Path<Counter> path) {
97 computeAndSaveMeasures(directory, path);
101 public void visitModule(Component module, Path<Counter> path) {
102 computeAndSaveMeasures(module, path);
106 public void visitFile(Component file, Path<Counter> path) {
107 computeAndSaveMeasures(file, path);
110 private void computeAndSaveMeasures(Component component, Path<Counter> path) {
111 if (!periodsHolder.hasPeriod()) {
114 initRatingsToA(path);
115 processIssues(component, path);
116 path.current().newRatingValueByMetric.entrySet()
118 .filter(entry -> entry.getValue().isSet())
120 entry -> measureRepository.add(
122 metricsByKey.get(entry.getKey()),
123 newMeasureBuilder().setVariation(entry.getValue().getValue().getIndex()).createNoValue()));
127 private static void initRatingsToA(Path<Counter> path) {
128 path.current().newRatingValueByMetric.values().forEach(entry -> entry.increment(A));
131 private void processIssues(Component component, Path<Counter> path) {
132 componentIssuesRepository.getIssues(component)
134 .filter(issue -> issue.resolution() == null)
135 .filter(issue -> issue.type().equals(BUG) || issue.type().equals(VULNERABILITY))
136 .forEach(issue -> path.current().processIssue(issue, periodsHolder.getPeriod()));
139 private static void addToParent(Path<Counter> path) {
140 if (!path.isRoot()) {
141 path.parent().add(path.current());
145 static final class Counter {
146 private Map<String, RatingValue> newRatingValueByMetric = ImmutableMap.of(
147 NEW_RELIABILITY_RATING_KEY, new RatingValue(),
148 NEW_SECURITY_RATING_KEY, new RatingValue());
151 // prevents instantiation
154 void add(Counter otherCounter) {
155 newRatingValueByMetric.entrySet().forEach(e -> e.getValue().increment(otherCounter.newRatingValueByMetric.get(e.getKey())));
158 void processIssue(Issue issue, Period period) {
159 if (isOnPeriod((DefaultIssue) issue, period)) {
160 Rating rating = RATING_BY_SEVERITY.get(issue.severity());
161 if (issue.type().equals(BUG)) {
162 newRatingValueByMetric.get(NEW_RELIABILITY_RATING_KEY).increment(rating);
163 } else if (issue.type().equals(VULNERABILITY)) {
164 newRatingValueByMetric.get(NEW_SECURITY_RATING_KEY).increment(rating);
169 private static boolean isOnPeriod(DefaultIssue issue, Period period) {
170 // Add one second to not take into account issues created during current analysis
171 return issue.creationDate().getTime() >= period.getSnapshotDate() + 1000L;
175 private static final class CounterFactory extends SimpleStackElementFactory<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
176 public static final CounterFactory INSTANCE = new CounterFactory();
178 private CounterFactory() {
179 // prevents instantiation
183 public Counter createForAny(Component component) {
184 return new Counter();