KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jeantessier > metrics > StatisticalMeasurement


1 /*
2  * Copyright (c) 2001-2005, Jean Tessier
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of Jean Tessier nor the names of his contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */

32
33 package com.jeantessier.metrics;
34
35 import java.io.*;
36 import java.text.*;
37 import java.util.*;
38
39 import org.apache.log4j.*;
40
41 /**
42  * <p>Computes the statistical properties of a given measurement across the
43  * submetrics of the measurement's context. Given a measurement name, it
44  * explores the tree of metrics rooted at the context and finds the numerical
45  * value of these named measurements in the tree. For these measurements, it
46  * computes:</p>
47  *
48  * <ul>
49  * <li>minimum value</li>
50  * <li>median value</li>
51  * <li>average value</li>
52  * <li>standard deviation</li>
53  * <li>maximum value</li>
54  * <li>sum</li>
55  * <li>number of data points</li>
56  * </ul>
57  *
58  * <p>This is the syntax for initializing this type of measurement:</p>
59  *
60  * <pre>
61  * &lt;init&gt;
62  * monitored measurement name [DISPOSE_x]
63  * [DISPOSE_x]
64  * &lt;/init&gt;
65  * </pre>
66  *
67  * <p>If the monitored measurement is itself a statistical measurement, the
68  * disposition indicates how to deal with it, which of its values to use in
69  * this measurement's calculation. The default is {@link #DISPOSE_IGNORE},
70  * meaning it should skip statistical measurements look in further submetrics
71  * for raw values.</p>
72  *
73  * <p>The second disposition tells which internal value to return in calls to
74  * its {@link #compute} method, which will be used by clients that do not
75  * distinguish between StatisticalMeasurent and other Measurements. The
76  * default is {@link #DISPOSE_AVERAGE}.</p>
77  */

