2 * Sonar, open source software quality management tool.
3 * Copyright (C) 2008-2012 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * Sonar 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 * Sonar 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
17 * License along with Sonar; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
20 package org.sonar.plugins.core.timemachine;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Date;
25 import java.util.List;
28 import org.apache.commons.lang.StringUtils;
29 import org.sonar.api.batch.Decorator;
30 import org.sonar.api.batch.DecoratorBarriers;
31 import org.sonar.api.batch.DecoratorContext;
32 import org.sonar.api.batch.DependedUpon;
33 import org.sonar.api.batch.DependsUpon;
34 import org.sonar.api.measures.CoreMetrics;
35 import org.sonar.api.measures.Measure;
36 import org.sonar.api.measures.MeasureUtils;
37 import org.sonar.api.measures.MeasuresFilters;
38 import org.sonar.api.measures.Metric;
39 import org.sonar.api.measures.RuleMeasure;
40 import org.sonar.api.resources.Project;
41 import org.sonar.api.resources.Resource;
42 import org.sonar.api.resources.ResourceUtils;
43 import org.sonar.api.resources.Scopes;
44 import org.sonar.api.rules.Rule;
45 import org.sonar.api.rules.RulePriority;
46 import org.sonar.api.rules.Violation;
47 import org.sonar.batch.components.PastSnapshot;
48 import org.sonar.batch.components.TimeMachineConfiguration;
50 import com.google.common.collect.ArrayListMultimap;
51 import com.google.common.collect.ListMultimap;
52 import com.google.common.collect.Sets;
54 @DependsUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING)
55 public class NewViolationsDecorator implements Decorator {
57 private TimeMachineConfiguration timeMachineConfiguration;
59 public NewViolationsDecorator(TimeMachineConfiguration timeMachineConfiguration) {
60 this.timeMachineConfiguration = timeMachineConfiguration;
63 public boolean shouldExecuteOnProject(Project project) {
64 return project.isLatestAnalysis();
68 public List<Metric> generatesMetric() {
70 CoreMetrics.NEW_VIOLATIONS,
71 CoreMetrics.NEW_BLOCKER_VIOLATIONS,
72 CoreMetrics.NEW_CRITICAL_VIOLATIONS,
73 CoreMetrics.NEW_MAJOR_VIOLATIONS,
74 CoreMetrics.NEW_MINOR_VIOLATIONS,
75 CoreMetrics.NEW_INFO_VIOLATIONS);
78 public void decorate(Resource resource, DecoratorContext context) {
79 if (shouldDecorateResource(resource, context)) {
80 computeNewViolations(context);
81 computeNewViolationsPerSeverity(context);
82 computeNewViolationsPerRule(context);
86 private boolean shouldDecorateResource(Resource resource, DecoratorContext context) {
87 return (StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope()) || StringUtils
88 .equals(Scopes.FILE, resource.getScope()))
89 && !ResourceUtils.isUnitTestClass(resource)
90 && context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null;
93 private void computeNewViolations(DecoratorContext context) {
94 Measure measure = new Measure(CoreMetrics.NEW_VIOLATIONS);
95 for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) {
96 int variationIndex = pastSnapshot.getIndex();
97 Collection<Measure> children = context.getChildrenMeasures(CoreMetrics.NEW_VIOLATIONS);
98 int count = countViolations(context.getViolations(), pastSnapshot.getTargetDate());
99 double sum = MeasureUtils.sumOnVariation(true, variationIndex, children) + count;
100 measure.setVariation(variationIndex, sum);
102 context.saveMeasure(measure);
105 private void computeNewViolationsPerSeverity(DecoratorContext context) {
106 ListMultimap<RulePriority, Violation> violationsPerSeverities = ArrayListMultimap.create();
107 for (Violation violation : context.getViolations()) {
108 violationsPerSeverities.put(violation.getSeverity(), violation);
111 for (RulePriority severity : RulePriority.values()) {
112 Metric metric = severityToMetric(severity);
113 Measure measure = new Measure(metric);
114 for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) {
115 int variationIndex = pastSnapshot.getIndex();
116 int count = countViolations(violationsPerSeverities.get(severity), pastSnapshot.getTargetDate());
117 Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.metric(metric));
118 double sum = MeasureUtils.sumOnVariation(true, variationIndex, children) + count;
119 measure.setVariation(variationIndex, sum);
121 context.saveMeasure(measure);
125 private void computeNewViolationsPerRule(DecoratorContext context) {
126 for (RulePriority severity : RulePriority.values()) {
127 Metric metric = severityToMetric(severity);
128 ListMultimap<Rule, Measure> childMeasuresPerRule = ArrayListMultimap.create();
129 ListMultimap<Rule, Violation> violationsPerRule = ArrayListMultimap.create();
130 Set<Rule> rules = Sets.newHashSet();
132 Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.rules(metric));
133 for (Measure child : children) {
134 RuleMeasure childRuleMeasure = (RuleMeasure) child;
135 Rule rule = childRuleMeasure.getRule();
137 childMeasuresPerRule.put(rule, childRuleMeasure);
142 for (Violation violation : context.getViolations()) {
143 if (violation.getSeverity().equals(severity)) {
144 rules.add(violation.getRule());
145 violationsPerRule.put(violation.getRule(), violation);
149 for (Rule rule : rules) {
150 RuleMeasure measure = RuleMeasure.createForRule(metric, rule, null);
151 measure.setRulePriority(severity);
152 for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) {
153 int variationIndex = pastSnapshot.getIndex();
154 int count = countViolations(violationsPerRule.get(rule), pastSnapshot.getTargetDate());
155 double sum = MeasureUtils.sumOnVariation(true, variationIndex, childMeasuresPerRule.get(rule)) + count;
156 measure.setVariation(variationIndex, sum);
158 context.saveMeasure(measure);
163 int countViolations(Collection<Violation> violations, Date targetDate) {
164 if (violations == null) {
168 for (Violation violation : violations) {
169 if (isAfter(violation, targetDate)) {
176 private boolean isAfter(Violation violation, Date date) {
180 return violation.getCreatedAt() != null && violation.getCreatedAt().after(date);
183 private Metric severityToMetric(RulePriority severity) {
185 if (severity.equals(RulePriority.BLOCKER)) {
186 metric = CoreMetrics.NEW_BLOCKER_VIOLATIONS;
187 } else if (severity.equals(RulePriority.CRITICAL)) {
188 metric = CoreMetrics.NEW_CRITICAL_VIOLATIONS;
189 } else if (severity.equals(RulePriority.MAJOR)) {
190 metric = CoreMetrics.NEW_MAJOR_VIOLATIONS;
191 } else if (severity.equals(RulePriority.MINOR)) {
192 metric = CoreMetrics.NEW_MINOR_VIOLATIONS;
193 } else if (severity.equals(RulePriority.INFO)) {
194 metric = CoreMetrics.NEW_INFO_VIOLATIONS;
196 throw new IllegalArgumentException("Unsupported severity: " + severity);
202 public String toString() {
203 return getClass().getSimpleName();