001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.plugins.core.sensors;
021    
022    import com.google.common.collect.HashMultiset;
023    import com.google.common.collect.Maps;
024    import com.google.common.collect.Multiset;
025    import org.sonar.api.batch.*;
026    import org.sonar.api.measures.*;
027    import org.sonar.api.resources.Project;
028    import org.sonar.api.resources.Resource;
029    import org.sonar.api.resources.ResourceUtils;
030    import org.sonar.api.rules.Rule;
031    import org.sonar.api.rules.RulePriority;
032    import org.sonar.api.rules.Violation;
033    
034    import java.util.Arrays;
035    import java.util.Collection;
036    import java.util.List;
037    import java.util.Map;
038    
039    @DependsUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING)
040    public class ViolationsDecorator implements Decorator {
041    
042      // temporary data for current resource
043      private Multiset<Rule> rules = HashMultiset.create();
044      private Multiset<RulePriority> severities = HashMultiset.create();
045      private Map<Rule, RulePriority> ruleToSeverity = Maps.newHashMap();
046      private int total = 0;
047    
048      public boolean shouldExecuteOnProject(Project project) {
049        return true;
050      }
051    
052      @DependedUpon
053      public List<Metric> generatesViolationsMetrics() {
054        return Arrays.asList(CoreMetrics.VIOLATIONS,
055            CoreMetrics.BLOCKER_VIOLATIONS, CoreMetrics.CRITICAL_VIOLATIONS, CoreMetrics.MAJOR_VIOLATIONS, CoreMetrics.MINOR_VIOLATIONS, CoreMetrics.INFO_VIOLATIONS);
056      }
057    
058      public void decorate(Resource resource, DecoratorContext context) {
059        if (shouldDecorateResource(resource)) {
060          resetCounters();
061          countViolations(context);
062          saveTotalViolations(context);
063          saveViolationsBySeverity(context);
064          saveViolationsByRule(context);
065        }
066      }
067    
068      private boolean shouldDecorateResource(Resource resource) {
069        return !ResourceUtils.isUnitTestClass(resource);
070      }
071    
072      private void resetCounters() {
073        rules.clear();
074        severities.clear();
075        ruleToSeverity.clear();
076        total = 0;
077      }
078    
079      private void saveViolationsBySeverity(DecoratorContext context) {
080        for (RulePriority severity : RulePriority.values()) {
081          Metric metric = getMetricForSeverity(severity);
082          if (context.getMeasure(metric) == null) {
083            Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.metric(metric));
084            double sum = MeasureUtils.sum(true, children) + severities.count(severity);
085            context.saveMeasure(new Measure(metric, sum));
086          }
087        }
088      }
089    
090      private Metric getMetricForSeverity(RulePriority severity) {
091        Metric metric = null;
092        if (severity.equals(RulePriority.BLOCKER)) {
093          metric = CoreMetrics.BLOCKER_VIOLATIONS;
094        } else if (severity.equals(RulePriority.CRITICAL)) {
095          metric = CoreMetrics.CRITICAL_VIOLATIONS;
096        } else if (severity.equals(RulePriority.MAJOR)) {
097          metric = CoreMetrics.MAJOR_VIOLATIONS;
098        } else if (severity.equals(RulePriority.MINOR)) {
099          metric = CoreMetrics.MINOR_VIOLATIONS;
100        } else if (severity.equals(RulePriority.INFO)) {
101          metric = CoreMetrics.INFO_VIOLATIONS;
102        }
103        return metric;
104      }
105    
106      private void saveViolationsByRule(DecoratorContext context) {
107        Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.rules(CoreMetrics.VIOLATIONS));
108        for (Measure childMeasure : children) {
109          RuleMeasure childRuleMeasure = (RuleMeasure) childMeasure;
110          Rule rule = childRuleMeasure.getRule();
111          if (rule != null && MeasureUtils.hasValue(childRuleMeasure)) {
112            rules.add(rule, childRuleMeasure.getValue().intValue());
113            ruleToSeverity.put(childRuleMeasure.getRule(), childRuleMeasure.getRulePriority());
114          }
115        }
116        for (Multiset.Entry<Rule> entry : rules.entrySet()) {
117          Rule rule = entry.getElement();
118          RuleMeasure measure = RuleMeasure.createForRule(CoreMetrics.VIOLATIONS, rule, (double) entry.getCount());
119          measure.setRulePriority(ruleToSeverity.get(rule));
120          context.saveMeasure(measure);
121        }
122      }
123    
124      private void saveTotalViolations(DecoratorContext context) {
125        if (context.getMeasure(CoreMetrics.VIOLATIONS) == null) {
126          Collection<Measure> childrenViolations = context.getChildrenMeasures(CoreMetrics.VIOLATIONS);
127          Double sum = MeasureUtils.sum(true, childrenViolations) + total;
128          context.saveMeasure(new Measure(CoreMetrics.VIOLATIONS, sum));
129        }
130      }
131    
132      private void countViolations(DecoratorContext context) {
133        List<Violation> violations = context.getViolations();
134        for (Violation violation : violations) {
135          rules.add(violation.getRule());
136          severities.add(violation.getSeverity());
137          ruleToSeverity.put(violation.getRule(), violation.getSeverity());
138        }
139        total = violations.size();
140      }
141    
142      @Override
143      public String toString() {
144        return getClass().getSimpleName();
145      }
146    }