/*
* StreamCruncher: Copyright (c) 2006-2008, Ashwin Jayaprakash. All Rights Reserved.
* Contact: ashwin {dot} jayaprakash {at} gmail {dot} com
* Web: http://www.StreamCruncher.com
*
* This file is part of StreamCruncher.
*
* StreamCruncher is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* StreamCruncher is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with StreamCruncher. If not, see <http://www.gnu.org/licenses/>.
*/
package streamcruncher.innards.core.partition.aggregate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import streamcruncher.api.Provider;
import streamcruncher.api.aggregator.DiffBaselineProvider;
import streamcruncher.boot.ProviderManager;
import streamcruncher.boot.Registry;
import streamcruncher.innards.query.Aggregator.Extra;
/*
* Author: Ashwin Jayaprakash Date: Oct 9, 2006 Time: 10:12:21 PM
*/
/**
* Attempts to aggregate only non-<code>null</code> {@link Comparable} items.
*/
public abstract class GenericSingleSrcColumnAggregator<T extends Comparable> extends
SingleSrcColumnAggregator {
protected TreeMap<T, AtomicInteger> valuesAndCounts;
protected int totalCount;
private T cachedValue;
private T extraOldValue;
protected DiffBaselineProvider<T> extraDiffBaselineProvider;
@Override
public void init(String[] params, LinkedHashMap<String, String> columnNamesAndTypes,
AggregationStage aggregationStage) {
super.init(params, columnNamesAndTypes, aggregationStage);
valuesAndCounts = new TreeMap<T, AtomicInteger>();
String extraDiffBaselineProviderName = getExtraDiffBaselineProviderName();
if (extraDiffBaselineProviderName != null) {
try {
ProviderManager providerManager = Registry.getImplFor(ProviderManager.class);
Provider provider = providerManager.createProvider(extraDiffBaselineProviderName);
extraDiffBaselineProvider = (DiffBaselineProvider<T>) provider;
}
catch (Exception e) {
String msg = "Could not instantiate the customized "
+ DiffBaselineProvider.class.getSimpleName() + "<Comparable>: "
+ extraDiffBaselineProviderName;
throw new RuntimeException(msg, e);
}
}
}
/**
* {@inheritDoc}
*
* @return <code>null</code> when the Aggregate list is empty.
*/
@SuppressWarnings("unchecked")
@Override
public T aggregate(List<Object[]> removedValues, List<Object[]> addedValues) {
final int pos = getColumnPosition();
boolean valueChanged = false;
if (removedValues != null && getAggregationStage() != AggregationStage.ENTRANCE) {
for (Object[] objects : removedValues) {
Object object = objects[pos];
// Consider only non-nulls.
if (object != null && object instanceof Comparable) {
Comparable c = (Comparable) object;
AtomicInteger count = valuesAndCounts.get(c);
if (count.decrementAndGet() == 0) {
valuesAndCounts.remove(c);
}
totalCount--;
valueChanged = true;
}
}
}
if (addedValues != null) {
for (Object[] objects : addedValues) {
Object object = objects[pos];
// Consider only non-nulls.
if (object != null && object instanceof Comparable) {
T c = (T) object;
AtomicInteger count = valuesAndCounts.get(c);
if (count == null) {
count = new AtomicInteger(0);
valuesAndCounts.put(c, count);
}
count.incrementAndGet();
totalCount++;
valueChanged = true;
}
}
}
if (valuesAndCounts.size() > 0) {
if (valueChanged) {
T newValue = fetchAggregatedValue();
cachedValue = doExtra(newValue);
}
}
else {
cachedValue = doExtra(null);
}
return cachedValue;
}
/**
* This method gets called only if the {@link #valuesAndCounts} has <b>at
* least 1 element</b>.
*
* @return some value stored in {@link #valuesAndCounts}.
*/
protected abstract T fetchAggregatedValue();
protected T doExtra(T newValue) {
if (getExtra() == Extra.DIFF) {
T baseline = extraDiffBaselineProvider.getBaseline(extraOldValue, newValue);
T diff = doDiff(baseline, newValue);
extraOldValue = newValue;
return diff;
}
return newValue;
}
/**
* Return NewValue - OldValue.
*
* @param oldValue
* @param newValue
* @return
*/
protected abstract T doDiff(T oldValue, T newValue);
}