View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.lang.rule.stat;
    5
    6   import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.MINIMUM_DESCRIPTOR;
    7   import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.SIGMA_DESCRIPTOR;
    8   import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.TOP_SCORE_DESCRIPTOR;
    9
    10  import java.util.Set;
    11  import java.util.SortedSet;
    12  import java.util.TreeSet;
    13
    14  import net.sourceforge.pmd.RuleContext;
    15  import net.sourceforge.pmd.lang.rule.AbstractRule;
    16  import net.sourceforge.pmd.stat.DataPoint;
    17  import net.sourceforge.pmd.stat.Metric;
    18
    19  /**
    20   * This class is used to implement the core logic of a StatisticalRule.
    21   * Concrete Rule implementations should delegate to an instance of this class.
    22   *
    23   * @author David Dixon-Peugh
    24   *         Aug 8, 2002 StatisticalRule.java
    25   */
    26  public class StatisticalRuleHelper {
    27
    28      public static final double DELTA = 0.000005; // Within this range. . .
    29
    30      private AbstractRule rule;
    31
    32      private SortedSet<DataPoint> dataPoints = new TreeSet<DataPoint>();
    33
    34      private int count = 0;
    35      private double total = 0.0;
    36
    37      public StatisticalRuleHelper(AbstractRule rule) {
    38      	this.rule = rule;
    39      	rule.definePropertyDescriptor(SIGMA_DESCRIPTOR);
    40      	rule.definePropertyDescriptor(MINIMUM_DESCRIPTOR);
    41      	rule.definePropertyDescriptor(TOP_SCORE_DESCRIPTOR);
    42      }
    43
    44      public void addDataPoint(DataPoint point) {
    45          count++;
    46          total += point.getScore();
    47          dataPoints.add(point);
    48      }
    49
    50      public void apply(RuleContext ctx) {
    51
    52          double deviation;
    53          double minimum = 0.0;
    54
    55          if (rule.getProperty(SIGMA_DESCRIPTOR) != null) {	// TODO - need to come up with a good default value
    56              deviation = getStdDev();
    57              double sigma = rule.getProperty(SIGMA_DESCRIPTOR);
    58              minimum = getMean() + (sigma * deviation);
    59          }
    60
    61          if (rule.getProperty(MINIMUM_DESCRIPTOR) != null) {	// TODO - need to come up with a good default value
    62              double mMin = rule.getProperty(MINIMUM_DESCRIPTOR);
    63              if (mMin > minimum) {
    64                  minimum = mMin;
    65              }
    66          }
    67
    68          SortedSet<DataPoint> newPoints = applyMinimumValue(dataPoints, minimum);
    69
    70          if (rule.getProperty(TOP_SCORE_DESCRIPTOR) != null) {	// TODO - need to come up with a good default value
    71              int topScore = rule.getProperty(TOP_SCORE_DESCRIPTOR);
    72              if (newPoints.size() >= topScore) {
    73                  newPoints = applyTopScore(newPoints, topScore);
    74              }
    75          }
    76
    77          makeViolations(ctx, newPoints);
    78
    79          double low = 0.0d;
    80          double high = 0.0d;
    81          if (!dataPoints.isEmpty()) {
    82              low = dataPoints.first().getScore();
    83              high = dataPoints.last().getScore();
    84          }
    85
    86          ctx.getReport().addMetric(new Metric(rule.getName(), count, total, low, high, getMean(), getStdDev()));
    87
    88          dataPoints.clear();
    89      }
    90
    91      private double getMean() {
    92          return total / count;
    93      }
    94
    95      private double getStdDev() {
    96          if (dataPoints.size() < 2) {
    97              return Double.NaN;
    98          }
    99
    100         double mean = getMean();
    101         double deltaSq = 0.0;
    102         double scoreMinusMean;
    103
    104         for (DataPoint point: dataPoints) {
    105             scoreMinusMean = point.getScore() - mean;
    106             deltaSq += scoreMinusMean * scoreMinusMean;
    107         }
    108
    109         return Math.sqrt(deltaSq / (dataPoints.size() - 1));
    110     }
    111
    112     private SortedSet<DataPoint> applyMinimumValue(SortedSet<DataPoint> pointSet, double minValue) {
    113         SortedSet<DataPoint> rc = new TreeSet<DataPoint>();
    114         double threshold = minValue - DELTA;
    115
    116         for (DataPoint point: pointSet) {
    117             if (point.getScore() > threshold) {
    118                 rc.add(point);
    119             }
    120         }
    121         return rc;
    122     }
    123
    124     private SortedSet<DataPoint> applyTopScore(SortedSet<DataPoint> points, int topScore) {
    125         SortedSet<DataPoint> s = new TreeSet<DataPoint>();
    126         DataPoint[] arr = points.toArray(new DataPoint[]{});
    127         for (int i = arr.length - 1; i >= (arr.length - topScore); i--) {
    128             s.add(arr[i]);
    129         }
    130         return s;
    131     }
    132
    133     private void makeViolations(RuleContext ctx, Set<DataPoint> p) {
    134         for (DataPoint point: p) {
    135             rule.addViolationWithMessage(ctx, point.getNode(), point.getMessage(), ((StatisticalRule)rule).getViolationParameters(point));
    136         }
    137     }
    138 }