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}