1 | /* |
2 | * Copyright (c) 2001-2009, 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.util.*; |
37 | |
38 | import org.apache.log4j.*; |
39 | |
40 | /** |
41 | * <p>Adds up numerical values. Use it with just one term to alias |
42 | * other measurements.</p> |
43 | * |
44 | * <p>This is the syntax for initializing this type of |
45 | * measurement:</p> |
46 | * |
47 | * <pre> |
48 | * <init> |
49 | * number | measurement name [DISPOSE_x] |
50 | * ... |
51 | * </init> |
52 | * </pre> |
53 | */ |
54 | public class SumMeasurement extends MeasurementBase { |
55 | private List<String> terms = new LinkedList<String>(); |
56 | |
57 | private double value = 0.0; |
58 | |
59 | public SumMeasurement(MeasurementDescriptor descriptor, Metrics context, String initText) { |
60 | super(descriptor, context, initText); |
61 | |
62 | try { |
63 | BufferedReader in = new BufferedReader(new StringReader(initText)); |
64 | String line; |
65 | |
66 | while ((line = in.readLine()) != null) { |
67 | terms.add(line.trim()); |
68 | } |
69 | |
70 | in.close(); |
71 | } catch (Exception ex) { |
72 | Logger.getLogger(getClass()).debug("Cannot initialize with \"" + initText + "\"", ex); |
73 | terms.clear(); |
74 | } |
75 | } |
76 | |
77 | public List<String> getTerms() { |
78 | return terms; |
79 | } |
80 | |
81 | public boolean isEmpty() { |
82 | compute(); |
83 | |
84 | return super.isEmpty(); |
85 | } |
86 | |
87 | public void accept(MeasurementVisitor visitor) { |
88 | visitor.visitSumMeasurement(this); |
89 | } |
90 | |
91 | protected double compute() { |
92 | if (!isCached()) { |
93 | synchronized (this) { |
94 | if (!isCached()) { |
95 | value = 0.0; |
96 | setEmpty(true); |
97 | |
98 | if (getContext() != null) { |
99 | Logger.getLogger(getClass()).debug("Start computing \"" + getShortName() + "\" on \"" + getContext().getName() + "\": value=" + value); |
100 | } else { |
101 | Logger.getLogger(getClass()).debug("Start computing \"" + getShortName() + "\" on null: value=" + value); |
102 | } |
103 | |
104 | for (String term : getTerms()) { |
105 | Logger.getLogger(getClass()).debug("Evaluating term \"" + term + "\""); |
106 | |
107 | double termValue = Double.NaN; |
108 | |
109 | try { |
110 | termValue = Double.parseDouble(term); |
111 | } catch (NumberFormatException ex) { |
112 | if (term.startsWith("-")) { |
113 | termValue = -1 * evaluateMeasurement(term.substring(1)); |
114 | } else { |
115 | termValue = evaluateMeasurement(term); |
116 | } |
117 | } |
118 | |
119 | Logger.getLogger(getClass()).debug("term \"" + term + "\" is " + termValue); |
120 | |
121 | value += termValue; |
122 | |
123 | Logger.getLogger(getClass()).debug("value=" + value); |
124 | } |
125 | |
126 | if (getContext() != null) { |
127 | Logger.getLogger(getClass()).debug("Stop computing \"" + getShortName() + "\" on \"" + getContext().getName() + "\": value=" + value); |
128 | } else { |
129 | Logger.getLogger(getClass()).debug("Stop computing \"" + getShortName() + "\" on null: value=" + value); |
130 | } |
131 | |
132 | setCached(true); |
133 | } |
134 | } |
135 | } |
136 | |
137 | if (getContext() != null) { |
138 | Logger.getLogger(getClass()).debug("\"" + getShortName() + "\" on \"" + getContext().getName() + "\": value=" + value); |
139 | } else { |
140 | Logger.getLogger(getClass()).debug("\"" + getShortName() + "\" on null: value=" + value); |
141 | } |
142 | |
143 | return value; |
144 | } |
145 | |
146 | private double evaluateMeasurement(String name) { |
147 | double result = 0; |
148 | |
149 | if (name.length() != 0) { |
150 | int dispose; |
151 | |
152 | synchronized (perl()) { |
153 | if (perl().match("/(.*)\\s+(dispose_\\w+)$/i", name)) { |
154 | name = perl().group(1); |
155 | |
156 | String disposeText = perl().group(2); |
157 | |
158 | if (disposeText.equalsIgnoreCase("DISPOSE_IGNORE")) { |
159 | dispose = StatisticalMeasurement.DISPOSE_IGNORE; |
160 | } else if (disposeText.equalsIgnoreCase("DISPOSE_MINIMUM")) { |
161 | dispose = StatisticalMeasurement.DISPOSE_MINIMUM; |
162 | } else if (disposeText.equalsIgnoreCase("DISPOSE_MEDIAN")) { |
163 | dispose = StatisticalMeasurement.DISPOSE_MEDIAN; |
164 | } else if (disposeText.equalsIgnoreCase("DISPOSE_AVERAGE")) { |
165 | dispose = StatisticalMeasurement.DISPOSE_AVERAGE; |
166 | } else if (disposeText.equalsIgnoreCase("DISPOSE_STANDARD_DEVIATION")) { |
167 | dispose = StatisticalMeasurement.DISPOSE_STANDARD_DEVIATION; |
168 | } else if (disposeText.equalsIgnoreCase("DISPOSE_MAXIMUM")) { |
169 | dispose = StatisticalMeasurement.DISPOSE_MAXIMUM; |
170 | } else if (disposeText.equalsIgnoreCase("DISPOSE_SUM")) { |
171 | dispose = StatisticalMeasurement.DISPOSE_SUM; |
172 | } else if (disposeText.equalsIgnoreCase("DISPOSE_NB_DATA_POINTS")) { |
173 | dispose = StatisticalMeasurement.DISPOSE_NB_DATA_POINTS; |
174 | } else { |
175 | dispose = StatisticalMeasurement.DISPOSE_IGNORE; |
176 | } |
177 | } else { |
178 | dispose = StatisticalMeasurement.DISPOSE_IGNORE; |
179 | } |
180 | } |
181 | |
182 | Measurement measurement = getContext().getMeasurement(name); |
183 | |
184 | if (measurement instanceof StatisticalMeasurement) { |
185 | StatisticalMeasurement stats = (StatisticalMeasurement) measurement; |
186 | |
187 | switch (dispose) { |
188 | case StatisticalMeasurement.DISPOSE_MINIMUM: |
189 | result = stats.getMinimum(); |
190 | break; |
191 | case StatisticalMeasurement.DISPOSE_MEDIAN: |
192 | result = stats.getMedian(); |
193 | break; |
194 | case StatisticalMeasurement.DISPOSE_AVERAGE: |
195 | result = stats.getAverage(); |
196 | break; |
197 | case StatisticalMeasurement.DISPOSE_STANDARD_DEVIATION: |
198 | result = stats.getStandardDeviation(); |
199 | break; |
200 | case StatisticalMeasurement.DISPOSE_MAXIMUM: |
201 | result = stats.getMaximum(); |
202 | break; |
203 | case StatisticalMeasurement.DISPOSE_SUM: |
204 | result = stats.getSum(); |
205 | break; |
206 | case StatisticalMeasurement.DISPOSE_NB_DATA_POINTS: |
207 | result = stats.getNbDataPoints(); |
208 | break; |
209 | case StatisticalMeasurement.DISPOSE_IGNORE: |
210 | default: |
211 | result = stats.getValue().doubleValue(); |
212 | break; |
213 | } |
214 | } else { |
215 | result = measurement.getValue().doubleValue(); |
216 | } |
217 | |
218 | if (super.isEmpty()) { |
219 | setEmpty(measurement.isEmpty()); |
220 | } |
221 | } |
222 | |
223 | return result; |
224 | } |
225 | } |