]> source.dussan.org Git - sonarqube.git/blob
a9ca63e71f9d382e6dc2ae3b46d498ba821eadad
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 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.computation.task.projectanalysis.qualitymodel;
21
22 import com.google.common.collect.ImmutableMap;
23 import java.util.Map;
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;
36
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;
55
56 /**
57  * Compute following measures :
58  * {@link CoreMetrics#NEW_RELIABILITY_RATING_KEY}
59  * {@link CoreMetrics#NEW_SECURITY_RATING_KEY}
60  */
61 public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
62
63   private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
64     BLOCKER, E,
65     CRITICAL, D,
66     MAJOR, C,
67     MINOR, B,
68     INFO, A);
69
70   private final MeasureRepository measureRepository;
71   private final ComponentIssuesRepository componentIssuesRepository;
72   private final PeriodHolder periodHolder;
73
74   private final Map<String, Metric> metricsByKey;
75
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;
82
83     // Output metrics
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));
87   }
88
89   @Override
90   public void visitProject(Component project, Path<Counter> path) {
91     computeAndSaveMeasures(project, path);
92   }
93
94   @Override
95   public void visitDirectory(Component directory, Path<Counter> path) {
96     computeAndSaveMeasures(directory, path);
97   }
98
99   @Override
100   public void visitModule(Component module, Path<Counter> path) {
101     computeAndSaveMeasures(module, path);
102   }
103
104   @Override
105   public void visitFile(Component file, Path<Counter> path) {
106     computeAndSaveMeasures(file, path);
107   }
108
109   private void computeAndSaveMeasures(Component component, Path<Counter> path) {
110     if (!periodHolder.hasPeriod()) {
111       return;
112     }
113     initRatingsToA(path);
114     processIssues(component, path);
115     path.current().newRatingValueByMetric.entrySet()
116       .stream()
117       .filter(entry -> entry.getValue().isSet())
118       .forEach(
119         entry -> measureRepository.add(
120           component,
121           metricsByKey.get(entry.getKey()),
122           newMeasureBuilder().setVariation(entry.getValue().getValue().getIndex()).createNoValue()));
123     addToParent(path);
124   }
125
126   private static void initRatingsToA(Path<Counter> path) {
127     path.current().newRatingValueByMetric.values().forEach(entry -> entry.increment(A));
128   }
129
130   private void processIssues(Component component, Path<Counter> path) {
131     componentIssuesRepository.getIssues(component)
132       .stream()
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()));
136   }
137
138   private static void addToParent(Path<Counter> path) {
139     if (!path.isRoot()) {
140       path.parent().add(path.current());
141     }
142   }
143
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());
148
149     private Counter() {
150       // prevents instantiation
151     }
152
153     void add(Counter otherCounter) {
154       newRatingValueByMetric.entrySet().forEach(e -> e.getValue().increment(otherCounter.newRatingValueByMetric.get(e.getKey())));
155     }
156
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);
164         }
165       }
166     }
167
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;
171     }
172   }
173
174   private static final class CounterFactory extends SimpleStackElementFactory<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
175     public static final CounterFactory INSTANCE = new CounterFactory();
176
177     private CounterFactory() {
178       // prevents instantiation
179     }
180
181     @Override
182     public Counter createForAny(Component component) {
183       return new Counter();
184     }
185   }
186 }