001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 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 */
020package org.sonar.plugins.core.sensors;
021
022import com.google.common.collect.Multiset;
023import com.google.common.collect.TreeMultiset;
024import org.sonar.api.CoreProperties;
025import org.sonar.api.Properties;
026import org.sonar.api.Property;
027import org.sonar.api.batch.Decorator;
028import org.sonar.api.batch.DecoratorContext;
029import org.sonar.api.batch.DependedUpon;
030import org.sonar.api.batch.DependsUpon;
031import org.sonar.api.config.Settings;
032import org.sonar.api.measures.CoreMetrics;
033import org.sonar.api.measures.Measure;
034import org.sonar.api.measures.MeasureUtils;
035import org.sonar.api.measures.Metric;
036import org.sonar.api.resources.Project;
037import org.sonar.api.resources.Resource;
038import org.sonar.api.rules.RulePriority;
039import org.sonar.api.utils.KeyValueFormat;
040
041import java.util.Arrays;
042import java.util.List;
043import java.util.Map;
044
045@Properties(
046    @Property(
047        key = CoreProperties.CORE_RULE_WEIGHTS_PROPERTY,
048        defaultValue = CoreProperties.CORE_RULE_WEIGHTS_DEFAULT_VALUE,
049        name = "Rules weight",
050        description = "A weight is associated to each severity to calculate the Rules Compliance Index.",
051        project = false,
052        global = true,
053        category = CoreProperties.CATEGORY_GENERAL)
054)
055public class WeightedViolationsDecorator implements Decorator {
056
057  private Settings settings;
058  private Map<RulePriority, Integer> weightsBySeverity;
059
060  public WeightedViolationsDecorator(Settings settings) {
061    this.settings = settings;
062  }
063
064  @DependsUpon
065  public List<Metric> dependsUponViolations() {
066    return Arrays.asList(CoreMetrics.BLOCKER_VIOLATIONS, CoreMetrics.CRITICAL_VIOLATIONS,
067        CoreMetrics.MAJOR_VIOLATIONS, CoreMetrics.MINOR_VIOLATIONS, CoreMetrics.INFO_VIOLATIONS);
068  }
069
070  @DependedUpon
071  public Metric generatesWeightedViolations() {
072    return CoreMetrics.WEIGHTED_VIOLATIONS;
073  }
074
075  public boolean shouldExecuteOnProject(Project project) {
076    return true;
077  }
078
079  public void start() {
080    weightsBySeverity = getWeights(settings);
081  }
082
083  Map<RulePriority, Integer> getWeightsBySeverity() {
084    return weightsBySeverity;
085  }
086
087  static Map<RulePriority, Integer> getWeights(final Settings settings) {
088    String value = settings.getString(CoreProperties.CORE_RULE_WEIGHTS_PROPERTY);
089
090    Map<RulePriority, Integer> weights = KeyValueFormat.parse(value, KeyValueFormat.newPriorityConverter(), KeyValueFormat.newIntegerConverter());
091
092    for (RulePriority priority : RulePriority.values()) {
093      if (!weights.containsKey(priority)) {
094        weights.put(priority, 1);
095      }
096    }
097    return weights;
098  }
099
100
101  public void decorate(Resource resource, DecoratorContext context) {
102    decorate(context);
103  }
104
105  void decorate(DecoratorContext context) {
106    double debt = 0.0;
107    Multiset<RulePriority> distribution = TreeMultiset.create();
108
109    for (RulePriority severity : RulePriority.values()) {
110      Measure measure = context.getMeasure(SeverityUtils.severityToViolationMetric(severity));
111      if (measure != null && MeasureUtils.hasValue(measure)) {
112        distribution.add(severity, measure.getIntValue());
113        double add = weightsBySeverity.get(severity) * measure.getIntValue();
114        debt += add;
115      }
116    }
117
118    Measure debtMeasure = new Measure(CoreMetrics.WEIGHTED_VIOLATIONS, debt, KeyValueFormat.format(distribution));
119    context.saveMeasure(debtMeasure);
120  }
121
122}