78 public class StatisticalMeasurement extends MeasurementBase {
79     private static final NumberFormat valueFormat = new DecimalFormat("#.##");
80
81     /** Ignore StatisticalMeasurements and drill down to the next level */
82     public static final int DISPOSE_IGNORE = 0;
83
84     /** Use Minimum() value on StatisticalMeasurements */
85     public static final int DISPOSE_MINIMUM = 1;
86
87     /** Use Median() value on StatisticalMeasurements */
88     public static final int DISPOSE_MEDIAN = 2;
89
90     /** Use Average() value on StatisticalMeasurements */
91     public static final int DISPOSE_AVERAGE = 3;
92
93     /** Use StandardDeviation() value on StatisticalMeasurements */
94     public static final int DISPOSE_STANDARD_DEVIATION = 4;
95
96     /** Use Maximum() value on StatisticalMeasurements */
97     public static final int DISPOSE_MAXIMUM = 5;
98
99     /** Use Sum() value on StatisticalMeasurements */
100     public static final int DISPOSE_SUM = 6;
101
102     /** Use NbDataPoints() value on StatisticalMeasurements */
103     public static final int DISPOSE_NB_DATA_POINTS = 7;
104
105     public static String JavaDoc getDisposeLabel(int dispose) {
106         String JavaDoc result = "";
107
108         switch (dispose) {
109             case DISPOSE_MINIMUM:
110                 result = "minimum";
111                 break;
112         
113             case DISPOSE_MEDIAN:
114                 result = "median";
115                 break;
116         
117             case DISPOSE_AVERAGE:
118                 result = "average";
119                 break;
120         
121             case DISPOSE_STANDARD_DEVIATION:
122                 result = "standard deviation";
123                 break;
124         
125             case DISPOSE_MAXIMUM:
126                 result = "maximum";
127                 break;
128         
129             case DISPOSE_SUM:
130                 result = "sum";
131                 break;
132         
133             case DISPOSE_NB_DATA_POINTS:
134                 result = "number of data points";
135                 break;
136         
137             case DISPOSE_IGNORE:
138             default:
139                 break;
140         }
141         
142         return result;
143     }
144
145     public static String JavaDoc getDisposeAbbreviation(int dispose) {
146         String JavaDoc result = "";
147
148         switch (dispose) {
149             case DISPOSE_MINIMUM:
150                 result = "min";
151                 break;
152         
153             case DISPOSE_MEDIAN:
154                 result = "med";
155                 break;
156         
157             case DISPOSE_AVERAGE:
158                 result = "avg";
159                 break;
160         
161             case DISPOSE_STANDARD_DEVIATION:
162                 result = "sdv";
163                 break;
164         
165             case DISPOSE_MAXIMUM:
166                 result = "max";
167                 break;
168         
169             case DISPOSE_SUM:
170                 result = "sum";
171                 break;
172         
173             case DISPOSE_NB_DATA_POINTS:
174                 result = "nb";
175                 break;
176         
177             case DISPOSE_IGNORE:
178             default:
179                 break;
180         }
181         
182         return result;
183     }
184
185     private String JavaDoc monitoredMeasurement;
186     private int dispose;
187     private int selfDispose;
188     
189     private List data = new LinkedList();
190
191     private double minimum = 0.0;
192     private double median = 0.0;
193     private double average = 0.0;
194     private double standardDeviation = 0.0;
195     private double maximum = 0.0;
196     private double sum = 0.0;
197     private int nbDataPoints = 0;
198
199     private int nbSubmetrics = -1;
200
201     public StatisticalMeasurement(MeasurementDescriptor descriptor, Metrics context, String JavaDoc initText) {
202         super(descriptor, context, initText);
203
204         try {
205             BufferedReader in = new BufferedReader(new StringReader(initText));
206             monitoredMeasurement = in.readLine().trim();
207
208             synchronized (perl()) {
209                 if (perl().match("/(.*)\\s+(dispose_\\w+)$/i", monitoredMeasurement)) {
210                     monitoredMeasurement = perl().group(1);
211                     
212                     String JavaDoc disposeText = perl().group(2);
213                     
214                     if (disposeText.equalsIgnoreCase("DISPOSE_IGNORE")) {
215                         dispose = DISPOSE_IGNORE;
216                     } else if (disposeText.equalsIgnoreCase("DISPOSE_MINIMUM")) {
217                         dispose = DISPOSE_MINIMUM;
218                     } else if (disposeText.equalsIgnoreCase("DISPOSE_MEDIAN")) {
219                         dispose = DISPOSE_MEDIAN;
220                     } else if (disposeText.equalsIgnoreCase("DISPOSE_AVERAGE")) {
221                         dispose = DISPOSE_AVERAGE;
222                     } else if (disposeText.equalsIgnoreCase("DISPOSE_STANDARD_DEVIATION")) {
223                         dispose = DISPOSE_STANDARD_DEVIATION;
224                     } else if (disposeText.equalsIgnoreCase("DISPOSE_MAXIMUM")) {
225                         dispose = DISPOSE_MAXIMUM;
226                     } else if (disposeText.equalsIgnoreCase("DISPOSE_SUM")) {
227                         dispose = DISPOSE_SUM;
228                     } else if (disposeText.equalsIgnoreCase("DISPOSE_NB_DATA_POINTS")) {
229                         dispose = DISPOSE_NB_DATA_POINTS;
230                     } else {
231                         dispose = DISPOSE_IGNORE;
232                     }
233                 } else {
234                     dispose = DISPOSE_IGNORE;
235                 }
236             }
237
238             String JavaDoc selfDisposeText = in.readLine();
239             if (selfDisposeText != null) {
240                 selfDisposeText = selfDisposeText.trim();
241
242                 if (selfDisposeText.equalsIgnoreCase("DISPOSE_IGNORE")) {
243                     selfDispose = DISPOSE_IGNORE;
244                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_MINIMUM")) {
245                     selfDispose = DISPOSE_MINIMUM;
246                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_MEDIAN")) {
247                     selfDispose = DISPOSE_MEDIAN;
248                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_AVERAGE")) {
249                     selfDispose = DISPOSE_AVERAGE;
250                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_STANDARD_DEVIATION")) {
251                     selfDispose = DISPOSE_STANDARD_DEVIATION;
252                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_MAXIMUM")) {
253                     selfDispose = DISPOSE_MAXIMUM;
254                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_SUM")) {
255                     selfDispose = DISPOSE_SUM;
256                 } else if (selfDisposeText.equalsIgnoreCase("DISPOSE_NB_DATA_POINTS")) {
257                     selfDispose = DISPOSE_NB_DATA_POINTS;
258                 } else {
259                     selfDispose = DISPOSE_AVERAGE;
260                 }
261             } else {
262                 selfDispose = DISPOSE_AVERAGE;
263             }
264             
265             in.close();
266         } catch (Exception JavaDoc ex) {
267             Logger.getLogger(getClass()).debug("Cannot initialize with \"" + initText + "\"", ex);
268             monitoredMeasurement = null;
269         }
270     }
271     
272     public double getMinimum() {
273         collectData();
274         return minimum;
275     }
276
277     public double getMedian() {
278         collectData();
279         return median;
280     }
281
282     public double getAverage() {
283         collectData();
284         return average;
285     }
286
287     /**
288      * Real standard deviation of the data set.
289      * This is NOT the estimator "s".
290      */

291     public double getStandardDeviation() {
292         collectData();
293         return standardDeviation;
294     }
295
296     public double getMaximum() {
297         collectData();
298         return maximum;
299     }
300
301     public double getSum() {
302         collectData();
303         return sum;
304     }
305
306     public int getNbDataPoints() {
307         collectData();
308         return nbDataPoints;
309     }
310     
311     private void collectData() {
312         if (getContext().getSubMetrics().size() != nbSubmetrics) {
313             synchronized (this) {
314                 if (getContext().getSubMetrics().size() != nbSubmetrics) {
315                     data = new LinkedList();
316                     setEmpty(true);
317                     
318                     Iterator i = getContext().getSubMetrics().iterator();
319                     while (i.hasNext()) {
320                         visitMetrics((Metrics) i.next());
321                     }
322                     
323                     if (!data.isEmpty()) {
324                         Collections.sort(data);
325                         
326                         minimum = ((Number JavaDoc) data.get(0)).doubleValue();
327                         median = ((Number JavaDoc) data.get(data.size() / 2)).doubleValue();
328                         maximum = ((Number JavaDoc) data.get(data.size() - 1)).doubleValue();
329                         nbDataPoints = data.size();
330                         
331                         sum = 0.0;
332                         Iterator j = data.iterator();
333                         while (j.hasNext()) {
334                             sum += ((Number JavaDoc) j.next()).doubleValue();
335                         }
336                     } else {
337                         minimum = Double.NaN;
338                         median = Double.NaN;
339                         maximum = Double.NaN;
340                         nbDataPoints = 0;
341                         sum = 0.0;
342                     }
343                     
344                     average = sum / nbDataPoints;
345                     
346                     if (!data.isEmpty()) {
347                         double temp = 0.0;
348                         
349                         Iterator j = data.iterator();
350                         while (j.hasNext()) {
351                             temp += Math.pow(((Number JavaDoc) j.next()).doubleValue() - average, 2);
352                         }
353                         
354                         standardDeviation = Math.sqrt(temp / nbDataPoints);
355                     } else {
356                         standardDeviation = Double.NaN;
357                     }
358                     
359                     nbSubmetrics = getContext().getSubMetrics().size();
360                 }
361             }
362         }
363     }
364     
365     private void visitMetrics(Metrics metrics) {
366         Logger.getLogger(getClass()).debug("VisitMetrics: " + metrics.getName());
367         
368         Measurement measurement = metrics.getMeasurement(monitoredMeasurement);
369
370         Logger.getLogger(getClass()).debug("measurement for " + monitoredMeasurement + " is " + measurement.getClass());
371         
372         if (measurement instanceof StatisticalMeasurement) {
373             StatisticalMeasurement stats = (StatisticalMeasurement) measurement;
374             
375             Logger.getLogger(getClass()).debug("dispose of StatisticalMeasurements is " + dispose);
376
377             switch (dispose) {
378                 case DISPOSE_MINIMUM:
379                     Logger.getLogger(getClass()).debug("using Minimum(): " + stats.getMinimum());
380                     data.add(new Double JavaDoc(stats.getMinimum()));
381                     break;
382                     
383                 case DISPOSE_MEDIAN:
384                     Logger.getLogger(getClass()).debug("using Median(): " + stats.getMedian());
385                     data.add(new Double JavaDoc(stats.getMedian()));
386                     break;
387                     
388                 case DISPOSE_AVERAGE:
389                     Logger.getLogger(getClass()).debug("using Average(): " + stats.getAverage());
390                     data.add(new Double JavaDoc(stats.getAverage()));
391                     break;
392                             
393                 case DISPOSE_STANDARD_DEVIATION:
394                     Logger.getLogger(getClass()).debug("using StandardDeviation(): " + stats.getStandardDeviation());
395                     data.add(new Double JavaDoc(stats.getStandardDeviation()));
396                     break;
397             
398                 case DISPOSE_MAXIMUM:
399                     Logger.getLogger(getClass()).debug("using Maximum(): " + stats.getMaximum());
400                     data.add(new Double JavaDoc(stats.getMaximum()));
401                     break;
402                     
403                 case DISPOSE_SUM:
404                     Logger.getLogger(getClass()).debug("using Sum(): " + stats.getSum());
405                     data.add(new Double JavaDoc(stats.getSum()));
406                     break;
407                     
408                 case DISPOSE_NB_DATA_POINTS:
409                     Logger.getLogger(getClass()).debug("using NbDataPoints(): " + stats.getNbDataPoints());
410                     data.add(new Integer JavaDoc(stats.getNbDataPoints()));
411                     break;
412
413                 case DISPOSE_IGNORE:
414                 default:
415                     Logger.getLogger(getClass()).debug("Skipping to next level ...");
416                     Iterator i = metrics.getSubMetrics().iterator();
417                     while (i.hasNext()) {
418                         visitMetrics((Metrics) i.next());
419                     }
420                     break;
421             }
422         } else if (measurement instanceof NullMeasurement) {
423             Logger.getLogger(getClass()).debug("Skipping to next level ...");
424             Iterator i = metrics.getSubMetrics().iterator();
425             while (i.hasNext()) {
426                 visitMetrics((Metrics) i.next());
427             }
428         } else {
429             Number JavaDoc value = measurement.getValue();
430             
431             Logger.getLogger(getClass()).debug(monitoredMeasurement + " on " + metrics.getName() + " is " + value);
432
433             if (value != null) {
434                 data.add(value);
435             }
436         }
437
438         if (super.isEmpty()) {
439             setEmpty(measurement.isEmpty());
440         }
441     }
442
443     public boolean isEmpty() {
444         collectData();
445         
446         return super.isEmpty();
447     }
448
449     public void accept(MeasurementVisitor visitor) {
450         visitor.visitStatisticalMeasurement(this);
451     }
452
453     protected double compute() {
454         double result = Double.NaN;
455         
456         switch (selfDispose) {
457             case DISPOSE_MINIMUM:
458                 result = getMinimum();
459                 break;
460                 
461             case DISPOSE_MEDIAN:
462                 result = getMedian();
463                 break;
464                 
465             case DISPOSE_AVERAGE:
466                 result = getAverage();
467                 break;
468                 
469             case DISPOSE_STANDARD_DEVIATION:
470                 result = getStandardDeviation();
471                 break;
472                 
473             case DISPOSE_MAXIMUM:
474                 result = getMaximum();
475                 break;
476                 
477             case DISPOSE_SUM:
478                 result = getSum();
479                 break;
480                 
481             case DISPOSE_NB_DATA_POINTS:
482                 result = getNbDataPoints();
483                 break;
484
485             case DISPOSE_IGNORE:
486             default:
487                 break;
488         }
489
490         return result;
491     }
492
493     public String JavaDoc toString() {
494         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
495
496         result.append("[").append(valueFormat.format(getMinimum()));
497         result.append(" ").append(valueFormat.format(getMedian()));
498         result.append("/").append(valueFormat.format(getAverage()));
499         result.append(" ").append(valueFormat.format(getStandardDeviation()));
500         result.append(" ").append(valueFormat.format(getMaximum()));
501         result.append(" ").append(valueFormat.format(getSum()));
502         result.append(" (").append(valueFormat.format(getNbDataPoints())).append(")]");
503         
504         return result.toString();
505     }
506 }
507
Popular Tags