View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.stat;
    5
    6   import java.util.Iterator;
    7   import java.util.List;
    8   import java.util.Map;
    9   import java.util.Set;
    10  import java.util.SortedSet;
    11  import java.util.TreeSet;
    12
    13  import net.sourceforge.pmd.AbstractRule;
    14  import net.sourceforge.pmd.PropertyDescriptor;
    15  import net.sourceforge.pmd.RuleContext;
    16  import net.sourceforge.pmd.properties.DoubleProperty;
    17  import net.sourceforge.pmd.properties.IntegerProperty;
    18
    19  /***
    20   * @author David Dixon-Peugh
    21   *         Aug 8, 2002 StatisticalRule.java
    22   */
    23  public abstract class StatisticalRule extends AbstractRule {
    24
    25      public static double DELTA = 0.000005; // Within this range. . .
    26
    27      private SortedSet dataPoints = new TreeSet();
    28
    29      private int count = 0;
    30      private double total = 0.0;
    31
    32      private static final PropertyDescriptor sigmaDescriptor = new DoubleProperty(
    33      	"sigma", "Sigma value",	0,	1.0f
    34      	);
    35
    36      private static final PropertyDescriptor minimumDescriptor = new DoubleProperty(
    37          "minimum", "Minimum value",	0,	1.0f
    38          );
    39
    40      private static final PropertyDescriptor topScoreDescriptor = new IntegerProperty(
    41          "topscore", "Top score value",	0,	1.0f
    42          );
    43
    44      private static final Map propertyDescriptorsByName = asFixedMap( new PropertyDescriptor[] {
    45      	sigmaDescriptor, minimumDescriptor, topScoreDescriptor
    46      	});
    47
    48
    49      public void addDataPoint(DataPoint point) {
    50          count++;
    51          total += point.getScore();
    52          dataPoints.add(point);
    53      }
    54
    55      public void apply(List acus, RuleContext ctx) {
    56          visitAll(acus, ctx);
    57
    58          double deviation;
    59          double minimum = 0.0;
    60
    61          if (hasProperty("sigma")) {	// TODO - need to come up with a good default value
    62              deviation = getStdDev();
    63              double sigma = getDoubleProperty(sigmaDescriptor);
    64              minimum = getMean() + (sigma * deviation);
    65          }
    66
    67          if (hasProperty("minimum")) {	// TODO - need to come up with a good default value
    68              double mMin = getDoubleProperty(minimumDescriptor);
    69              if (mMin > minimum) {
    70                  minimum = mMin;
    71              }
    72          }
    73
    74          SortedSet newPoints = applyMinimumValue(dataPoints, minimum);
    75
    76          if (hasProperty("topscore")) { // TODO - need to come up with a good default value
    77              int topScore = getIntProperty(topScoreDescriptor);
    78              if (newPoints.size() >= topScore) {
    79                  newPoints = applyTopScore(newPoints, topScore);
    80              }
    81          }
    82
    83          makeViolations(ctx, newPoints);
    84
    85          double low = 0.0d;
    86          double high = 0.0d;
    87          if (!dataPoints.isEmpty()) {
    88              low = ((DataPoint) dataPoints.first()).getScore();
    89              high = ((DataPoint) dataPoints.last()).getScore();
    90          }
    91
    92          ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev()));
    93
    94          dataPoints.clear();
    95      }
    96
    97      protected double getMean() {
    98          return total / count;
    99      }
    100
    101     protected double getStdDev() {
    102         if (dataPoints.size() < 2) {
    103             return Double.NaN;
    104         }
    105
    106         Iterator points = dataPoints.iterator();
    107         double mean = getMean();
    108         double deltaSq = 0.0;
    109         double scoreMinusMean;
    110
    111         while (points.hasNext()) {
    112             scoreMinusMean = ((DataPoint) points.next()).getScore() - mean;
    113             deltaSq += (scoreMinusMean * scoreMinusMean);
    114         }
    115
    116         return Math.sqrt(deltaSq / (dataPoints.size() - 1));
    117     }
    118
    119     protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) {
    120         Iterator points = pointSet.iterator();
    121         SortedSet RC = new TreeSet();
    122         double threshold = minValue - DELTA;
    123
    124         while (points.hasNext()) {
    125             DataPoint point = (DataPoint) points.next();
    126
    127             if (point.getScore() > threshold) {
    128                 RC.add(point);
    129             }
    130         }
    131         return RC;
    132     }
    133
    134     protected SortedSet applyTopScore(SortedSet points, int topScore) {
    135         SortedSet s = new TreeSet();
    136         Object[] arr = points.toArray();
    137         for (int i = arr.length - 1; i >= (arr.length - topScore); i--) {
    138             s.add(arr[i]);
    139         }
    140         return s;
    141     }
    142
    143     protected void makeViolations(RuleContext ctx, Set p) {
    144         Iterator points = p.iterator();
    145         while (points.hasNext()) {
    146             DataPoint point = (DataPoint) points.next();
    147             addViolationWithMessage(ctx, point.getNode(), point.getMessage());
    148         }
    149     }
    150
    151     protected Map propertiesByName() {
    152     	return propertyDescriptorsByName;
    153     }
    154 }