View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.search.aggregator;
18  
19  import net.sf.ehcache.search.Attribute;
20  
21  /***
22   * Compute the average (arithmetic mean) as a double
23   *
24   * @author teck
25   */
26  public class Average implements AggregatorInstance<Double> {
27  
28      private final Attribute<?> attribute;
29  
30      private Engine engine;
31  
32      /***
33       * @param attribute
34       */
35      public Average(Attribute<?> attribute) {
36          this.attribute = attribute;
37      }
38  
39      /***
40       * {@inheritDoc}
41       * <p/>
42       * NOTE: Null values are ignored and not included in the computation
43       */
44      public void accept(Object input) throws AggregatorException {
45          if (input == null) {
46              return;
47          }
48  
49          if (input instanceof Number) {
50              if (engine == null) {
51                  engine = Engine.create((Number) input);
52              } else {
53                  engine.accept((Number) input);
54              }
55          } else {
56              throw new AggregatorException("Non-number type encounted: " + input.getClass());
57          }
58      }
59  
60      /***
61       * {@inheritDoc}
62       * <p/>
63       * NOTE: null is returned if there was no input supplied to this function
64       */
65      public Number aggregateResult() {
66          if (engine == null) {
67              return null;
68          } else {
69              return engine.result();
70          }
71      }
72  
73      /***
74       * {@inheritDoc}
75       */
76      public Attribute getAttribute() {
77          return attribute;
78      }
79  
80      /***
81       * Abstract super-class for all average calculating engines.
82       */
83      abstract static class Engine {
84  
85          /***
86           * Create a type specific engine using the given initial value.
87           *
88           * @param value initial value
89           * @return type specific engine
90           */
91          static Engine create(Number value) {
92              if (value instanceof Float) {
93                  return new FloatEngine(value.floatValue());
94              } else if (value instanceof Double) {
95                  return new DoubleEngine(value.doubleValue());
96              } else if (value instanceof Long) {
97                  return new LongEngine(value.longValue());
98              } else {
99                  return new IntegerEngine(value.intValue());
100             }
101         }
102 
103         /***
104          * Update the engine with the given value.
105          *
106          * @param input data value
107          */
108         abstract void accept(Number input) throws AggregatorException;
109 
110         /***
111          * Get the (current) result of this engine.
112          *
113          * @return engine result
114          */
115         abstract Number result();
116 
117         /***
118          * An int based averaging engine.
119          */
120         static class IntegerEngine extends Engine {
121 
122             private int count;
123             private long sum;
124 
125             /***
126              * Creates a new instance starting with an initial value
127              *
128              * @param value initial value
129              */
130             IntegerEngine(int value) {
131                 this.count = 1;
132                 this.sum = value;
133             }
134 
135             @Override
136             void accept(Number input) throws AggregatorException {
137                 count++;
138                 sum += input.intValue();
139             }
140 
141             @Override
142             Number result() {
143                 return Float.valueOf(((float) sum) / count);
144             }
145         }
146 
147         /***
148          * A long based averaging engine.
149          */
150         static class LongEngine extends Engine {
151 
152             private int count;
153             private long sum;
154 
155             /***
156              * Creates a new instance starting with an initial value
157              *
158              * @param value initial value
159              */
160             LongEngine(long value) {
161                 this.count = 1;
162                 this.sum = value;
163             }
164 
165             @Override
166             void accept(Number input) throws AggregatorException {
167                 count++;
168                 sum += input.longValue();
169             }
170 
171             @Override
172             Number result() {
173                 return Double.valueOf(((double) sum) / count);
174             }
175         }
176 
177         /***
178          * A float based averaging engine.
179          */
180         static class FloatEngine extends Engine {
181 
182             private int count;
183             private float sum;
184 
185             /***
186              * Creates a new instance starting with an initial value
187              *
188              * @param value initial value
189              */
190             FloatEngine(float value) {
191                 this.count = 1;
192                 this.sum = value;
193             }
194 
195             @Override
196             void accept(Number input) throws AggregatorException {
197                 count++;
198                 sum += input.floatValue();
199             }
200 
201             @Override
202             Number result() {
203                 return Float.valueOf(sum / count);
204             }
205         }
206 
207         /***
208          * A double based averaging engine.
209          */
210         static class DoubleEngine extends Engine {
211 
212             private int count;
213             private double sum;
214 
215             /***
216              * Creates a new instance starting with an initial value
217              *
218              * @param value initial value
219              */
220             DoubleEngine(double value) {
221                 this.count = 1;
222                 this.sum = value;
223             }
224 
225             @Override
226             void accept(Number input) throws AggregatorException {
227                 count++;
228                 sum += input.doubleValue();
229             }
230 
231             @Override
232             Number result() {
233                 return Double.valueOf(sum / count);
234             }
235         }
236     }
237 }