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 }