commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From simonetrip...@apache.org
Subject svn commit: r1344757 [1/4] - in /commons/proper/functor/trunk: ./ src/changes/ src/main/java/org/apache/commons/functor/aggregator/ src/main/java/org/apache/commons/functor/aggregator/functions/ src/site/xdoc/ src/test/java/org/apache/commons/functor/a...
Date Thu, 31 May 2012 14:56:50 GMT
Author: simonetripodi
Date: Thu May 31 14:56:47 2012
New Revision: 1344757

URL: http://svn.apache.org/viewvc?rev=1344757&view=rev
Log:
[FUNCTOR-1] New components: summarize and aggregate - patch contributed by Liviu Tudor

Added:
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java   (with props)
    commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java   (with props)
    commons/proper/functor/trunk/src/site/xdoc/aggregate.xml   (with props)
    commons/proper/functor/trunk/src/site/xdoc/aggregator.xml   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregatorTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregatorTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/AbstractTimedAggregatorTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregatorTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntCountAggregatorBinaryFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntMaxAggregatorBinaryFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntMaxAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntMeanValueAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntMedianValueAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntPercentileAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntSumAggregatorBinaryFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/aggregator/functions/IntSumAggregatorFunctionTest.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/list/
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/list/OwnFunctionImplementationSample.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/list/OwnListImplementationSample.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/list/package-info.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/nostore/
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/nostore/AggregatedFunctionSample.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/nostore/NoStoreAggregatorSample.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/nostore/package-info.java   (with props)
    commons/proper/functor/trunk/src/test/java/org/apache/commons/functor/example/aggregator/package-info.java   (with props)
Modified:
    commons/proper/functor/trunk/pom.xml
    commons/proper/functor/trunk/src/changes/changes.xml
    commons/proper/functor/trunk/src/site/xdoc/examples.xml

Modified: commons/proper/functor/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/pom.xml?rev=1344757&r1=1344756&r2=1344757&view=diff
==============================================================================
--- commons/proper/functor/trunk/pom.xml (original)
+++ commons/proper/functor/trunk/pom.xml Thu May 31 14:56:47 2012
@@ -85,6 +85,10 @@
      <name>Bruno P. Kinoshita</name>
      <email>brunodepaulak at yahoo dot com dot br</email>
    </contributor>
+   <contributor>
+     <name>Liviu Tudor</name>
+     <email>me AT liviutudor DOT com</email>
+   </contributor>
   </contributors>
 
   <dependencies>

Modified: commons/proper/functor/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/changes/changes.xml?rev=1344757&r1=1344756&r2=1344757&view=diff
==============================================================================
--- commons/proper/functor/trunk/src/changes/changes.xml (original)
+++ commons/proper/functor/trunk/src/changes/changes.xml Thu May 31 14:56:47 2012
@@ -29,6 +29,9 @@
       <action dev="simonetripodi" issue="FUNCTOR-2">
         Improve Functor web page, removing Ant from building (Contributed by Bruno P. Kinoshita)
       </action>
