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 net.sourceforge.pmd.AbstractRule;
7   import net.sourceforge.pmd.RuleContext;
8   
9   import java.util.Iterator;
10  import java.util.List;
11  import java.util.Set;
12  import java.util.SortedSet;
13  import java.util.TreeSet;
14  
15  /***
16   * @author David Dixon-Peugh
17   * Aug 8, 2002 StatisticalRule.java
18   */
19  public abstract class StatisticalRule extends AbstractRule {
20      public static double DELTA = 0.000005; // Within this range. . .
21  
22      private SortedSet dataPoints = new TreeSet();
23  
24      private int count = 0;
25      private double total = 0.0;
26      private double totalSquared = 0.0;
27  
28      public void addDataPoint(DataPoint point) {
29          count++;
30          total += point.getScore();
31          totalSquared += point.getScore() * point.getScore();
32          dataPoints.add(point);
33      }
34  
35      public void apply(List acus, RuleContext ctx) {
36          visitAll(acus, ctx);
37  
38          double deviation;
39          double minimum = 0.0;
40  
41          if (hasProperty("sigma")) {
42              deviation = getStdDev();
43              double sigma = getDoubleProperty("sigma");
44  
45              minimum = getMean() + (sigma * deviation);
46          }
47  
48          if (hasProperty("minimum")) {
49              double mMin = getDoubleProperty("minimum");
50              if (mMin > minimum) {
51                  minimum = mMin;
52              }
53          }
54  
55          SortedSet newPoints = applyMinimumValue(dataPoints, minimum);
56  
57          if (hasProperty("topscore")) {
58              int topScore = getIntProperty("topscore");
59              if (newPoints.size() >= topScore) {
60                  newPoints = applyTopScore(newPoints, topScore);
61              }
62          }
63  
64          makeViolations(ctx, newPoints);
65  
66          double low = 0.0d;
67          double high = 0.0d;
68          if (!dataPoints.isEmpty()) {
69              low = ((DataPoint) dataPoints.first()).getScore();
70              high = ((DataPoint) dataPoints.last()).getScore();
71          }
72  
73          ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev()));
74  
75          dataPoints.clear();
76      }
77  
78      protected double getMean() {
79          return total / count;
80      }
81  
82      protected double getStdDev() {
83      	Iterator points = dataPoints.iterator();
84      	double mean = getMean();
85      	double deltaSq = 0.0;
86      	
87      	if (dataPoints.size() < 2) {
88      		return Double.NaN;
89      	}
90      	
91      	while (points.hasNext()) {
92      		DataPoint point = (DataPoint) points.next();	
93      		deltaSq += ((point.getScore() - mean) * (point.getScore() - mean));
94      	}
95      	
96      	return Math.sqrt( deltaSq / (dataPoints.size() - 1));
97      }
98  
99      protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) {
100         Iterator points = pointSet.iterator();
101         SortedSet RC = new TreeSet();
102 
103         while (points.hasNext()) {
104             DataPoint point = (DataPoint) points.next();
105 
106             if (point.getScore() > (minValue - DELTA)) {
107                 RC.add(point);
108             }
109         }
110         return RC;
111     }
112 
113     protected SortedSet applyTopScore(SortedSet points, int topScore) {
114         SortedSet RC = new TreeSet();
115         for (int i = 0; i < topScore; i++) {
116             DataPoint point = (DataPoint) points.last();
117             points.remove(point);
118 
119             RC.add(point);
120         }
121 
122         return RC;
123     }
124 
125     protected void makeViolations(RuleContext ctx, Set dataPoints) {
126         Iterator points = dataPoints.iterator();
127         while (points.hasNext()) {
128             DataPoint point = (DataPoint) points.next();
129             ctx.getReport().addRuleViolation(this.createRuleViolation(ctx, point.getLineNumber(), point.getMessage()));
130         }
131     }
132 }