Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The contents of this file are subject to the terms of either the Universal Permissive License
* v 1.0 as shown at http://oss.oracle.com/licenses/upl
*
* or the following license:
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.openjdk.jmc.common.item;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Predicate;
import org.openjdk.jmc.common.messages.internal.Messages;
import org.openjdk.jmc.common.unit.ContentType;
import org.openjdk.jmc.common.unit.IQuantity;
import org.openjdk.jmc.common.unit.IUnit;
import org.openjdk.jmc.common.unit.KindOfQuantity;
import org.openjdk.jmc.common.unit.LinearKindOfQuantity;
import org.openjdk.jmc.common.unit.UnitLookup;
import org.openjdk.jmc.common.util.PredicateToolkit;
import org.openjdk.jmc.common.util.StringToolkit;
public class Aggregators {
public static abstract class AggregatorBase> implements IAggregator {
private final String name;
private final String description;
private final IType ct;
public AggregatorBase(String name, String description, IType ct) {
this.name = name;
this.description = description;
this.ct = ct;
}
@Override
public IType getValueType() {
return ct;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
}
public static abstract class MergingAggregator> extends AggregatorBase {
public MergingAggregator(String name, String description, IType ct) {
super(name, description, ct);
}
// FIXME: consumers can have different types, they should maybe not be merged?
// FIXME: Who should be responsible for this merge?
@Override
public V getValue(Iterator consumers) {
if (consumers.hasNext()) {
C consumer = consumers.next();
while (consumers.hasNext()) {
C next = consumers.next();
consumer = consumer.merge(next);
}
return getValue(consumer);
}
return null;
}
public abstract V getValue(C consumer);
}
public static abstract class FieldAggregatorBase> extends MergingAggregator {
FieldAggregatorBase(String name, String description, IType ct) {
super(name, description, ct);
}
@Override
public boolean acceptType(IType type) {
IMemberAccessor a = doGetAccessor(type);
return a != null;
}
protected abstract IMemberAccessor doGetAccessor(IType type);
IMemberAccessor getAccessor(IType type) {
IMemberAccessor ma = doGetAccessor(type);
if (ma != null) {
return ma;
}
throw new IllegalArgumentException("IAggregator.acceptType must be called before newValueConsumer"); //$NON-NLS-1$
}
}
private static abstract class QuantityConsumer implements IItemConsumer {
IMemberAccessor accessor;
QuantityConsumer(IMemberAccessor accessor) {
this.accessor = accessor;
}
}
private static class SumConsumer extends QuantityConsumer {
double sum = 0.0;
IUnit unit = null;
SumConsumer(IMemberAccessor accessor) {
super(accessor);
}
@Override
public void consume(IItem item) {
IQuantity fieldValue = accessor.getMember(item);
if (unit == null) {
unit = fieldValue.getUnit();
}
sum += fieldValue.doubleValueIn(unit);
}
@Override
public SumConsumer merge(SumConsumer other) {
// FIXME: Should we create a new instance, or is it OK to modify consumers like this?
if (unit != null) {
if (other.unit != null) {
sum += other.unit.valueTransformTo(unit).targetValue(other.sum);
}
return this;
}
return other;
}
}
public static abstract class Sum extends FieldAggregatorBase {
public Sum(String name, String description, LinearKindOfQuantity ct) {
super(name, description, ct);
}
@Override
public SumConsumer newItemConsumer(IType type) {
return new SumConsumer(getAccessor(type));
}
@Override
public IQuantity getValue(SumConsumer consumer) {
return consumer.unit != null ? consumer.unit.quantity(consumer.sum) : null;
}
}
public static abstract class Variance extends FieldAggregatorBase {
private final boolean besselCorrection;
public Variance(String name, String description, LinearKindOfQuantity ct, boolean besselCorrection) {
super(name, description, ct);
this.besselCorrection = besselCorrection;
}
@Override
public VarianceConsumer newItemConsumer(IType type) {
return new VarianceConsumer(getAccessor(type));
}
@Override
public IQuantity getValue(VarianceConsumer consumer) {
if (consumer.unit == null) {
return null;
}
Number variance = consumer.getVariance(besselCorrection);
return variance == null ? null : consumer.unit.quantity(variance);
}
}
public static abstract class Stddev extends FieldAggregatorBase {
private final boolean besselCorrection;
public Stddev(String name, String description, LinearKindOfQuantity ct, boolean besselCorrection) {
super(name, description, ct);
this.besselCorrection = besselCorrection;
}
@Override
public VarianceConsumer newItemConsumer(IType type) {
return new VarianceConsumer(getAccessor(type));
}
@Override
public IQuantity getValue(VarianceConsumer consumer) {
if (consumer.unit == null) {
return null;
}
Number stddev = consumer.getStddev(besselCorrection);
return stddev == null ? null : consumer.unit.quantity(stddev);
}
}
/**
* Consumer for calculating stddev and variance in a one pass, numerically stable way.
*/
public static class VarianceConsumer extends QuantityConsumer {
public long n = 0;
public double mean = 0.0;
public double M2 = 0.0;
public IUnit unit = null;
public VarianceConsumer(IMemberAccessor accessor) {
super(accessor);
}
public Number getVariance(boolean besselCorrection) {
long divisor = besselCorrection ? n - 1 : n;
if (divisor < 0) {
return null;
}
if (divisor == 0) {
return besselCorrection ? null : 0;
}
return M2 / divisor;
}
public Number getStddev(boolean besselCorrection) {
Number variance = getVariance(besselCorrection);
if (variance == null) {
return null;
}
return Math.sqrt(variance.doubleValue());
}
@Override
public void consume(IItem item) {
IQuantity fieldValue = accessor.getMember(item);
n++;
if (fieldValue == null) {
return;
}
if (unit == null) {
unit = fieldValue.getUnit();
}
double x = fieldValue.doubleValueIn(unit);
double delta = x - mean;
mean = mean + delta / n;
M2 = M2 + delta * (x - mean);
}
@Override
public VarianceConsumer merge(VarianceConsumer other) {
if (unit == null) {
unit = other.unit;
}
if (unit != null) {
if (other.unit != null) {
/*
* Since the Knuth algorithm (Chan et. al) can be used with partitioned sets, we
* can combine the results from two aggregators with partial results like below.
*/
double otherMean = other.unit.valueTransformTo(unit).targetValue(other.mean);
double otherM2 = other.unit.valueTransformTo(unit).targetValue(other.M2);
double deltaMean = otherMean - mean;
mean = mean + deltaMean * (other.n / (double) (other.n + n));
M2 = otherM2 + M2 + deltaMean * deltaMean * (other.n * n / (double) (n + other.n));
n += other.n;
}
return this;
}
return other;
}
}
// FIXME: Would like to extend SumConsumer, but this currently causes generics problems
public static class AvgConsumer extends QuantityConsumer {
public double sum = 0.0;
public IUnit unit = null;
public int count = 0;
public AvgConsumer(IMemberAccessor accessor) {
super(accessor);
}
@Override
public void consume(IItem item) {
IQuantity fieldValue = accessor.getMember(item);
if (fieldValue == null) {
count++;
return;
}
if (unit == null) {
unit = fieldValue.getUnit();
}
sum += fieldValue.doubleValueIn(unit);
count++;
}
@Override
public AvgConsumer merge(AvgConsumer other) {
if (unit == null) {
unit = other.unit;
}
if (unit != null) {
if (other.unit != null) {
sum += other.unit.valueTransformTo(unit).targetValue(other.sum);
count += other.count;
}
return this;
}
return other;
}
}
public static abstract class Avg extends FieldAggregatorBase {
public Avg(String name, String description, ContentType ct) {
super(name, description, ct);
}
@Override
public AvgConsumer newItemConsumer(IType type) {
return new AvgConsumer(getAccessor(type));
}
@Override
public IQuantity getValue(AvgConsumer consumer) {
return consumer.unit == null ? null : consumer.unit.quantity(consumer.sum / consumer.count);
}
}
public static class MinMaxConsumer> implements IItemConsumer> {
private final IMemberAccessor accessor;
private final boolean max;
private V value;
private IItem item;
public MinMaxConsumer(IMemberAccessor accessor, boolean max) {
this.accessor = accessor;
this.max = max;
}
@Override
public void consume(IItem item) {
add(accessor.getMember(item), item);
}
// FIXME: "add" is not an ideal name for this method, rename to something better
private void add(V newValue, IItem newItem) {
if (newValue != null && (value == null || newValue.compareTo(value) > 0 == max)) {
value = newValue;
item = newItem;
}
}
@Override
public MinMaxConsumer merge(MinMaxConsumer other) {
add(other.value, other.item);
return this;
}
}
public static abstract class MinMax> extends FieldAggregatorBase> {
private final boolean max;
MinMax(String name, String description, ContentType ct, boolean max) {
super(name, description, ct);
this.max = max;
}
@Override
public MinMaxConsumer newItemConsumer(IType type) {
return new MinMaxConsumer<>(getAccessor(type), max);
}
@Override
public V getValue(MinMaxConsumer consumer) {
return consumer.value;
}
}
public static class CountConsumer implements IItemConsumer {
private int count = 0;
@Override
public void consume(IItem item) {
count++;
}
@Override
public CountConsumer merge(CountConsumer other) {
count += other.count;
return this;
}
public int getCount() {
return count;
}
}
private static class FilterConsumer> implements IItemConsumer> {
private final Predicate p;
private final C nestedConsumer;
public FilterConsumer(Predicate p, C nestedConsumer) {
this.p = p;
this.nestedConsumer = nestedConsumer;
}
@Override
public void consume(IItem item) {
if (p.test(item)) {
nestedConsumer.consume(item);
}
}
@Override
public FilterConsumer merge(FilterConsumer other) {
nestedConsumer.merge(other.nestedConsumer);
return this;
}
}
private static class Count extends MergingAggregator {
Count(String name, String description) {
super(name, description, UnitLookup.NUMBER);
}
@Override
public boolean acceptType(IType type) {
return true;
}
@Override
public CountConsumer newItemConsumer(IType type) {
return new CountConsumer();
}
@Override
public IQuantity getValue(CountConsumer consumer) {
return UnitLookup.NUMBER_UNITY.quantity(consumer.count);
}
}
private static final Count COUNT = new Count(Messages.getString(Messages.ItemAggregate_COUNT), null);
private static class AndOrConsumer implements IItemConsumer {
boolean and;
Boolean b;
IMemberAccessor accessor;
public AndOrConsumer(IMemberAccessor accessor, boolean and) {
this.and = and;
this.accessor = accessor;
}
@Override
public void consume(IItem item) {
evaluate(accessor.getMember(item));
}
void evaluate(Boolean value) {
if (b == null) {
b = value;
} else if (value != null) {
b = and ? b && value : b || value;
}
}
@Override
public AndOrConsumer merge(AndOrConsumer other) {
evaluate(other.b);
return this;
}
}
private static abstract class AndOr extends FieldAggregatorBase {
public AndOr(String name, String description, IType ct) {
super(name, description, ct);
}
@Override
public Boolean getValue(AndOrConsumer consumer) {
return consumer.b;
}
}
private static > IAggregator minMaxItem(
String name, final IAttribute attribute, boolean max) {
return new MergingAggregator>("Item with " + name, null, UnitLookup.UNKNOWN) { //$NON-NLS-1$
@Override
public boolean acceptType(IType type) {
return attribute.getAccessor(type) != null;
}
@Override
public MinMaxConsumer newItemConsumer(IType type) {
return new MinMaxConsumer<>(attribute.getAccessor(type), true);
}
@Override
public IItem getValue(MinMaxConsumer consumer) {
return consumer.item;
}
};
}
public static > IAggregator itemWithMin(IAttribute attribute) {
String name = getMinName(attribute.getName(), attribute.getContentType());
return minMaxItem(name, attribute, false);
}
public static > IAggregator itemWithMax(IAttribute attribute) {
String name = getMaxName(attribute.getName(), attribute.getContentType());
return minMaxItem(name, attribute, true);
}
public static IAggregator filter(IAggregator aggregator, IItemFilter filter) {
return filter(aggregator.getName(), aggregator.getDescription(), aggregator, filter);
}
public static > IAggregator filter(
String name, String description, final IAggregator aggregator, final IItemFilter filter) {
return new AggregatorBase>(name, description, aggregator.getValueType()) {
@Override
public boolean acceptType(IType type) {
return aggregator.acceptType(type) && !PredicateToolkit.isFalseGuaranteed(filter.getPredicate(type));
}
@Override
public FilterConsumer newItemConsumer(IType type) {
return new FilterConsumer<>(filter.getPredicate(type), aggregator.newItemConsumer(type));
}
@Override
public V getValue(final Iterator> consumers) {
return aggregator.getValue(new Iterator() {
@Override
public boolean hasNext() {
return consumers.hasNext();
}
@Override
public C next() {
return consumers.next().nestedConsumer;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
});
}
};
}
public static IAggregator sum(final IAttribute attribute) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof LinearKindOfQuantity) {
return new Sum(getSumName(attribute.getName()), attribute.getDescription(),
(LinearKindOfQuantity) contentType) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
throw new IllegalArgumentException("Can only use LinearKindOfQuantity"); //$NON-NLS-1$
}
/**
* Calculates the sample variance for a linear quantity attribute.
*
* @param attribute
* the attribute to calculate the sample variance for
* @return the variance for the attribute
*/
public static IAggregator variance(final IAttribute attribute) {
return varianceInternal(attribute, true);
}
/**
* Calculates the population variance for a linear quantity attribute.
*
* @param attribute
* the attribute to calculate the population variance for
* @return the variance for the attribute
*/
public static IAggregator variancep(final IAttribute attribute) {
return varianceInternal(attribute, false);
}
private static IAggregator varianceInternal(
final IAttribute attribute, boolean besselCorrection) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof LinearKindOfQuantity) {
return new Variance(getVarianceName(attribute.getName(), besselCorrection), attribute.getDescription(),
(LinearKindOfQuantity) contentType, besselCorrection) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
throw new IllegalArgumentException("Can only use LinearKindOfQuantity"); //$NON-NLS-1$
}
/**
* Calculates the sample standard deviation for a linear quantity attribute.
*
* @param attribute
* the attribute to calculate the sample standard deviation for
* @return the standard deviation for the attribute
*/
public static IAggregator stddev(final IAttribute attribute) {
return stddevInternal(attribute, true);
}
/**
* Calculates the sample standard deviation for a linear quantity attribute.
*
* @param name
* aggregator name
* @param description
* aggregator description
* @param attribute
* the attribute to calculate the sample standard deviation for
* @return an aggregator that calculates the standard deviation for the attribute
*/
public static IAggregator stddev(
String name, String description, final IAttribute attribute) {
return stddevInternal(name, description, attribute, true);
}
/**
* Calculates the population standard deviation for a linear quantity attribute.
*
* @param attribute
* the attribute to calculate the population standard deviation for
* @return an aggregator that calculates the standard deviation for the attribute
*/
public static IAggregator stddevp(final IAttribute attribute) {
return stddevInternal(attribute, false);
}
/**
* Calculates the population standard deviation for a linear quantity attribute.
*
* @param name
* aggregator name
* @param description
* aggregator description
* @param attribute
* the attribute to calculate the population standard deviation for
* @return an aggregator that calculates the standard deviation for the attribute
*/
public static IAggregator stddevp(
String name, String description, final IAttribute attribute) {
return stddevInternal(name, description, attribute, false);
}
private static IAggregator stddevInternal(
final IAttribute attribute, boolean besselCorrection) {
return stddevInternal(getStddevName(attribute.getName(), besselCorrection), attribute.getDescription(),
attribute, besselCorrection);
}
private static IAggregator stddevInternal(
String name, String description, final IAttribute attribute, boolean besselCorrection) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof LinearKindOfQuantity) {
return new Stddev(name, description, (LinearKindOfQuantity) contentType, besselCorrection) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
throw new IllegalArgumentException("Can only use LinearKindOfQuantity"); //$NON-NLS-1$
}
public static IAggregator sum(final String typeId, final IAttribute attribute) {
return sum(getSumName(attribute.getName()), null, typeId, attribute);
}
public static IAggregator sum(String name, String description, IAttribute attribute) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof LinearKindOfQuantity) {
return sum(name, description, (LinearKindOfQuantity) contentType, attribute);
}
throw new IllegalArgumentException("Can only use LinearKindOfQuantity"); //$NON-NLS-1$
}
public static IAggregator sum(
String name, String description, final String typeId, final IAttribute attribute) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof LinearKindOfQuantity) {
return new Sum(name, description, (LinearKindOfQuantity) contentType) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
if (type.getIdentifier().equals(typeId)) {
return attribute.getAccessor(type);
}
return null;
}
};
}
throw new IllegalArgumentException("Can only use LinearKindOfQuantity"); //$NON-NLS-1$
}
public static IAggregator sum(
String name, String description, LinearKindOfQuantity ct, final IAccessorFactory af) {
return new Sum(name, description, ct) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return af.getAccessor(type);
}
};
}
public static IAggregator avg(final IAttribute attribute) {
return new Avg(getAvgName(attribute.getName()), attribute.getDescription(), attribute.getContentType()) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
public static IAggregator avg(final String typeId, final IAttribute attribute) {
return avg(getAvgName(attribute.getName()), null, typeId, attribute);
}
public static IAggregator avg(String name, String description, IAttribute attribute) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof KindOfQuantity) {
return avg(name, description, (KindOfQuantity) contentType, attribute);
}
throw new IllegalArgumentException("Can only use KindOfQuantity"); //$NON-NLS-1$
}
public static IAggregator avg(
String name, String description, final String typeId, final IAttribute attribute) {
ContentType contentType = attribute.getContentType();
if (contentType instanceof KindOfQuantity) {
return new Avg(name, description, (KindOfQuantity) contentType) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
if (type.getIdentifier().equals(typeId)) {
return attribute.getAccessor(type);
}
return null;
}
};
}
throw new IllegalArgumentException("Can only use KindOfQuantity"); //$NON-NLS-1$
}
public static IAggregator avg(
String name, String description, KindOfQuantity ct, final IAccessorFactory af) {
return new Avg(name, description, ct) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return af.getAccessor(type);
}
};
}
public static > IAggregator min(final IAttribute attribute) {
String name = getMinName(attribute.getName(), attribute.getContentType());
return new MinMax(name, attribute.getDescription(), attribute.getContentType(), false) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
public static > IAggregator min(final String typeId, final IAttribute attribute) {
String name = getMinName(attribute.getName(), attribute.getContentType());
return min(name, null, typeId, attribute);
}
public static > IAggregator min(
String name, String description, final String typeId, final IAttribute attribute) {
ContentType contentType = attribute.getContentType();
return new MinMax(name, description, contentType, false) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
if (type.getIdentifier().equals(typeId)) {
return attribute.getAccessor(type);
}
return null;
}
};
}
public static > IAggregator max(final IAttribute attribute) {
String name = getMaxName(attribute.getName(), attribute.getContentType());
return new MinMax(name, attribute.getDescription(), attribute.getContentType(), true) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
public static IAggregator max(final String typeId, final IAttribute attribute) {
String name = getMaxName(attribute.getName(), attribute.getContentType());
return max(name, null, typeId, attribute);
}
public static > IAggregator max(
String name, String description, final IAttribute attribute) {
ContentType contentType = attribute.getContentType();
return new MinMax(name, description, contentType, true) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
return attribute.getAccessor(type);
}
};
}
public static > IAggregator max(
String name, String description, final String typeId, final IAttribute attribute) {
ContentType contentType = attribute.getContentType();
return new MinMax(name, description, contentType, true) {
@Override
protected IMemberAccessor doGetAccessor(IType type) {
if (type.getIdentifier().equals(typeId)) {
return attribute.getAccessor(type);
}
return null;
}
};
}
public static IAggregator count() {
return COUNT;
}
public static IAggregator count(String name, String description) {
return new Count(name, description);
}
public static IAggregator count(IType type) {
return filter(getCountName(type), null, COUNT, ItemFilters.type(type.getIdentifier()));
}
public static IAggregator count(IItemFilter filter) {
return filter(COUNT, filter);
}
public static IAggregator count(String name, String description, IItemFilter filter) {
return filter(name, description, COUNT, filter);
}
public static IAggregator and(final String typeId, final IAttribute attribute) {
return new AndOr(attribute.getName(), attribute.getDescription(), UnitLookup.FLAG) {
@Override
public AndOrConsumer newItemConsumer(IType type) {
return new AndOrConsumer(attribute.getAccessor(type), true);
}
@Override
public boolean acceptType(IType type) {
return type.getIdentifier().equals(typeId);
}
@Override
protected IMemberAccessor doGetAccessor(IType type) {
if (type.getIdentifier().equals(typeId)) {
return attribute.getAccessor(type);
}
return null;
}
};
}
public static IAggregator or(final String typeId, final IAttribute attribute) {
return new AndOr(attribute.getName(), attribute.getDescription(), UnitLookup.FLAG) {
@Override
public AndOrConsumer newItemConsumer(IType type) {
return new AndOrConsumer(attribute.getAccessor(type), false);
}
@Override
public boolean acceptType(IType type) {
return type.getIdentifier().equals(typeId);
}
@Override
protected IMemberAccessor doGetAccessor(IType type) {
if (type.getIdentifier().equals(typeId)) {
return attribute.getAccessor(type);
}
return null;
}
};
}
public static class SetConsumer implements IItemConsumer> {
Set distinct = new HashSet<>();
private final IMemberAccessor accessor;
public SetConsumer(IMemberAccessor accessor) {
this.accessor = accessor;
}
@Override
public void consume(IItem item) {
T member = accessor.getMember(item);
if (member != null) {
distinct.add(member);
}
}
@Override
public SetConsumer merge(SetConsumer other) {
distinct.addAll(other.distinct);
return this;
}
}
private abstract static class SetAggregator extends MergingAggregator> {
private final IAccessorFactory attribute;
public SetAggregator(String name, String description, IAccessorFactory attribute, IType type) {
super(name, description, type);
this.attribute = attribute;
}
@Override
public boolean acceptType(IType type) {
return attribute.getAccessor(type) != null;
}
@Override
public SetConsumer newItemConsumer(IType itemType) {
return new SetConsumer<>(attribute.getAccessor(itemType));
}
};
public static IAggregator distinctAsString(String typeId, IAttribute attribute) {
return filter(distinctAsString(attribute, ", "), ItemFilters.type(typeId)); //$NON-NLS-1$
}
public static IAggregator distinctAsString(IAttribute attribute, final String delimiter) {
return distinctAsString(attribute, delimiter, attribute.getName(), attribute.getDescription());
}
public static IAggregator distinctAsString(
IAttribute attribute, final String delimiter, String name, String description) {
IAggregator, ?> aggregator = Aggregators.distinct(attribute);
return Aggregators.valueBuilderAggregator(aggregator, new IValueBuilder>() {
@Override
public String getValue(Set source) {
return source.isEmpty() ? null : StringToolkit.join(source, delimiter);
}
@Override
public IType getValueType() {
return UnitLookup.PLAIN_TEXT;
}
}, name, description);
}
public static > IAggregator valueBuilderAggregator(
final IAggregator aggregator, final IValueBuilder valuebuilder, String name,
String description) {
return new AggregatorBase(name, description, valuebuilder.getValueType()) {
@Override
public boolean acceptType(IType type) {
return aggregator.acceptType(type);
}
@Override
public C newItemConsumer(IType type) {
return aggregator.newItemConsumer(type);
}
@Override
public V2 getValue(final Iterator consumers) {
V1 val1 = aggregator.getValue(consumers);
return val1 != null ? valuebuilder.getValue(val1) : null;
}
};
}
public static IAggregator countDistinct(
String name, String description, IAccessorFactory attribute) {
return new SetAggregator(name, description, attribute, UnitLookup.NUMBER) {
@Override
public IQuantity getValue(SetConsumer consumer) {
return UnitLookup.NUMBER_UNITY.quantity(consumer.distinct.size());
}
};
}
public static IAggregator, ?> distinct(IAttribute attribute) {
return distinct(MessageFormat.format(Messages.getString(Messages.ItemAggregate_DISTINCT), attribute.getName()),
attribute);
}
public static IAggregator, ?> distinct(String name, IAccessorFactory attribute) {
return new SetAggregator, T>(name, null, attribute, UnitLookup.UNKNOWN) {
@Override
public Set getValue(SetConsumer consumer) {
return consumer.distinct;
}
};
}
public static > IAggregator forConsumer(IItemConsumerFactory consumerFactory) {
return forConsumer(consumerFactory, PredicateToolkit.> truePredicate());
}
public static > IAggregator forConsumer(
final IItemConsumerFactory consumerFactory, final Predicate> acceptType) {
return new MergingAggregator("", null, UnitLookup.UNKNOWN) { //$NON-NLS-1$
@Override
public boolean acceptType(IType type) {
return acceptType.test(type);
}
@Override
public C newItemConsumer(IType type) {
return consumerFactory.newItemConsumer(type);
}
@Override
public C getValue(C consumer) {
return consumer;
}
};
}
private static String getCountName(IType type) {
return Messages.getString(Messages.ItemAggregate_COUNT) + " " + type.getName(); //$NON-NLS-1$
}
static String getSumName(String name) {
return Messages.getString(Messages.ItemAggregate_TOTAL) + " " + name; //$NON-NLS-1$
}
static String getVarianceName(String name, boolean besselCorrection) {
return Messages.getString(besselCorrection ? Messages.ItemAggregate_VARIANCE : Messages.ItemAggregate_VARIANCEP)
+ " " + name; //$NON-NLS-1$
}
static String getStddevName(String name, boolean besselCorrection) {
return Messages.getString(besselCorrection ? Messages.ItemAggregate_STDDEV : Messages.ItemAggregate_STDDEVP)
+ " " + name; //$NON-NLS-1$
}
static String getAvgName(String name) {
return Messages.getString(Messages.ItemAggregate_AVERAGE) + " " + name; //$NON-NLS-1$
}
static String getMaxName(String name, ContentType ct) {
if (ct == UnitLookup.TIMESPAN) {
return Messages.getString(Messages.ItemAggregate_LONGEST) + " " + name; //$NON-NLS-1$
} else if (ct == UnitLookup.TIMESTAMP) {
return Messages.getString(Messages.ItemAggregate_LAST) + " " + name; //$NON-NLS-1$
} else {
return Messages.getString(Messages.ItemAggregate_MAXIMUM) + " " + name; //$NON-NLS-1$
}
}
static String getMinName(String name, ContentType ct) {
if (ct == UnitLookup.TIMESPAN) {
return Messages.getString(Messages.ItemAggregate_SHORTEST) + " " + name; //$NON-NLS-1$
} else if (ct == UnitLookup.TIMESTAMP) {
return Messages.getString(Messages.ItemAggregate_FIRST) + " " + name; //$NON-NLS-1$
} else {
return Messages.getString(Messages.ItemAggregate_MINIMUM) + " " + name; //$NON-NLS-1$
}
}
// FIXME: Translated strings are not good for persistence purposes. Maybe do something else.
public static IAggregator getQuantityAggregator(String name, IAttribute attribute) {
if (name == null) {
return null;
}
if (name.startsWith(Messages.getString(Messages.ItemAggregate_TOTAL))) {
return sum(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_AVERAGE))) {
return avg(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_LONGEST))) {
return max(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_LAST))) {
return max(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_MAXIMUM))) {
return max(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_SHORTEST))) {
return min(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_FIRST))) {
return min(attribute);
} else if (name.startsWith(Messages.getString(Messages.ItemAggregate_MINIMUM))) {
return min(attribute);
} else {
return null;
}
}
public static IAggregator getQuantityAggregator(String name, IType type) {
if (type != null) {
if (name.startsWith(Messages.getString(Messages.ItemAggregate_COUNT))) {
return count(type);
}
}
if (name.startsWith(Messages.getString(Messages.ItemAggregate_COUNT))) {
return count();
}
return null;
}
public static IAggregator getQuantityAggregator(String name) {
if (name.startsWith(Messages.getString(Messages.ItemAggregate_COUNT))) {
return count();
}
return null;
}
/**
* This consumer separates the attribute for which to do the ordering from the attribute to use
* for accessing the value. It is typically used within the AdvancedMinMaxAggregator for getting
* a specific value from the first or last event from a collection of events.
*
* @param
* the return value type, for example {@code java.lang.String}
* @param
* the value type for the ordering
*/
public static class AdvancedMinMaxConsumer>
implements IItemConsumer> {
private final IMemberAccessor accessor;
private final IMemberAccessor comparatorAccessor;
private final boolean max;
private IItem item;
/**
* @param valueAccessor
* the accessor for retrieving the value
* @param comparatorAccessor
* the accessor for retrieving the value to use for comparisons
* @param max
* whether to use the smallest value, or the greatest
*/
public AdvancedMinMaxConsumer(IMemberAccessor valueAccessor,
IMemberAccessor comparatorAccessor, boolean max) {
this.accessor = valueAccessor;
this.max = max;
this.comparatorAccessor = comparatorAccessor;
}
@Override
public void consume(IItem newItem) {
if (newItem == null) {
return;
}
T newOrderingValue = comparatorAccessor.getMember(newItem);
if (newOrderingValue == null) {
return;
} else if (item == null) {
item = newItem;
} else {
T oldOrderingValue = comparatorAccessor.getMember(item);
if (newOrderingValue.compareTo(oldOrderingValue) > 0 == max) {
item = newItem;
}
}
}
@Override
public AdvancedMinMaxConsumer merge(AdvancedMinMaxConsumer other) {
consume(other.item);
return this;
}
public V getValue() {
if (item == null) {
return null;
}
return accessor.getMember(item);
}
}
/**
* This aggregator separates the attribute for which to do the ordering from the attribute to
* use for accessing the value. It is typically used for getting a specific value from the first
* or last event from a collection of events.
*
* @param
* the return value type, for example {@code java.lang.String}
* @param
* the value type for the ordering
*/
private static class AdvancedMinMaxAggregator