001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.functor.aggregator;
018
019import java.util.List;
020
021import org.apache.commons.functor.Function;
022import org.apache.commons.lang3.Validate;
023
024/**
025 * An aggregator which stores the data series in a List. Every call to
026 * {@link #add(Object)} will add an item in the array and there is no limit to
027 * how much data we can store. It is down to subclasses to decide which types of
028 * List implementation they need to used -- and the abstract factory
029 * {@link #createList()} is provided for this.
030 * <p>This implementation also allows for various "aggregations" of the list to be
031 * used by providing a {@link Function Function<List<T>, T>} in the
032 * constructor.</p>
033 * <p>
034 * <b>Thread safety</b> : Note that due to the fact that
035 * {@link AbstractTimedAggregator} provides a threadsafe environment for access
036 * to data, the <code>List</code> implementation can be unsynchronized.
037 * </p>
038 *
039 * @param <T>
040 *            Type of object stored.
041 * @see AbstractTimedAggregator
042 */
043public abstract class AbstractListBackedAggregator<T> extends AbstractTimedAggregator<T> {
044    /**
045     * Stores the data series we ought to aggregate/evaluate. This list can only
046     * be modified via {@link #reset()} and {@link #add(Object)} and will be
047     * traversed during {@link #evaluate()}.
048     */
049    private List<T>                   series;
050
051    /**
052     * Used to actually aggregate the data when {@link #evaluate()} is called.
053     * This is set in {@link #AbstractListBackedAggregator() the constructor}.
054     */
055    private Function<List<T>, T> aggregationFunction;
056
057    /**
058     * Default constructor. Similar to
059     * {@link #AbstractListBackedAggregator(Function, long)
060     * AbstractListBackedAggregator(aggregationFunction,0L}.
061     *
062     * @param aggregationFunction
063     *            Aggregation function to use in {@link #evaluate()}. Throws
064     *            <code>NullPointerException</code> if this is <code>null</code>
065     */
066    public AbstractListBackedAggregator(Function<List<T>, T> aggregationFunction) {
067        this(aggregationFunction, 0L);
068    }
069
070    /**
071     * Similar to
072     * {@link #AbstractListBackedAggregator(Function, long, boolean)
073     * AbstractListBackedAggregator(aggregationFunction,interval,false}.
074     *
075     * @param aggregationFunction
076     *            Aggregation function to use in {@link #evaluate()}. Throws
077     *            <code>NullPointerException</code> if this is <code>null</code>
078     * @param interval
079     *            interval in miliseconds to reset this aggregator
080     */
081    public AbstractListBackedAggregator(Function<List<T>, T> aggregationFunction, long interval) {
082        this(aggregationFunction, interval, false);
083    }
084
085    /**
086     * Constructs an aggregator which will use the given function, reset itself
087     * at the given interval and will use a shared timer on own private timer.
088     *
089     * @param aggregationFunction
090     *            Aggregation function to use in {@link #evaluate()}. Throws
091     *            <code>NullPointerException</code> if this is <code>null</code>
092     * @param interval
093     *            interval in miliseconds to reset this aggregator
094     * @param useSharedTimer
095     *            if set to true, it will use a shared timer, as per
096     *            {@link AbstractTimedAggregator#AbstractTimedAggregator(long, boolean)}
097     *            ; otherwise if it's false it will use its own timer instance
098     * @see AbstractTimedAggregator#AbstractTimedAggregator(long, boolean)
099     */
100    public AbstractListBackedAggregator(Function<List<T>, T> aggregationFunction, long interval,
101            boolean useSharedTimer) {
102        super(interval, useSharedTimer);
103        this.aggregationFunction = Validate.notNull(aggregationFunction, "Function argument must not be null");
104        this.series = createList();
105    }
106
107    /**
108     * Adds data to the series which will be aggregated. This implementation
109     * simply adds the data to the {@link #series} list.
110     *
111     * @param data
112     *            Data to be added to the data series.
113     */
114    @Override
115    public final void doAdd(T data) {
116        series.add(data);
117    }
118
119    /**
120     * The actual "beef" of this class: iterate through the list and aggregates
121     * all the data and evaluates the result. This is done by calling
122     * <code>aggregationFunction.evaluate(series)</code>.
123     *
124     * @return the result of <code>aggregationFunction.evaluate(series)</code>
125     * @see Aggregator#evaluate()
126     */
127    @Override
128    protected final T doEvaluate() {
129        return aggregationFunction.evaluate(series);
130    }
131
132    /**
133     * Resets the data series to the empty state.
134     */
135    @Override
136    protected final void doReset() {
137        series.clear();
138    }
139
140    /**
141     * Allows subclasses to create the list which will store the {@link #series
142     * data series}.
143     *
144     * @return an instance of <code>List</code> which will be used to store the
145     *         data.
146     */
147    protected abstract List<T> createList();
148
149    /**
150     * Getter for {@link #series}.
151     *
152     * @return Value of {@link #series}
153     */
154    protected final List<T> getSeries() {
155        return series;
156    }
157
158    /**
159     * Simply returns the size of the data series which is the size of the list
160     * used internally.
161     *
162     * @return Size of {@link #series} -- equivalent to
163     *         <code>series.size()</code>
164     */
165    @Override
166    protected final int retrieveDataSize() {
167        return series.size();
168    }
169
170    /**
171     * Getter for {@link #aggregationFunction}. Provided for testing purposes
172     * only.
173     *
174     * @return Current value of {@link #aggregationFunction}
175     */
176    final Function<List<T>, T> getAggregationFunction() {
177        return aggregationFunction;
178    }
179
180    @Override
181    public String toString() {
182        return AbstractListBackedAggregator.class.getName();
183    }
184}