2 * Sonar, open source software quality management tool.
3 * Copyright (C) 2008-2011 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 com.google.common.collect.*;
23 import org.apache.commons.lang.StringUtils;
24 import org.sonar.api.batch.Decorator;
25 import org.sonar.api.batch.DecoratorContext;
26 import org.sonar.api.batch.DependedUpon;
27 import org.sonar.api.batch.DependsUpon;
28 import org.sonar.api.measures.*;
29 import org.sonar.api.resources.Project;
30 import org.sonar.api.resources.Resource;
31 import org.sonar.api.resources.ResourceUtils;
32 import org.sonar.api.resources.Scopes;
33 import org.sonar.api.rules.Rule;
34 import org.sonar.api.rules.RulePriority;
35 import org.sonar.api.rules.Violation;
36 import org.sonar.batch.components.PastSnapshot;
37 import org.sonar.batch.components.TimeMachineConfiguration;
41 /* temporary workaround - the attributes classes() should be used but it is buggy */
42 @DependsUpon("ViolationPersisterDecorator")
43 public class NewViolationsDecorator implements Decorator {
45 private TimeMachineConfiguration timeMachineConfiguration;
47 // temporary data for current resource
48 private Map<Rule, RulePriority> ruleToLevel = Maps.newHashMap();
49 private Multimap<RulePriority, Violation> violationsBySeverity = ArrayListMultimap.create();
50 private Multimap<Rule, Violation> violationsByRule = ArrayListMultimap.create();
52 public NewViolationsDecorator(TimeMachineConfiguration timeMachineConfiguration) {
53 this.timeMachineConfiguration = timeMachineConfiguration;
56 public boolean shouldExecuteOnProject(Project project) {
57 return project.isLatestAnalysis();
61 public List<Metric> generatesMetric() {
63 CoreMetrics.NEW_VIOLATIONS, CoreMetrics.NEW_BLOCKER_VIOLATIONS, CoreMetrics.NEW_CRITICAL_VIOLATIONS,
64 CoreMetrics.NEW_MAJOR_VIOLATIONS, CoreMetrics.NEW_MINOR_VIOLATIONS, CoreMetrics.NEW_INFO_VIOLATIONS);
67 public void decorate(Resource resource, DecoratorContext context) {
68 if (shouldDecorateResource(resource, context)) {
69 prepareCurrentResourceViolations(context);
70 saveNewViolations(context);
71 saveNewViolationsBySeverity(context);
72 saveNewViolationsByRule(context);
77 private boolean shouldDecorateResource(Resource resource, DecoratorContext context) {
79 (StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope()) || StringUtils.equals(Scopes.FILE, resource.getScope()))
80 && !ResourceUtils.isUnitTestClass(resource) && context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null;
84 private void clearCache() {
86 violationsBySeverity.clear();
87 violationsByRule.clear();
90 private void prepareCurrentResourceViolations(DecoratorContext context) {
91 for (Violation violation : context.getViolations()) {
92 violationsBySeverity.put(violation.getSeverity(), violation);
93 violationsByRule.put(violation.getRule(), violation);
94 ruleToLevel.put(violation.getRule(), violation.getSeverity());
98 private void saveNewViolations(DecoratorContext context) {
99 Measure measure = new Measure(CoreMetrics.NEW_VIOLATIONS);
100 for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) {
101 int variationIndex = pastSnapshot.getIndex();
102 Collection<Measure> children = context.getChildrenMeasures(CoreMetrics.NEW_VIOLATIONS);
103 int count = countViolations(context.getViolations(), pastSnapshot.getTargetDate());
104 double sum = sumChildren(variationIndex, children) + count;
105 measure.setVariation(variationIndex, sum);
107 context.saveMeasure(measure);
110 private void saveNewViolationsBySeverity(DecoratorContext context) {
111 for (RulePriority priority : RulePriority.values()) {
112 Metric metric = getMetricForSeverity(priority);
113 Measure measure = new Measure(metric);
114 for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) {
115 int variationIndex = pastSnapshot.getIndex();
116 int count = countViolations(violationsBySeverity.get(priority), pastSnapshot.getTargetDate());
117 Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.metric(metric));
118 double sum = sumChildren(variationIndex, children) + count;
119 measure.setVariation(variationIndex, sum);
121 context.saveMeasure(measure);
125 private void saveNewViolationsByRule(DecoratorContext context) {
126 ListMultimap<Rule, Measure> childrenByRule = ArrayListMultimap.create();
127 Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.rules(CoreMetrics.NEW_VIOLATIONS));
128 for (Measure childMeasure : children) {
129 RuleMeasure childRuleMeasure = (RuleMeasure) childMeasure;
130 Rule rule = childRuleMeasure.getRule();
132 childrenByRule.put(rule, childMeasure);
133 ruleToLevel.put(childRuleMeasure.getRule(), childRuleMeasure.getRulePriority());
137 Set<Rule> rules = Sets.newHashSet(violationsByRule.keys());
138 rules.addAll(childrenByRule.keys());
140 for (Rule rule : rules) {
141 RuleMeasure measure = RuleMeasure.createForRule(CoreMetrics.NEW_VIOLATIONS, rule, null);
142 measure.setRulePriority(ruleToLevel.get(rule));
143 for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) {
144 int variationIndex = pastSnapshot.getIndex();
145 int count = countViolations(violationsByRule.get(rule), pastSnapshot.getTargetDate());
146 double sum = sumChildren(variationIndex, childrenByRule.get(rule)) + count;
147 measure.setVariation(variationIndex, sum);
149 context.saveMeasure(measure);
153 int sumChildren(int variationIndex, Collection<Measure> measures) {
155 for (Measure measure : measures) {
156 Double var = measure.getVariation(variationIndex);
158 sum += var.intValue();
164 int countViolations(Collection<Violation> violations, Date targetDate) {
165 if (violations == null) {
169 for (Violation violation : violations) {
170 if (isAfter(violation, targetDate)) {
177 private boolean isAfter(Violation violation, Date date) {
178 return violation.getCreatedAt()!= null && violation.getCreatedAt().after(date);
181 private Metric getMetricForSeverity(RulePriority severity) {
183 if (severity.equals(RulePriority.BLOCKER)) {
184 metric = CoreMetrics.NEW_BLOCKER_VIOLATIONS;
185 } else if (severity.equals(RulePriority.CRITICAL)) {
186 metric = CoreMetrics.NEW_CRITICAL_VIOLATIONS;
187 } else if (severity.equals(RulePriority.MAJOR)) {
188 metric = CoreMetrics.NEW_MAJOR_VIOLATIONS;
189 } else if (severity.equals(RulePriority.MINOR)) {
190 metric = CoreMetrics.NEW_MINOR_VIOLATIONS;
191 } else if (severity.equals(RulePriority.INFO)) {
192 metric = CoreMetrics.NEW_INFO_VIOLATIONS;
194 throw new IllegalArgumentException("Not supported severity: " + severity);
200 public String toString() {
201 return getClass().getSimpleName();