blob: 7993ebcc63bab98112f0c7c3e166c5f9eda2bf20 [file] [log] [blame]
/*
* 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.Function;
import org.apache.commons.lang3.Validate;
/**
* 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 Function Function<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 Function<List<T>, T> aggregationFunction;
/**
* Default constructor. Similar to
* {@link #AbstractListBackedAggregator(Function, 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(Function<List<T>, T> aggregationFunction) {
this(aggregationFunction, 0L);
}
/**
* Similar to
* {@link #AbstractListBackedAggregator(Function, 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(Function<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(Function<List<T>, T> aggregationFunction, long interval,
boolean useSharedTimer) {
super(interval, useSharedTimer);
this.aggregationFunction = Validate.notNull(aggregationFunction, "Function argument must not be null");
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 Function<List<T>, T> getAggregationFunction() {
return aggregationFunction;
}
@Override
public String toString() {
return AbstractListBackedAggregator.class.getName();
}
}