+      <action dev="simonetripodi" issue="FUNCTOR-1" due-to="Liviu Tudor">
+        New components: summarize and aggregate
+      </action>
     </release>
   </body>
 </document>

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java Thu May 31 14:56:47 2012
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator;
+
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * An aggregator which stores the data series in a List. Every call to
+ * {@link #add(Object)} will add an item in the array and there is no limit to
+ * how much data we can store. It is down to subclasses to decide which types of
+ * List implementation they need to used -- and the abstract factory
+ * {@link #createList()} is provided for this.
+ * <p>This implementation also allows for various "aggregations" of the list to be
+ * used by providing a {@link UnaryFunction UnaryFunction<List<T>, T>} in the
+ * constructor.</p>
+ * <p>
+ * <b>Thread safety</b> : Note that due to the fact that
+ * {@link AbstractTimedAggregator} provides a threadsafe environment for access
+ * to data, the <code>List</code> implementation can be unsynchronized.
+ * </p>
+ *
+ * @param <T>
+ *            Type of object stored.
+ * @see AbstractTimedAggregator
+ */
+public abstract class AbstractListBackedAggregator<T> extends AbstractTimedAggregator<T> {
+    /**
+     * Stores the data series we ought to aggregate/evaluate. This list can only
+     * be modified via {@link #reset()} and {@link #add(Object)} and will be
+     * traversed during {@link #evaluate()}.
+     */
+    private List<T>                   series;
+
+    /**
+     * Used to actually aggregate the data when {@link #evaluate()} is called.
+     * This is set in {@link #AbstractListBackedAggregator() the constructor}.
+     */
+    private UnaryFunction<List<T>, T> aggregationFunction;
+
+    /**
+     * Default constructor. Similar to
+     * {@link #AbstractListBackedAggregator(UnaryFunction, long)
+     * AbstractListBackedAggregator(aggregationFunction,0L}.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #evaluate()}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     */
+    public AbstractListBackedAggregator(UnaryFunction<List<T>, T> aggregationFunction) {
+        this(aggregationFunction, 0L);
+    }
+
+    /**
+     * Similar to
+     * {@link #AbstractListBackedAggregator(UnaryFunction, long, boolean)
+     * AbstractListBackedAggregator(aggregationFunction,interval,false}.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #evaluate()}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @param interval
+     *            interval in miliseconds to reset this aggregator
+     */
+    public AbstractListBackedAggregator(UnaryFunction<List<T>, T> aggregationFunction, long interval) {
+        this(aggregationFunction, interval, false);
+    }
+
+    /**
+     * Constructs an aggregator which will use the given function, reset itself
+     * at the given interval and will use a shared timer on own private timer.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #evaluate()}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @param interval
+     *            interval in miliseconds to reset this aggregator
+     * @param useSharedTimer
+     *            if set to true, it will use a shared timer, as per
+     *            {@link AbstractTimedAggregator#AbstractTimedAggregator(long, boolean)}
+     *            ; otherwise if it's false it will use its own timer instance
+     * @see AbstractTimedAggregator#AbstractTimedAggregator(long, boolean)
+     */
+    public AbstractListBackedAggregator(UnaryFunction<List<T>, T> aggregationFunction, long interval,
+            boolean useSharedTimer) {
+        super(interval, useSharedTimer);
+        if (aggregationFunction == null) {
+            throw new NullPointerException("no function specified for aggregation");
+        }
+        this.aggregationFunction = aggregationFunction;
+        this.series = createList();
+    }
+
+    /**
+     * Adds data to the series which will be aggregated. This implementation
+     * simply adds the data to the {@link #series} list.
+     *
+     * @param data
+     *            Data to be added to the data series.
+     */
+    @Override
+    public final void doAdd(T data) {
+        series.add(data);
+    }
+
+    /**
+     * The actual "beef" of this class: iterate through the list and aggregates
+     * all the data and evaluates the result. This is done by calling
+     * <code>aggregationFunction.evaluate(series)</code>.
+     *
+     * @return the result of <code>aggregationFunction.evaluate(series)</code>
+     * @see Aggregator#evaluate()
+     */
+    @Override
+    protected final T doEvaluate() {
+        return aggregationFunction.evaluate(series);
+    }
+
+    /**
+     * Resets the data series to the empty state.
+     */
+    @Override
+    protected final void doReset() {
+        series.clear();
+    }
+
+    /**
+     * Allows subclasses to create the list which will store the {@link #series
+     * data series}.
+     *
+     * @return an instance of <code>List</code> which will be used to store the
+     *         data.
+     */
+    protected abstract List<T> createList();
+
+    /**
+     * Getter for {@link #series}.
+     *
+     * @return Value of {@link #series}
+     */
+    protected final List<T> getSeries() {
+        return series;
+    }
+
+    /**
+     * Simply returns the size of the data series which is the size of the list
+     * used internally.
+     *
+     * @return Size of {@link #series} -- equivalent to
+     *         <code>series.size()</code>
+     */
+    @Override
+    protected final int retrieveDataSize() {
+        return series.size();
+    }
+
+    /**
+     * Getter for {@link #aggregationFunction}. Provided for testing purposes
+     * only.
+     *
+     * @return Current value of {@link #aggregationFunction}
+     */
+    final UnaryFunction<List<T>, T> getAggregationFunction() {
+        return aggregationFunction;
+    }
+
+    @Override
+    public String toString() {
+        return AbstractListBackedAggregator.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractListBackedAggregator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java Thu May 31 14:56:47 2012
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator;
+
+import org.apache.commons.functor.BinaryFunction;
+
+/**
+ * An implementation of an aggregator which doesn't store the data series but
+ * instead it processes the data on the fly, as it arrives in
+ * {@link #add(Object)} and stores the result after each addition. It processes
+ * the data by using a {@link BinaryFunction} which takes the result of the
+ * previous {@link #add(Object)} and the data passed in and returns a new result
+ * which gets stored (for using again in the next call to {@link #add(Object)}.
+ * The call to {@link #evaluate()} simply returns this stored value at any
+ * point. This has a lower memory footprint compared to
+ * {@link AbstractListBackedAggregator} however it only allows for simpler
+ * processing on the data received.
+ *
+ * @param <T>
+ *            Type of object stored.
+ */
+public abstract class AbstractNoStoreAggregator<T> extends AbstractTimedAggregator<T> {
+    /**
+     * Function used to aggregate the data on the fly in {@link #add(Object)}.
+     *
+     * @see #add(Object)
+     * @see #AbstractNoStoreAggregator(BinaryFunction)
+     */
+    private BinaryFunction<T, T, T> aggregationFunction;
+
+    /**
+     * Stores the result of the last {@link #add(Object)} operation.
+     *
+     * @see #add(Object)
+     */
+    private T                       result;
+
+    /**
+     * Similar to {@link #AbstractNoStoreAggregator(BinaryFunction, long)
+     * AbstractNoStoreAggregator(aggregationFunction,0L)}.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #add(Object)}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @see #add(Object)
+     * @see #aggregationFunction
+     */
+    public AbstractNoStoreAggregator(BinaryFunction<T, T, T> aggregationFunction) {
+        this(aggregationFunction, 0L);
+    }
+
+    /**
+     * Similar to
+     * {@link #AbstractNoStoreAggregator(BinaryFunction, long,boolean)
+     * AbstractNoStoreAggregator(aggregationFunction,0L,false)}.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #add(Object)}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @param interval
+     *            interval in miliseconds to reset this aggregator
+     * @see #add(Object)
+     * @see #aggregationFunction
+     */
+    public AbstractNoStoreAggregator(BinaryFunction<T, T, T> aggregationFunction, long interval) {
+        this(aggregationFunction, interval, false);
+    }
+
+    /**
+     * Constructs an aggregator which will use the given function, reset itself
+     * at the given interval and will use a shared timer on own private timer.
+     * Simply prepares an aggregator which will use the given aggregation
+     * function each time {@link #add(Object)} is called. Also it initializes
+     * {@link #result} with the value returned by {@link #initialValue()}, thus
+     * allowing subclasses to have a custom way of specifying the start value.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #add(Object)}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @param interval
+     *            interval in miliseconds to reset this aggregator
+     * @param useSharedTimer
+     *            if set to true, it will use a shared timer, as per
+     *            {@link AbstractTimedAggregator#AbstractTimedAggregator(long, boolean)}
+     *            ; otherwise if it's false it will use its own timer instance
+     * @see AbstractTimedAggregator#AbstractTimedAggregator(long, boolean)
+     */
+    public AbstractNoStoreAggregator(BinaryFunction<T, T, T> aggregationFunction, long interval,
+            boolean useSharedTimer) {
+        super(interval, useSharedTimer);
+        this.aggregationFunction = aggregationFunction;
+        result = initialValue();
+    }
+
+    /**
+     * Receives data to be aggregated/processed on the fly. This implementation
+     * simply calls {@link #aggregationFunction} and stores the result.
+     *
+     * @param data
+     *            Data to aggregate
+     */
+    @Override
+    protected final void doAdd(T data) {
+        result = aggregationFunction.evaluate(result, data);
+    }
+
+    /**
+     * Returns the value already computed and stored in {@link #result}.
+     *
+     * @return Current (aggregated) value stored in {@link #result}
+     * @see Aggregator#evaluate()
+     */
+    @Override
+    protected final T doEvaluate() {
+        return result;
+    }
+
+    /**
+     * Resets the {@link #result} member to the {@link #initialValue()}.
+     *
+     * @see #initialValue()
+     */
+    @Override
+    protected final void doReset() {
+        result = initialValue();
+    }
+
+    /**
+     * Allows subclasses to define the "initial" value. This value will be
+     * stored in {@link #result} when an instance of this class is created or
+     * when {@link #reset()} is called.
+     *
+     * @return Initial value to be used in {@link #result}.
+     */
+    protected abstract T initialValue();
+
+    /**
+     * Getter for {@link #aggregationFunction}.
+     *
+     * @return Current value of the member.
+     */
+    final BinaryFunction<T, T, T> getAggregationFunction() {
+        return aggregationFunction;
+    }
+
+    /**
+     * Getter for {@link #result}. Provided for test purposes only.
+     *
+     * @return Current value of the aggregated data.
+     */
+    final T getResult() {
+        return result;
+    }
+
+    /**
+     * Setter for {@link #result}. Provided for test purposes only.
+     *
+     * @param result
+     *            New value to store in {@link #result}
+     */
+    final void setResult(T result) {
+        this.result = result;
+    }
+
+    /**
+     * This aggregator doesn't store any data, so the data series size is always
+     * 0 (zero).
+     *
+     * @return 0
+     */
+    @Override
+    protected int retrieveDataSize() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return AbstractNoStoreAggregator.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractNoStoreAggregator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java Thu May 31 14:56:47 2012
@@ -0,0 +1,489 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * An aggregator which automatically resets the aggregated data at regular
+ * intervals and sends a notification when it is about to do so, so listeners
+ * can decide to gather the information before it is being reset (and log it
+ * etc). This allows for smaller memory footprints for instance in the case of
+ * List-based aggregators, as regularly the list is emptied. Also it allows for
+ * the call to <code>evaluate</code> to represent an "aggregated" value over a
+ * certain period of time. Note that you can still have a regular aggregator
+ * extending this class by specifying an interval less than or equal to zero.
+ * The regular flush/reset will be triggered from a timer which will always be
+ * started as a daemon thread (so it will stop when there are no more non-daemon
+ * threads in the JVM); this class allows 2 types of timers:
+ * <ul>
+ * <li>(default) per instance <code>Timer</code> -- each instance of this class
+ * will create a new <code>Timer</code> and this <code>Timer</code> will have a
+ * single <code>TimerTask</code> scheduled, which is the one that resets this
+ * <code>Aggregator</code> regularly and sends notifications. This way, when the
+ * <code>Aggregator</code> instance is destroyed, the <code>Timer</code> goes as
+ * well.</li>
+ * <li>shared <code>Timer</code> instance -- this class will create a static
+ * instance of <code>Timer</code> which can be shared by other instances of this
+ * class. While this is a bit more effective from a memory and thread management
+ * point of view, it has the downside that if the <code>TimerTask</code>'s are
+ * not managed properly this can create memory leaks. So if you decide to take
+ * this route make sure when you are finished with this instance, to always stop
+ * the timer at the end.</li>
+ * </ul>
+ * <p>
+ * <b>Synchronization</b>: This class provides a thread safe framework so when
+ * {@link #doAdd(Object)}, {@link #reset()} and {@link #evaluate()} is called,
+ * access is synchronized via a read-write lock. {@link #evaluate()} is
+ * considered a read operation and {@link #doAdd(Object)} and {@link #reset()}
+ * are considered write operations.
+ * </p>
+ *
+ * @param <T>
+ *            type of data to aggregate
+ */
+public abstract class AbstractTimedAggregator<T> implements Aggregator<T> {
+    /**
+     * Stores a list to all objects which are listening for time events
+     * generated by this object. If there is no timer programmed (e.g.
+     * {@link #interval} is set to 0) this list will be <code>null</code>. Under
+     * the cover, this will use a <code>CopyOnWriteArrayList</code> since there
+     * aren't too many updates expected to this list.
+     *
+     * @see #interval
+     * @see #timer
+     * @see TimedAggregatorListener
+     */
+    private List<TimedAggregatorListener<T>> timerListeners;
+
+    /**
+     * As per {@link #timer} javadoc, if the interval specified is zero or less
+     * there will be no <code>Timer</code> created/assigned to this instance.
+     * This constant is defined to make it easier to read code which creates
+     * instances of this class and doesn't assign them a timer.
+     */
+    public static final long                 NO_TIMER   = 0L;
+
+    /**
+     * Name of the shared timer which will run all the TimerTasks resulted from
+     * creating instances of this class which are set to used the shared timer.
+     * This is useful when looking at thread dumps. For instances which use
+     * their own timer task, the name will be
+     * <code>TIMER_NAME + hashCode()</code>.
+     */
+    public static final String               TIMER_NAME = "TimedSummarizerMainTimer";
+
+    /**
+     * The main shared timer which will execute all the <code>TimerTasks</code>
+     * resulted from instances of this class which chose to use the shared
+     * timer. Note that this <code>Timer</code> is started as a daemon thread so
+     * it will stop when there are no more non-daemon threads.
+     *
+     * @see #timer
+     */
+    private static final Timer               MAIN_TIMER = new Timer(TIMER_NAME, true);
+
+    /**
+     * The timer instance for this instance. Can point to {@link #MAIN_TIMER} if
+     * shared timer was chosen in constructor or a newly created instance of
+     * <code>Timer</code> which is private to this instance only.
+     *
+     * @see #MAIN_TIMER
+     */
+    private Timer                            timer;
+
+    /**
+     * Interval in milliseconds we flush the result of the "summary". This will
+     * be used to set up our <code>TimerTask</code> and schedule it with the
+     * <code>Timer</code>. Every time the timer kicks in after this interval, it
+     * will call {@link #timer()}. If this is set to a value of zero or less, no
+     * timer will be created.
+     */
+    private long                             interval;
+
+    /**
+     * This is the task that is created when a new instance of this class is
+     * created. Once created this task will be scheduled with the {@link #timer}
+     * . Calling {@link #stop()} cancels this task and also will set it to null
+     * (so it can be recycled by the garbage collection), otherwise, until that
+     * point this will store a reference to a valid <code>TimerTask</code>
+     * instance.
+     */
+    private TimerTask                        task;
+
+    /**
+     * Lock used internally to synchronize access to {@link #add(Object)},
+     * {@link #reset()} and {@link #evaluate()}. Locks for writing when
+     * {@link #add(Object)} and {@link #reset()} is called and for reading when
+     * {@link #evaluate()} is called.
+     *
+     * @see #add(Object)
+     * @see #evaluate()
+     * @see #reset()
+     */
+    private ReadWriteLock                    dataLock;
+
+    /**
+     * Default constructor -- creates an instance of this aggregator with no
+     * <code>Timer</code>. Equivalent to
+     * <code>AbstractTimedAggregator(NO_TIMER)</code>.
+     *
+     * @see #AbstractTimedAggregator(long)
+     */
+    public AbstractTimedAggregator() {
+        this(NO_TIMER);
+    }
+
+    /**
+     * Creates an aggregator which has a timer at the specified interval
+     * (miliseconds) and uses its own timer rather than the shared
+     * {@link #MAIN_TIMER}. Equivalent to
+     * <code>AbstractTimedAggregator(interval,false)</code>.
+     *
+     * @param interval
+     *            interval in miliseconds to set the timer for.
+     * @see #interval
+     * @see #timer
+     * @see #AbstractTimedAggregator(long, boolean)
+     */
+    public AbstractTimedAggregator(long interval) {
+        this(interval, false);
+    }
+
+    /**
+     * Creates an aggregator which has a timer at the specified interval and
+     * also allows control over using the {@link #MAIN_TIMER shared timer} or
+     * its own per-instance timer.
+     *
+     * @param interval
+     *            interval in miliseconds to set the timer for.
+     * @param useSharedTimer
+     *            if set to <code>true</code>, {@link #timer} will be set to
+     *            {@link #TIMER_NAME}, otherwise a new instance of
+     *            <code>Timer</code> will be created.
+     */
+    public AbstractTimedAggregator(long interval, boolean useSharedTimer) {
+        if (interval <= NO_TIMER) {
+            // not using timer
+            this.interval = NO_TIMER;
+            this.timer = null;
+            this.task = null;
+            this.timerListeners = null;
+        } else {
+            // we have been requested to use timers
+            this.interval = interval;
+            this.timerListeners = new CopyOnWriteArrayList<TimedAggregatorListener<T>>();
+            if (useSharedTimer) {
+                this.timer = MAIN_TIMER;
+            } else {
+                this.timer = new Timer(TIMER_NAME + hashCode(), true);
+            }
+            // having set up the timer, create the task
+            this.task = new TimerTask() {
+                @Override
+                public void run() {
+                    timer();
+                }
+            };
+            this.timer.scheduleAtFixedRate(this.task, this.interval, this.interval);
+        }
+        this.dataLock = new ReentrantReadWriteLock();
+    }
+
+    /**
+     * Getter for {@link #interval}.
+     *
+     * @return Current value of {@link #interval}.
+     */
+    public final long getInterval() {
+        return interval;
+    }
+
+    /**
+     * Adds the data to this aggregator. This function first locks
+     * {@link #dataLock} for writing then calls {@link #doAdd(Object)}, which
+     * allows subclasses to perform the actual adding to the aggregator and then
+     * at the end it unlocks {@link #dataLock}.
+     *
+     * @param data
+     *            Data to be added to the aggregator.
+     * @see #doAdd(Object)
+     * @see #dataLock
+     */
+    public final void add(T data) {
+        dataLock.writeLock().lock();
+        try {
+            doAdd(data);
+        } finally {
+            dataLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Function provided to allow subclasses to perform the actual adding of the
+     * data to the aggregator. This function is wrapped by {@link #add(Object)}
+     * so that access to any internal data series (implemented by subclasses)
+     * via {@link #add(Object)} or {@link #evaluate()} or {@link #reset()} is
+     * prohibited during this call, as a <b>write</b> lock is acquired prior to
+     * this function call to ensure this function is the only one which has
+     * access to the data.
+     *
+     * @param data
+     *            Data to be aggregated
+     * @see #add(Object)
+     */
+    protected abstract void doAdd(T data);
+
+    /**
+     * Aggregates all the data this object has been "fed" via calls to
+     * {@link #add(Object)}. Note that this object delegates the call to
+     * {@link #doEvaluate()} after it secured read-only access to
+     * {@link #dataLock} -- so any data series access can be safely read
+     * (however, subclasses should NOT try to modify any data series they might
+     * implement at this point!). The lock is released after
+     * {@link #doEvaluate()} returns.
+     *
+     * @return result of aggregating the data, as returned by
+     *         {@link #doEvaluate()}
+     * @see #doEvaluate()
+     */
+    public final T evaluate() {
+        dataLock.readLock().lock();
+        try {
+            return doEvaluate();
+        } finally {
+            dataLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Allows subclasses to perform the actual evaluation of the aggregated
+     * result in a thread-safe manner. When this function is called,
+     * <b>write</b> access to data (via {@link #add(Object)} and
+     * {@link #reset()}) is prohibited until this function finishes. However,
+     * please note that other read access (via calls to the same
+     * {@link #evaluate()}) is possible.
+     *
+     * @return Result of evaluating the aggregated data
+     */
+    protected abstract T doEvaluate();
+
+    /**
+     * Resets this aggregator.This function first locks {@link #dataLock} for
+     * writing then calls {@link #doReset()}, which allows subclasses to perform
+     * the actual resetting of the aggregator and then at the end it unlocks
+     * {@link #dataLock}.
+     *
+     * @see #doReset()
+     */
+    public final void reset() {
+        dataLock.writeLock().lock();
+        try {
+            doReset();
+        } finally {
+            dataLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Function provided to allow subclasses to perform the actual reset of the
+     * aggregator. This function is wrapped by {@link #reset()} so that access
+     * to data (via {@link #add(Object)} or {@link #evaluate()} or
+     * {@link #reset()}) is prohibited during this call, as a <b>write</b> lock
+     * is acquired prior to this function call to ensure this function is the
+     * only one which has access to the data.
+     */
+    protected abstract void doReset();
+
+    /**
+     * Retrieves the size of the currently-stored data series. This function
+     * first locks {@link #dataLock} for reading then calls
+     * {@link #retrieveDataSize()}, which allows subclasses to compute the data
+     * series size and then at the end it unlocks {@link #dataLock}.
+     *
+     * @return Size of the current data series, which will be aggregated at the
+     *         next call to {@link #evaluate()}
+     */
+    public final int getDataSize() {
+        dataLock.readLock().lock();
+        try {
+            return retrieveDataSize();
+        } finally {
+            dataLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Function provided to allow subclasses to retrieve the actual size of the
+     * data series. This function is wrapped by {@link #getDataSize()} so that
+     * access to data (via {@link #add(Object)} or {@link #reset()}) is
+     * prohibited during this call, as a <b>read</b> lock is acquired prior to
+     * this function call. (However, calls to {@link #evaluate()} are allowed as
+     * that locks for reading too.)
+     *
+     * @return Size of the current data series. Zero means no data stored.
+     */
+    protected abstract int retrieveDataSize();
+
+    /**
+     * Retrieves <b>an unmodifiable copy</b> of the {@link #timerListeners timer
+     * listeners}. Used for testing.
+     *
+     * @return <code>Collections.unmodifiableList(timerListeners)</code> if
+     *         {@link #timerListeners} is <b>not</b> <code>null</code>, or
+     *         <code>null</code> otherwise.
+     */
+    final List<TimedAggregatorListener<T>> getTimerListeners() {
+        if (timerListeners == null) {
+            return null;
+        }
+        return Collections.unmodifiableList(timerListeners);
+    }
+
+    /**
+     * If this <code>Aggregator</code> has been started with timer support, it
+     * will add the given listener, so it receives
+     * {@link TimedAggregatorListener#onTimer(AbstractTimedAggregator,Object)
+     * timer events}. If no timer support has been configured for this
+     * Aggregator, this call has no effect.
+     *
+     * @param listener
+     *            Listener to be added to received timer events from this
+     *            aggregator.
+     * @see #timerListeners
+     */
+    public final void addTimerListener(TimedAggregatorListener<T> listener) {
+        if (timerListeners == null) {
+            return;
+        }
+        timerListeners.add(listener);
+    }
+
+    /**
+     * Removes a listener from the timer listeners list if previously added. If
+     * this Aggregator has been configured with no timer support, this call will
+     * always return <code>false</code>.
+     *
+     * @param listener
+     *            Listener to be removed from the list. NullPointerException
+     *            thrown if this is null.
+     * @return <code>true</code> if this Aggregator has timer support and the
+     *         listener passed in was previously added (via
+     *         {@link #addTimerListener(TimedAggregatorListener)}) or false if
+     *         either the Aggregator has no timer support or it has timer
+     *         support but the listener was never registered with this
+     *         Aggregator.
+     * @see #timerListeners
+     */
+    public final boolean removeTimerListener(TimedAggregatorListener<T> listener) {
+        if (timerListeners == null) {
+            return false;
+        }
+        return timerListeners.remove(listener);
+    }
+
+    /**
+     * Computes the current aggregated value (by calling {@link #evaluate()},
+     * resets this aggregator then notifies all listeners. Go through all the
+     * {@link #timerListeners} and sends
+     * {@link TimedAggregatorListener#onTimer(AbstractTimedAggregator,Object)
+     * notification messages} to each of them. Does nothing if
+     * {@link #timerListeners} is <code>null</code>. Please note that
+     * {@link #evaluate()} is called only once at the beginning of this
+     * function, and only if there are listeners configured, then this value is
+     * passed to every notification. This is in order to ensure all listeners
+     * receive the same value -- the value of the evaluation prior to resetting
+     * it.
+     */
+    private void timer() {
+        if (timerListeners != null) {
+            // if we have listeners, notify them
+            T aggregated = evaluate(); // NOTE: shouldn't evaluate() and reset()
+                                       // be done atomically here?
+            reset();
+            for (TimedAggregatorListener<T> i : timerListeners) {
+                i.onTimer(this, aggregated);
+            }
+        } else {
+            reset();
+        }
+    }
+
+    /**
+     * Checks whether this instance has a timer associated with it or not. If
+     * there is a timer for this Aggregator, then the {@link #task} member
+     * should be set to a non-null value.
+     *
+     * @return <code>true</code> if {@link #task} is not null,
+     *         <code>false</code> otherwise (in which case there is no timer).
+     */
+    public final boolean isTimerEnabled() {
+        return (task != null);
+    }
+
+    /**
+     * Checks whether this instance uses its own timer or {@link #MAIN_TIMER the
+     * shared timer} for scheduling {@link #task the timer task}.
+     *
+     * @return <code>true</code> if <code>timer == MAIN_TIMER</code> or
+     *         <code>false</code> otherwise.
+     */
+    public final boolean isSharedTimer() {
+        return (timer == MAIN_TIMER);
+    }
+
+    /**
+     * Cancels the current timer task (if set) -- which means from there on the
+     * data will not be reset anymore. Also, if {@link #timer} is not set to
+     * {@link #MAIN_TIMER the shared timer} then it will be cancelled as well
+     * Also releases all the listeners from the {@link #timerListeners list}.
+     */
+    public final void stop() {
+        // cancel the task first
+        if (task != null) {
+            task.cancel();
+            task = null;
+            timer.purge(); // remove the reference to this task
+        }
+        // then the timer if needed
+        if (timer != null && timer != MAIN_TIMER) {
+            timer.cancel();
+        }
+        timer = null;
+        // finally remove the elements from the listeners list
+        if (timerListeners != null) {
+            timerListeners.clear();
+        }
+    }
+
+    @Override
+    protected final void finalize() throws Throwable {
+        // if we're going in the garbage, make sure we clean up
+        stop();
+    }
+
+    @Override
+    public String toString() {
+        return AbstractTimedAggregator.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/AbstractTimedAggregator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java Thu May 31 14:56:47 2012
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator;
+
+import org.apache.commons.functor.Function;
+
+/**
+ * Interface which offers a means of "aggregating" data. It offers functions
+ * which allows for data to be added to a "series" and then aggregate them. The
+ * term "aggregation" is possibly a bit loose here as this interface doesn't
+ * enforce summing up or averaging or any other way of processing the data -- it
+ * simply allows for the values to be processed in such a way that it generates
+ * a result. The aggregation of data will be done in the <code>evaluate()</code>
+ * function. This is the function at the core of the aggregator package as it
+ * allows for a way to process the data series and get a result of the same type
+ * out of this operation. Note that some aggregators will compute the data at
+ * this point by iterating through the series of data previously stored (if any)
+ * while others might prefer to compute this value on the fly, every time
+ * {@link #add(Object)} is called. This interface doesn't make any assumption as
+ * to when the aggregation result should be computed.
+ *
+ * @param <T>
+ *            type of data to aggregate
+ */
+public interface Aggregator<T> extends Function<T> {
+    /**
+     * Adds data to the series which will be aggregated. It doesn't enforce any
+     * limitations on how much data can be stored (or in fact whether it should
+     * be stored) nor does it make any assumptions on synchronization.
+     *
+     * @param data
+     *            Data to be added to the series which this aggregator will
+     *            process/aggregate.
+     */
+    void add(T data);
+
+    /**
+     * Resets any series of data previously stored and returns the aggregator in
+     * the initial state.
+     */
+    void reset();
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/Aggregator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java Thu May 31 14:56:47 2012
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Implementation of an aggregator which stores the data series in an
+ * <code>ArrayList</code>.
+ *
+ * @param <T>
+ *            Type of object stored in the data series.
+ */
+public class ArrayListBackedAggregator<T> extends AbstractListBackedAggregator<T> {
+    /**
+     * Similar to {@link #ArrayListBackedAggregator(UnaryFunction, long)
+     * ArrayListBackedAggregator(aggregationFunction, 0L)}.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #evaluate()}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     */
+    public ArrayListBackedAggregator(UnaryFunction<List<T>, T> aggregationFunction) {
+        this(aggregationFunction, 0L);
+    }
+
+    /**
+     * Similar to
+     * {@link #ArrayListBackedAggregator(UnaryFunction, long, boolean)
+     * ArrayListBackedAggregator(aggregationFunction,interval,false)}.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #evaluate()}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @param interval
+     *            interval in miliseconds to reset this aggregator
+     */
+    public ArrayListBackedAggregator(UnaryFunction<List<T>, T> aggregationFunction, long interval) {
+        this(aggregationFunction, interval, false);
+    }
+
+    /**
+     * Initializes an aggregator with the given function, interval and decides
+     * whether to use the shared timer or own timer.
+     *
+     * @param aggregationFunction
+     *            Aggregation function to use in {@link #evaluate()}. Throws
+     *            <code>NullPointerException</code> if this is <code>null</code>
+     * @param interval
+     *            interval in miliseconds to reset this aggregator
+     * @param useSharedTimer
+     *            if set to true, it shares a timer across instances as per
+     *            {@link AbstractTimedAggregator#AbstractTimedAggregator(long,boolean)}
+     *            , otherwise this instance will use its private timer
+     */
+    public ArrayListBackedAggregator(UnaryFunction<List<T>, T> aggregationFunction, long interval,
+            boolean useSharedTimer) {
+        super(aggregationFunction, interval, useSharedTimer);
+    }
+
+    /**
+     * Creates an instance of <code>ArrayList</code> and returns it.
+     *
+     * @return newly created <code>ArrayList</code> (with default initial
+     *         capacity as per JDK).
+     */
+    @Override
+    protected List<T> createList() {
+        return new ArrayList<T>();
+    }
+
+    @Override
+    public String toString() {
+        return ArrayListBackedAggregator.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/ArrayListBackedAggregator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java Thu May 31 14:56:47 2012
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator;
+
+/**
+ * Listener to be used with instances of {@link AbstractTimedAggregator} to
+ * receive notifications when the timer kicks in.
+ *
+ * @param <T>
+ *            Type of object the <code>Aggregator</code> is operating on.
+ */
+public interface TimedAggregatorListener<T> {
+    /**
+     * Received when the aggregator listening to has triggered the timer.
+     *
+     * @param aggregator
+     *            Aggregator which has triggered the time event in the first
+     *            place.
+     * @param evaluation
+     *            Current {@link AbstractTimedAggregator#evaluate() evaluation
+     *            result} of the aggregator which triggered the event
+     */
+    void onTimer(AbstractTimedAggregator<T> aggregator, T evaluation);
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/TimedAggregatorListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator.functions;
+
+import org.apache.commons.functor.BinaryFunction;
+
+/**
+ * Aggregation function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} which
+ * finds the maximum of 2 double(s).
+ */
+public final class DoubleMaxAggregatorBinaryFunction implements BinaryFunction<Double, Double, Double> {
+    /**
+     * Computes the maximum of the 2 given numbers and returns the result.
+     *
+     * @param left
+     *            first number to compare. If <code>null</code>, then
+     *            <code>right</code> will be returned.
+     * @param right
+     *            second number to add. If <code>null</code>, then
+     *            <code>left</code> will be returned.
+     * @return max of the 2 double's as described above
+     */
+    public Double evaluate(Double left, Double right) {
+        if (left == null) {
+            return right;
+        }
+        if (right == null) {
+            return left;
+        }
+        if (left.doubleValue() < right.doubleValue()) {
+            return right;
+        }
+        return left;
+    }
+
+    @Override
+    public String toString() {
+        return DoubleMaxAggregatorBinaryFunction.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorBinaryFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator.functions;
+
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * which finds the maximum number in a list. It does this by traversing the list
+ * (once) -- so the complexity of this will be <i>O(n)</i>.
+ */
+public class DoubleMaxAggregatorFunction implements UnaryFunction<List<Double>, Double> {
+    /**
+     * Does the actual traversal of the list and finds the maximum value then
+     * returns the result. Please note that caller is responsible for
+     * synchronizing access to the list.
+     *
+     * @param data
+     *            List to traverse and find max
+     * @return max number in the list or null if the list is empty.
+     */
+    public Double evaluate(List<Double> data) {
+        if (data == null || data.size() == 0) {
+            return null;
+        }
+        Double max = null;
+        for (Double d : data) {
+            if (max == null) {
+                max = d;
+            } else {
+                if (max.doubleValue() < d.doubleValue()) {
+                    max = d;
+                }
+            }
+        }
+        return max;
+    }
+
+    @Override
+    public String toString() {
+        return DoubleMaxAggregatorFunction.class.getName();
+    }
+
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMaxAggregatorFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator.functions;
+
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * which computes the arithmetic mean of all the numbers in the list.
+ */
+public final class DoubleMeanValueAggregatorFunction implements UnaryFunction<List<Double>, Double> {
+    /**
+     * Does the actual computation and returns the result. Please note that
+     * caller is responsible for synchronizing access to the list.
+     *
+     * @param data
+     *            List to traverse and sum
+     * @return arithmetic mean (average) of all the data in the list or null if
+     *         the list is empty.
+     */
+    public Double evaluate(List<Double> data) {
+        if (data == null || data.size() == 0) {
+            return null;
+        }
+        double mean = 0.0;
+        int n = data.size();
+        for (Double d : data) {
+            mean += d.doubleValue();
+        }
+        mean /= n;
+
+        return mean;
+    }
+
+    @Override
+    public String toString() {
+        return DoubleMeanValueAggregatorFunction.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMeanValueAggregatorFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator.functions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * which computes the <a href="http://en.wikipedia.org/wiki/Median">median</a>
+ * of all the numbers in the list.
+ */
+public final class DoubleMedianValueAggregatorFunction implements UnaryFunction<List<Double>, Double> {
+    /**
+     * Flag to indicate whether we are going to operate on a copy of the list
+     * given or not. In order to compute the median, we need to sort the list
+     * first (and then choose the item in the middle). This function offers 2
+     * ways of doing the sorting:
+     * <ul>
+     * <li>by sorting (modifying) the original list (<code>useCopy=false</code>)
+     * </li>
+     * <li>by operating on a copy of the original list and leaving the original
+     * untouched (<code>useCopy=true</code>)</li>
+     * </ul>
+     * NOTE: While using a copy ensures the original list is untouched, it does
+     * mean we are creating a temporary list for the purpose of this computation
+     * so it will have an impact on memory!
+     */
+    private boolean useCopy;
+
+    /**
+     * By default create a function which will operate on a copy of the original
+     * list ({@link #useCopy} = true).
+     *
+     * @see #useCopy
+     */
+    public DoubleMedianValueAggregatorFunction() {
+        this(true);
+    }
+
+    /**
+     * Constructor which allows the caller to specify whether to operate on the
+     * original list or a copy of it.
+     *
+     * @param useCopy
+     *            Set to true to operate on a copy of the list or false to
+     *            operate on the original list.
+     * @see #useCopy
+     */
+    public DoubleMedianValueAggregatorFunction(boolean useCopy) {
+        this.useCopy = useCopy;
+    }
+
+    /**
+     * Getter for {@link #useCopy}.
+     *
+     * @return Current value of {@link #useCopy}.
+     * @see #useCopy
+     */
+    public boolean isUseCopy() {
+        return useCopy;
+    }
+
+    /**
+     * Sorts the given list and chooses the median value. The sorting can be
+     * carried out against the original list or a copy of it, based on the value
+     * of {@link #useCopy}.
+     *
+     * @param data
+     *            List to compute the median value for
+     * @return the median value of the given list or <code>null</code> if the
+     *         list is <code>null</code> or empty.
+     */
+    public Double evaluate(List<Double> data) {
+        if (data == null || data.size() == 0) {
+            return null;
+        }
+        // if only one element in it, it is the mean
+        if (data.size() == 1) {
+            return data.get(0);
+        }
+        List<Double> copy = data;
+        if (useCopy) {
+            copy = new ArrayList<Double>(data);
+        }
+        Collections.sort(copy);
+        int n = copy.size();
+        int middle = n / 2;
+        if (n % 2 == 0) {
+            // need to compute the mean of middle and middle-1 (zero based
+            // index!)
+            return (copy.get(middle) + copy.get(middle - 1)) / 2;
+        }
+
+        // we're already positioned on the element in the middle so just return
+        // it
+        return copy.get(middle);
+    }
+
+    @Override
+    public String toString() {
+        return DoubleMedianValueAggregatorFunction.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleMedianValueAggregatorFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator.functions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * which retrieves the <a
+ * href="http://en.wikipedia.org/wiki/Percentile">percentile</a> value for a
+ * given percentile. The percentile rank/index for a value P can be obtained
+ * using formula: <code>n = round((P / 100) * N + 0.5)</code> where N is the
+ * number of items in a list.
+ */
+public class DoublePercentileAggregatorFunction implements UnaryFunction<List<Double>, Double> {
+    /** A percentile goes from 0 to 100% and that's it. */
+    private static final double MAX_PERCENTAGE = 100.0;
+    /**
+     * Percentile value to calculate. 0 &lt; percentile &lt;= 100
+     */
+    private double              percentile;
+
+    /**
+     * Flag to indicate whether we are going to operate on a copy of the list
+     * given or not. In order to compute the percentile, we need to sort the
+     * list first (and then choose the item based on the formula given above).
+     * This function offers 2 ways of doing the sorting:
+     * <ul>
+     * <li>by sorting (modifying) the original list (<code>useCopy=false</code>)
+     * </li>
+     * <li>by operating on a copy of the original list and leaving the original
+     * untouched (<code>useCopy=true</code>)</li>
+     * </ul>
+     * NOTE: While using a copy ensures the original list is untouched, it does
+     * mean we are creating a temporary list for the purpose of this computation
+     * so it will have an impact on memory!
+     */
+    private boolean             useCopy;
+
+    /**
+     * Similar to {@link #DoublePercentileAggregatorFunction(double, boolean)
+     * DoublePercentilAggregatorFunction(percentile,true)}.
+     *
+     * @param percentile
+     *            Percentile this function will return the value for
+     */
+    public DoublePercentileAggregatorFunction(double percentile) {
+        this(percentile, true);
+    }
+
+    /**
+     * Initializes the function with the given percentile and decides whether
+     * the function will modify the original list or not.
+     *
+     * @param percentile
+     *            Percentile this function will return the value for
+     * @param useCopy
+     *            If set to true, the original list will not be modified and
+     *            will contain the data in sorted order, if false, this instance
+     *            will operate on a copy of the list
+     */
+    public DoublePercentileAggregatorFunction(double percentile, boolean useCopy) {
+        if (percentile < 0.0 || percentile > MAX_PERCENTAGE) {
+            throw new IllegalArgumentException("Invalid value for percentile: " + percentile);
+        }
+        this.percentile = percentile;
+        this.useCopy = useCopy;
+    }
+
+    /**
+     * Used internally to compute the rank of the item in the list for the
+     * requested percentile. This is invoked internally from
+     * {@link #evaluate(List)}.
+     *
+     * @param data
+     *            List containing data. This cannot be <code>null</code> (throws
+     *            <code>NullPointerException</code>) or empty (throws
+     *            <code>ArrayIndexOutOfBoundsException</code>).
+     * @return Index of the item for the requested percentile
+     * @see #getPercentile()
+     */
+    final int computeRank(List<Double> data) {
+        int maxRank = data.size() - 1;
+        int rank = (int) Math.floor((percentile * maxRank) / MAX_PERCENTAGE);
+        return rank;
+    }
+
+    /**
+     * Traverses the list and computes the percentile. In doing so, it sorts the
+     * list first -- and might or might not use the original list or a copy
+     * depending on {@link #isUseCopy()}.
+     *
+     * @param data
+     *            List to compute the percentile for
+     * @return percentile of the given list or null if list is <code>null</code>
+     *         or empty (zero size).
+     */
+    public Double evaluate(List<Double> data) {
+        if (data == null || data.size() == 0) {
+            return null;
+        }
+        List<Double> copy = data;
+        if (useCopy) {
+            copy = new ArrayList<Double>(data);
+        }
+        Collections.sort(copy);
+        int rank = computeRank(data);
+        return copy.get(rank);
+    }
+
+    /**
+     * Getter for {@link #percentile}.
+     *
+     * @return Retrieves the percentile this instance will return
+     */
+    public double getPercentile() {
+        return percentile;
+    }
+
+    /**
+     * Does this instance modify the passed in list or not?
+     *
+     * @return If true, this instance will sort the list passed in and then use
+     *         it to compute the percentile; if false, it will operate on a copy
+     *         of the list
+     * @see DoublePercentileAggregatorFunction#DoublePercentileAggregatorFunction(double,
+     *      boolean)
+     */
+    public boolean isUseCopy() {
+        return useCopy;
+    }
+
+    @Override
+    public String toString() {
+        return DoublePercentileAggregatorFunction.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoublePercentileAggregatorFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.aggregator.functions;
+
+import org.apache.commons.functor.BinaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} which
+ * sums up the 2 given numbers (hence the "Binary" in the name!). Counterpart of
+ * {@link DoubleSumAggregatorFunction}.
+ */
+public final class DoubleSumAggregatorBinaryFunction implements BinaryFunction<Double, Double, Double> {
+    /**
+     * Adds the 2 numbers together and returns the result.
+     *
+     * @param left
+     *            first number to add. If <code>null</code>, then
+     *            <code>right</code> will be returned.
+     * @param right
+     *            second number to add. If <code>null</code>, then
+     *            <code>left</code> will be returned.
+     * @return sum of the 2 double's as described above
+     */
+    public Double evaluate(Double left, Double right) {
+        if (left == null) {
+            return right;
+        }
+        if (right == null) {
+            return left;
+        }
+        return left + right;
+    }
+
+    @Override
+    public String toString() {
+        return DoubleSumAggregatorBinaryFunction.class.getName();
+    }
+}

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorBinaryFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message