Java tutorial
/* * Copyright 2015 the original author or authors. * * Licensed 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 com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; import org.json.JSONObject; /** * <p>Title: AggregateFunction</p> * <p>Description: Defines aggregate functions for aggregating the values of multiple attributes into one return value</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction</code></p> */ public enum AggregateFunction implements IAggregator { /** Calculates the sum of the returned values */ SUM(new SumAggregator(false)), /** Calculates the sum of the returned values (strict) */ STRSUM(new SumAggregator(true)), /** Returns the number of items in the result set */ COUNT(new CountAggregator(false)), /** Returns the number of items in the result set (strict) */ STRCOUNT(new CountAggregator(true)), /** Returns the average of the returned values */ AVG(new AverageAggregator(false)), /** Returns the average of the returned values (strict) */ STRAVG(new AverageAggregator(true)), /** Returns the minimum value */ MIN(new MinAggregator(false)), /** Returns the minimum value (strict)*/ STRMIN(new MinAggregator(true)), /** Returns the maximum value */ MAX(new MaxAggregator(false)), /** Returns the maximum value (strict)*/ STRMAX(new MaxAggregator(true)), /** Returns the number of distinct items based on {@link Object#equals(Object)} */ DISTINCT(new DistinctAggregator()), /** Returns a json group with each unique item and a count of the occurences */ GROUP(new GroupAggregator()), /** Returns a JSON composite of Min, Max, Average and Count */ MMAC(new MinMaxAvgCntAggregator(false)), /** Returns a JSON composite of Min, Max, Average and Count (strict) */ STRMMAC(new MinMaxAvgCntAggregator(true)), /** Returns the average delta of the sequence of passed items */ DELTA_ALL(new Delta(false)), /** Returns the delta of the most recent 2 of the passed items */ DELTA_LAST(new Delta(true)), /** Returns the average rate per second from the sequence of passed items */ PS_RATE_ALL(new Rate(false, TimeUnit.SECONDS)), /** Returns the rate per second from the most recent 2 of the passed items */ PS_RATE_LAST(new Rate(false, TimeUnit.SECONDS)), /** Returns the average rate per milli-second from the sequence of passed items */ PMS_RATE_ALL(new Rate(false, TimeUnit.MILLISECONDS)), /** Returns the rate per milli-second from the most recent 2 of the passed items */ PMS_RATE_LAST(new Rate(false, TimeUnit.MILLISECONDS)); ; /** * Creates a new AggregateFunction * @param aggr The entry's aggregator */ private AggregateFunction(IAggregator aggr) { this.aggr = aggr; } /** The enum entry's aggregator implementation */ private final IAggregator aggr; /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Object aggregate(List<Object> items) { return aggr.aggregate(items); } /** * Returns the AggregateFunction for the passed name. Applies trim and toUpper to the name first. * @param name The name of the function * @return the named AggregateFunction */ public static AggregateFunction forName(CharSequence name) { if (name == null) throw new IllegalArgumentException("The passed AggregateFunction name was null", new Throwable()); try { return AggregateFunction.valueOf(name.toString().trim().toUpperCase()); } catch (Exception e) { throw new IllegalArgumentException( "The passed AggregateFunction name [" + name + "] is not a valid function name", new Throwable()); } } /** * Retrieves an AggregateFunction by name, returning null for no match * @param name The name of the function to apply * @return the named AggregateFunction or null if one was not found */ public static AggregateFunction getAggregateFunction(CharSequence name) { try { return forName(name); } catch (Exception e) { return null; } } /** * Computes and returns the aggregate for the named aggregator and list of input items * @param name The name of the aggregator function * @param items The list of items to aggregate * @return the aggregate value */ public static Object aggregate(CharSequence name, List<Object> items) { return AggregateFunction.forName(name).aggr.aggregate(items); } /** * Computes and returns the aggregate for the named aggregator and object of nput items. * The object is introspected to determine if it is:<ul> * <li>Null</li> * <li>{@link java.util.Map}</li> * <li>{@link java.util.Collection}</li> * <li>An array</li> * </ul>. * If it is none of the above, a runtime exception is thrown. * If it is a map or an array, it is converted to a list for aggregate computation. * @param name The name of the aggregator function * @param item The object of items to aggregate * @return the aggregate value * TODO: Do we need to support multi dimmensional arrays ? */ @SuppressWarnings("unchecked") public static Object aggregate(CharSequence name, Object item) { final List<Object> items; final AggregateFunction function = AggregateFunction.forName(name); if (item == null) { items = Collections.EMPTY_LIST; } else if (item instanceof Map) { Map<Object, Object> map = (Map<Object, Object>) item; items = new ArrayList<Object>(map.keySet()); } else if (item instanceof Collection) { items = new ArrayList<Object>((Collection<Object>) item); } else if (item.getClass().isArray()) { int length = Array.getLength(item); items = new ArrayList<Object>(length); for (int i = 0; i < length; i++) { items.add(i, Array.get(item, i)); } } else { throw new IllegalArgumentException("Aggregate object of type [" + item.getClass().getName() + "] was not a Map, Collection or Array", new Throwable()); } return function.aggregate(items); } /** * <p>Title: NumericAggregator</p> * <p>Description: Aggregates a numeric computation of all the values that are assumed to be numbers or implement {@link INumberProvider}</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.SumAggregator</code></p> */ public static abstract class NumericAggregator implements IAggregator { /** If true, throws an error if any item is null or not a number */ protected final boolean strict; /** * Creates a new SumAggregator * @param strict If true, throws an error if any item is null or not a number. Otherwise ignores the non number items */ public NumericAggregator(boolean strict) { this.strict = strict; } /** * Sifts through the passed items, looking for exceptions and if non-strict, returns a list of compliant items. * @param items The list of items to sift * @return a list of valid items and instances of {@link INumberProvider}s wrapped as Numbers. */ protected List<Number> sift(List<Object> items) { if (items == null) { if (strict) throw new RuntimeException("List of items was null and aggregator was strict", new Throwable()); } List<Number> numbers = new ArrayList<Number>(items.size()); for (Object o : items) { if (o == null) { if (strict) throw new RuntimeException("List of items had a null and aggregator was strict", new Throwable()); continue; } if (o instanceof Number) { numbers.add((Number) o); continue; } if (o instanceof INumberProvider) { numbers.add(NumberWrapper.getNumber((INumberProvider) o)); continue; } if (strict) throw new RuntimeException("List of items had a non-number item [" + o.getClass().getName() + "] and aggregator was strict", new Throwable()); } return numbers; } /** * Sums an array * @param items The items to sum * @return the total sum */ protected long sum(long[] items) { if (items == null || items.length < 1) return 0L; long total = 0; for (long t : items) { total += t; } return total; } /** * Sums an array * @param items The items to sum * @return the total sum */ protected double sum(double[] items) { if (items == null || items.length < 1) return 0D; double total = 0; for (double t : items) { total += t; } return total; } } /** * <p>Title: Delta</p> * <p>Description: Computes deltas of the passed numbers</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.Delta</code></p> */ public static class Delta extends NumericAggregator { /** If true, returns the delta of the last two items, otherwise returns the average delta of all entries */ protected final boolean last; /** * Creates a new Delta * @param last If true, returns the delta of the last two items, otherwise returns the average delta of all entries */ public Delta(boolean last) { super(true); this.last = last; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Object aggregate(List<Object> items) { List<Number> numbers = sift(items); if (numbers.size() < 2) return 0; if (last) { return numbers.get(0).doubleValue() - numbers.get(1).doubleValue(); } else { double[] deltas = new double[numbers.size() - 1]; for (int i = 0; i < numbers.size() - 1; i++) { deltas[i] = numbers.get(i + 1).doubleValue() - numbers.get(i).doubleValue(); } return STRAVG.aggregate(deltas); } } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { if (items.length < 2) return 0; if (last) { return items[0] - items[1]; } else { long[] deltas = new long[items.length - 1]; for (int i = 0; i < items.length - 1; i++) { deltas[i] = items[i + 1] - items[i]; } return STRAVG.aggregate(deltas); } } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { if (items.length < 2) return 0; if (last) { return items[0] - items[1]; } else { double[] deltas = new double[items.length - 1]; for (int i = 0; i < items.length - 1; i++) { deltas[i] = items[i + 1] - items[i]; } return STRAVG.aggregate(deltas); } } } /** * <p>Title: Rate</p> * <p>Description: Computes rate of the passed numbers</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.Rate</code></p> */ public static class Rate extends Delta { /** The time unit for which to report rates */ protected final TimeUnit rateUnit; /** * Creates a new Rate * @param last If true, returns the delta of the last two items, otherwise returns the average delta of all entries * @param rateUnit The time unit for which to report rates */ public Rate(boolean last, TimeUnit rateUnit) { super(last); this.rateUnit = rateUnit; } /** * Calculates a rate from the passed numbers. The time window is passed as the first entry in the list * and is assumed to be in the same unit as this Rate instance and the values are assumed to be ticks per second. * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.Delta#aggregate(java.util.List) */ @Override public Object aggregate(List<Object> items) { List<Number> numbers = sift(items); if (numbers.size() < 3) return 0; double window = rateUnit.convert(numbers.remove(0).longValue(), TimeUnit.SECONDS); double delta = ((Number) super.aggregate(new ArrayList<Object>(numbers))).doubleValue(); return delta / window; } /** * Calculates a rate from the passed double array. The time window is passed as the first array entry * and is assumed to be in the same unit as this Rate instance and the values are assumed to be ticks per second. * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.Delta#aggregate(double[]) */ @Override public double aggregate(double[] items) { if (items.length < 3) return 0; double[] anumbers = new double[items.length - 1]; System.arraycopy(items, 1, anumbers, 0, items.length - 1); double window = TimeUnit.SECONDS.convert((long) items[0], rateUnit); double delta = super.aggregate(anumbers); if (delta <= 0 || window <= 0) return 0D; return delta / window; } /** * Calculates a rate from the passed long array. The time window is passed as the first array entry * and is assumed to be in the same unit as this Rate instance and the values are assumed to be ticks per second. * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.Delta#aggregate(double[]) */ @Override public long aggregate(long[] items) { if (items.length < 3) return 0; long[] anumbers = new long[items.length - 1]; System.arraycopy(items, 1, anumbers, 0, items.length - 1); double window = rateUnit.convert(items[0], TimeUnit.SECONDS); double delta = super.aggregate(anumbers); if (delta <= 0 || window <= 0) return 0L; return (long) (delta / window); } } /** * <p>Title: SumAggregator</p> * <p>Description: Aggregates the numeric sum of all the values</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.SumAggregator</code></p> */ public static class SumAggregator extends NumericAggregator { /** * Creates a new SumAggregator * @param strict If true, throws an error if any item is null or not a number. Otherwise ignores the non number items */ public SumAggregator(boolean strict) { super(strict); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Double aggregate(List<Object> items) { double d = 0D; for (Number n : sift(items)) { d += n.doubleValue(); } return d; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { return sum(items); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { return sum(items); } } /** * <p>Title: AverageAggregator</p> * <p>Description: Aggregates the mathematical average of all the values</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.AverageAggregator</code></p> */ public static class AverageAggregator extends NumericAggregator { /** * Creates a new AverageAggregator * @param strict If true, throws an error if any item is null or not a number. Otherwise ignores the non number items */ public AverageAggregator(boolean strict) { super(strict); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Double aggregate(List<Object> items) { double total = 0D; double count = 0D; for (Number n : sift(items)) { count++; total += n.doubleValue(); } if (total == 0 || count == 0) return 0D; return total / count; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { if (items == null) return 0; double total = sum(items); double length = items.length; if (total == 0 || length == 0) return 0; double avg = total / length; return (long) avg; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { if (items == null) return 0; double total = sum(items); double length = items.length; if (total == 0 || length == 0) return 0; double avg = total / length; return avg; } } /** * <p>Title: MinAggregator</p> * <p>Description: Computes the lowest numeric value of all the values. If non-strict, returns -1D for an empty list</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.MinAggregator</code></p> */ public static class MinAggregator extends NumericAggregator { /** * Creates a new MinAggregator * @param strict If true, throws an error if any item is null or not a number. Otherwise ignores the non number items */ public MinAggregator(boolean strict) { super(strict); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Double aggregate(List<Object> items) { List<Number> numbers = sift(items); if (numbers.isEmpty()) { if (strict) throw new RuntimeException("List of items for MIN was empty and aggregator was strict", new Throwable()); return -1D; } double min = Double.MAX_VALUE; for (Number n : sift(items)) { if (n.doubleValue() < min) min = n.doubleValue(); } return min; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { if (items == null) return 0; Arrays.sort(items); return items[0]; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { if (items == null) return 0; Arrays.sort(items); return items[0]; } } /** * <p>Title: MaxAggregator</p> * <p>Description: Computes the highest numeric value of all the values. If non-strict, returns -1D for an empty list</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.MaxAggregator</code></p> */ public static class MaxAggregator extends NumericAggregator { /** * Creates a new MaxAggregator * @param strict If true, throws an error if any item is null or not a number. Otherwise ignores the non number items */ public MaxAggregator(boolean strict) { super(strict); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Double aggregate(List<Object> items) { List<Number> numbers = sift(items); if (numbers.isEmpty()) { if (strict) throw new RuntimeException("List of items for MAX was empty and aggregator was strict", new Throwable()); return -1D; } double max = Double.MIN_VALUE; for (Number n : sift(items)) { if (n.doubleValue() > max) max = n.doubleValue(); } return max; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { if (items == null) return 0; Arrays.sort(items); return items[items.length - 1]; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { if (items == null) return 0; Arrays.sort(items); return items[items.length - 1]; } } /** * <p>Title: CountAggregator</p> * <p>Description: Aggregates the items to a simple count of the number of items. If strict, throws an exception if any item is null, otherwise ignores null items.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.CountAggregator</code></p> */ public static class CountAggregator implements IAggregator { /** The strict indicator */ private final boolean strict; /** * Creates a new CountAggregator * @param strict If true, implements strict count rules */ public CountAggregator(boolean strict) { this.strict = strict; } /** * Counts the number if items * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Object aggregate(List<Object> items) { if (items == null) { if (strict) { throw new RuntimeException("List of items for Count was null and aggregator was strict", new Throwable()); } return 0; } if (strict) { for (Object o : items) { if (o == null) throw new RuntimeException( "List of items for Count contained a null and aggregator was strict", new Throwable()); } } return items.size(); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { return items == null ? 0 : items.length; } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { return items == null ? 0 : items.length; } } /** * <p>Title: DistinctAggregator</p> * <p>Description: Aggregates the items to a simple count of the number of distinct items where equality is determined by {@link Object#equals(Object)}. </p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.DistinctAggregator</code></p> */ public static class DistinctAggregator implements IAggregator { /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Object aggregate(List<Object> items) { if (items == null || items.isEmpty()) return 0; Set<Object> set = new CopyOnWriteArraySet<Object>(items); return set.size(); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { if (items == null || items.length < 1) return 0; Set<Long> set = new HashSet<Long>(items.length); for (int i = 0; i < items.length; i++) { set.add(items[i]); } return set.size(); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { if (items == null || items.length < 1) return 0; Set<Double> set = new HashSet<Double>(items.length); for (int i = 0; i < items.length; i++) { set.add(items[i]); } return set.size(); } } /** * <p>Title: GroupAggregator</p> * <p>Description: Aggregates the items to a a json group with each unique item and a count of the occurences where equality is determined by and items * are represented using {@link Object#toString()}. Null items are ignored.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.GroupAggregator</code></p> */ public static class GroupAggregator implements IAggregator { /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public Object aggregate(List<Object> items) { if (items == null || items.isEmpty()) return new JSONObject(); Map<String, Long> map = new HashMap<String, Long>(); for (Object o : items) { if (o == null) continue; String key = o.toString(); Long l = map.get(key); if (l == null) { l = 0L; } l = l++; map.put(key, l); } return new JSONObject(map); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { throw new UnsupportedOperationException( "The direct aggregate(long[]) cannot return a JSONObject. Please use AggregateFunction.aggreaget(Object)", new Throwable()); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { throw new UnsupportedOperationException( "The direct aggregate(double[]) cannot return a JSONObject. Please use AggregateFunction.aggreaget(Object)", new Throwable()); } } /** * <p>Title: MinMaxAvgCntAggregator</p> * <p>Description: Aggregates the passed numberic items to a JSON object representing the min, max, average and count. If non-strict, returns -1D values for a null list and for null items</p> * <p><code>com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.AggregateFunction.MinMaxAvgCntAggregator</code></p> */ public static class MinMaxAvgCntAggregator extends NumericAggregator { /** The MinMaxAvgCnt key for the min value */ public static final String KEY_MIN = "min"; /** The MinMaxAvgCnt key for the max value */ public static final String KEY_MAX = "max"; /** The MinMaxAvgCnt key for the avg value */ public static final String KEY_AVG = "avg"; /** The MinMaxAvgCnt key for the value count */ public static final String KEY_CNT = "cnt"; /** The base response for a non-strict MinMaxAvgCnt with null items */ private static final JSONObject BASE_RESP; static { Map<String, Double> map = new HashMap<String, Double>(4); map.put(KEY_MIN, -1D); map.put(KEY_MAX, -1D); map.put(KEY_AVG, -1D); map.put(KEY_CNT, 0D); BASE_RESP = new JSONObject(map); } /** * Creates a new MaxAggregator * @param strict If true, throws an error if any item is null or not a number. Otherwise ignores the non number items */ public MinMaxAvgCntAggregator(boolean strict) { super(strict); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(java.util.List) */ @Override public JSONObject aggregate(List<Object> items) { List<Number> numbers = sift(items); if (numbers.isEmpty()) { if (strict) throw new RuntimeException("List of items for MinMaxAvgCnt was empty and aggregator was strict", new Throwable()); return BASE_RESP; } double max = Double.MIN_VALUE; double min = Double.MAX_VALUE; double total = 0D; double count = 0D; for (Number n : sift(items)) { Double d = n.doubleValue(); if (d > max) max = d; if (d < min) min = d; total += d; count++; } double avg = (total == 0D || count == 0D) ? 0D : (total / count); Map<String, Double> map = new HashMap<String, Double>(4); map.put(KEY_MIN, min); map.put(KEY_MAX, max); map.put(KEY_AVG, avg); map.put(KEY_CNT, count); return new JSONObject(map); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { throw new UnsupportedOperationException( "The direct aggregate(long[]) cannot return a JSONObject. Please use AggregateFunction.aggreaget(Object)", new Throwable()); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { throw new UnsupportedOperationException( "The direct aggregate(double[]) cannot return a JSONObject. Please use AggregateFunction.aggreaget(Object)", new Throwable()); } } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(long[]) */ @Override public long aggregate(long[] items) { return aggr.aggregate(items); } /** * {@inheritDoc} * @see com.heliosapm.opentsdb.client.jvmjmx.custom.aggregation.IAggregator#aggregate(double[]) */ @Override public double aggregate(double[] items) { return aggr.aggregate(items); } @SuppressWarnings("javadoc") public static void log(Object msg) { System.out.println(msg); } @SuppressWarnings({ "unchecked", "rawtypes", "javadoc" }) public static void main(String[] args) { log("DELTA Test"); Object d = null; d = DELTA_LAST.aggregate(new long[] { 20, 10, 5 }); log("DeltaLast:" + d); d = DELTA_ALL.aggregate(new long[] { 20, 10, 5 }); log("DeltaAll:" + d); d = DELTA_LAST.aggregate(new ArrayList(Arrays.asList(20, 10, 5))); log("DeltaLast:" + d); d = DELTA_ALL.aggregate(new ArrayList(Arrays.asList(20, 10, 5))); log("DeltaAll:" + d); log("\nRATE Test"); d = PS_RATE_LAST.aggregate(new long[] { 1, 10, 20 }); log("PS Last:" + d); d = PS_RATE_LAST.aggregate(new ArrayList(Arrays.asList(1, 10, 20))); log("PS Last:" + d); d = PMS_RATE_LAST.aggregate(new long[] { 1, 10000, 20000 }); log("PMS Last:" + d); d = PMS_RATE_LAST.aggregate(new ArrayList(Arrays.asList(1, 10000, 20000))); log("PMS Last:" + d); } }