Return-Path: X-Original-To: apmail-commons-commits-archive@minotaur.apache.org Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 592FECE68 for ; Thu, 31 May 2012 14:57:19 +0000 (UTC) Received: (qmail 37731 invoked by uid 500); 31 May 2012 14:57:18 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 37639 invoked by uid 500); 31 May 2012 14:57:18 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 37623 invoked by uid 99); 31 May 2012 14:57:18 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 May 2012 14:57:18 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 May 2012 14:57:12 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id BC2F423889E0 for ; Thu, 31 May 2012 14:56:52 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1344757 [2/4] - in /commons/proper/functor/trunk: ./ src/changes/ src/main/java/org/apache/commons/functor/aggregator/ src/main/java/org/apache/commons/functor/aggregator/functions/ src/site/xdoc/ src/test/java/org/apache/commons/functor/a... Date: Thu, 31 May 2012 14:56:50 -0000 To: commits@commons.apache.org From: simonetripodi@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120531145652.BC2F423889E0@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,53 @@ +/* + * 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.functions; + +import java.util.List; + +import org.apache.commons.functor.UnaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * which sums up all the numbers in the list. + */ +public final class DoubleSumAggregatorFunction implements UnaryFunction, Double> { + /** + * Does the actual adding and returns the result. Please note that caller is + * responsible for synchronizing access to the list. + * + * @param data + * List to traverse and sum + * @return arithmetic sum of all the data in the list or null if the list is + * empty. + */ + public Double evaluate(List data) { + if (data == null || data.size() == 0) { + return null; + } + double sum = 0.0; + for (Double d : data) { + sum += d; + } + return sum; + } + + @Override + public String toString() { + return DoubleSumAggregatorFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/DoubleSumAggregatorFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,60 @@ +/* + * 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.functions; + +import org.apache.commons.functor.BinaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} which + * simply increments the first argument by 1 and returns it. The reason behind + * this class is to provide a simple counter implementation: users call + * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator#add(Object)} + * with some data (which will be ignored) and the class will simply count how + * many times this call was made. Such an implementation can be used for + * instance to keep track for instance of number of transactions going through a + * system, whereas every time a transaction was made we just increment a + * counter. This can be achieved still using a + * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} and a + * {@link DoubleSumAggregatorBinaryFunction}-like function (but using int) and always + * supplying the second parameter as 1 (one). However, using this might make the + * code clearer. + */ +public final class IntegerCountAggregatorBinaryFunction implements BinaryFunction { + /** + * Increments left by one and returns it. + * + * @param left + * Value to be incremented by 1 and returned. If + * null, null is returned. + * @param right + * ignored + * @return left + 1 if left != null otherwise it + * returns null. + */ + public Integer evaluate(Integer left, Integer right) { + if (left == null) { + return null; + } + return left + 1; + } + + @Override + public String toString() { + return IntegerCountAggregatorBinaryFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,55 @@ +/* + * 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.functions; + +import org.apache.commons.functor.BinaryFunction; + +/** + * Aggregation function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} which + * finds the maximum of 2 ints. + */ +public class IntegerMaxAggregatorBinaryFunction implements BinaryFunction { + /** + * Computes the maximum of the 2 given numbers and returns the result. + * + * @param left + * first number to compare. If null, then + * right will be returned. + * @param right + * second number to add. If null, then + * left will be returned. + * @return max of the 2 integers as described above + */ + public Integer evaluate(Integer left, Integer right) { + if (left == null) { + return right; + } + if (right == null) { + return left; + } + if (left.intValue() < right.intValue()) { + return right; + } + return left; + } + + @Override + public String toString() { + return IntegerMaxAggregatorBinaryFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,60 @@ +/* + * 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.functions; + +import java.util.List; + +import org.apache.commons.functor.UnaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * which finds the maximum number in a list. It does this by traversing the list + * (once) -- so the complexity of this will be O(n). + */ +public class IntegerMaxAggregatorFunction implements UnaryFunction, Integer> { + /** + * Does the actual traversal of the list and finds the maximum value then + * returns the result. Please note that caller is responsible for + * synchronizing access to the list. + * + * @param data + * List to traverse and find max + * @return max number in the list or null if the list is empty. + */ + public Integer evaluate(List data) { + if (data == null || data.size() == 0) { + return null; + } + Integer max = null; + for (Integer d : data) { + if (max == null) { + max = d; + } else { + if (max.intValue() < d.intValue()) { + max = d; + } + } + } + return max; + } + + @Override + public String toString() { + return IntegerMaxAggregatorFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,56 @@ +/* + * 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.functions; + +import java.util.List; + +import org.apache.commons.functor.UnaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * which computes the arithmetic mean of all the numbers in the list. + */ +public final class IntegerMeanValueAggregatorFunction implements UnaryFunction, Integer> { + /** + * Does the actual computation and returns the result. Please note that + * caller is responsible for synchronizing access to the list. + * + * @param data + * List to traverse and sum + * @return arithmetic mean (average) of all the data in the list or null if + * the list is empty. + */ + public Integer evaluate(List data) { + if (data == null || data.size() == 0) { + return null; + } + int mean = 0; + int n = data.size(); + for (Integer d : data) { + mean += d.intValue(); + } + mean /= n; + + return mean; + } + + @Override + public String toString() { + return IntegerMeanValueAggregatorFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMeanValueAggregatorFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,122 @@ +/* + * 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.functions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.functor.UnaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * which computes the median + * of all the numbers in the list. + */ +public final class IntegerMedianValueAggregatorFunction implements UnaryFunction, Integer> { + /** + * Flag to indicate whether we are going to operate on a copy of the list + * given or not. In order to compute the median, we need to sort the list + * first (and then choose the item in the middle). This function offers 2 + * ways of doing the sorting: + *
    + *
  • by sorting (modifying) the original list (useCopy=false) + *
  • + *
  • by operating on a copy of the original list and leaving the original + * untouched (useCopy=true)
  • + *
+ * NOTE: While using a copy ensures the original list is untouched, it does + * mean we are creating a temporary list for the purpose of this computation + * so it will have an impact on memory! + */ + private boolean useCopy; + + /** + * By default create a function which will operate on a copy of the original + * list ({@link #useCopy} = true). + * + * @see #useCopy + */ + public IntegerMedianValueAggregatorFunction() { + this(true); + } + + /** + * Constructor which allows the caller to specify whether to operate on the + * original list or a copy of it. + * + * @param useCopy + * Set to true to operate on a copy of the list or false to + * operate on the original list. + * @see #useCopy + */ + public IntegerMedianValueAggregatorFunction(boolean useCopy) { + this.useCopy = useCopy; + } + + /** + * Getter for {@link #useCopy}. + * + * @return Current value of {@link #useCopy}. + * @see #useCopy + */ + public boolean isUseCopy() { + return useCopy; + } + + /** + * Sorts the given list and chooses the median value. The sorting can be + * carried out against the original list or a copy of it, based on the value + * of {@link #useCopy}. + * + * @param data + * List to compute the median value for + * @return the median value of the given list or null if the + * list is null or empty. + */ + public Integer evaluate(List data) { + if (data == null || data.size() == 0) { + return null; + } + // if only one element in it, it is the mean + if (data.size() == 1) { + return data.get(0); + } + List copy = data; + if (useCopy) { + copy = new ArrayList(data); + } + Collections.sort(copy); + int n = copy.size(); + int middle = n / 2; + if (n % 2 == 0) { + // need to compute the mean of middle and middle-1 (zero based + // index!) + return (copy.get(middle) + copy.get(middle - 1)) / 2; + } + + // we're already positioned on the element in the middle so just return + // it + return copy.get(middle); + } + + @Override + public String toString() { + return IntegerMedianValueAggregatorFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMedianValueAggregatorFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,156 @@ +/* + * 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.functions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.functor.UnaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * which retrieves the percentile value for a + * given percentile. The percentile rank/index for a value P can be obtained + * using formula: n = round((P / 100) * N + 0.5) where N is the + * number of items in a list. + */ +public class IntegerPercentileAggregatorFunction implements UnaryFunction, Integer> { + /** A percentile goes from 0 to 100% and that's it. */ + private static final double MAX_PERCENTAGE = 100.0; + /** + * Percentile value to calculate. 0 < percentile <= 100 + */ + private double percentile; + + /** + * Flag to indicate whether we are going to operate on a copy of the list + * given or not. In order to compute the percentile, we need to sort the + * list first (and then choose the item based on the formula given above). + * This function offers 2 ways of doing the sorting: + *
    + *
  • by sorting (modifying) the original list (useCopy=false) + *
  • + *
  • by operating on a copy of the original list and leaving the original + * untouched (useCopy=true)
  • + *
+ * NOTE: While using a copy ensures the original list is untouched, it does + * mean we are creating a temporary list for the purpose of this computation + * so it will have an impact on memory! + */ + private boolean useCopy; + + /** + * Similar to {@link #IntegerPercentileAggregatorFunction(double, boolean) + * IntPercentilAggregatorFunction(percentile,true)}. + * + * @param percentile + * Percentile this function will return the value for + */ + public IntegerPercentileAggregatorFunction(double percentile) { + this(percentile, true); + } + + /** + * Initializes the function with the given percentile and decides whether + * the function will modify the original list or not. + * + * @param percentile + * Percentile this function will return the value for + * @param useCopy + * If set to true, the original list will not be modified and + * will contain the data in sorted order, if false, this instance + * will operate on a copy of the list + */ + public IntegerPercentileAggregatorFunction(double percentile, boolean useCopy) { + if (percentile < 0.0 || percentile > MAX_PERCENTAGE) { + throw new IllegalArgumentException("Invalid value for percentile: " + percentile); + } + this.percentile = percentile; + this.useCopy = useCopy; + } + + /** + * Used internally to compute the rank of the item in the list for the + * requested percentile. This is invoked internally from + * {@link #evaluate(List)}. + * + * @param data + * List containing data. This cannot be null (throws + * NullPointerException) or empty (throws + * ArrayIndexOutOfBoundsException). + * @return Index of the item for the requested percentile + * @see #getPercentile() + */ + final int computeRank(List data) { + int maxRank = data.size() - 1; + int rank = (int) Math.floor((percentile * maxRank) / MAX_PERCENTAGE); + return rank; + } + + /** + * Traverses the list and computes the percentile. In doing so, it sorts the + * list first -- and might or might not use the original list or a copy + * depending on {@link #isUseCopy()}. + * + * @param data + * List to compute the percentile for + * @return percentile of the given list or null if list is null + * or empty (zero size). + */ + public Integer evaluate(List data) { + if (data == null || data.size() == 0) { + return null; + } + List copy = data; + if (useCopy) { + copy = new ArrayList(data); + } + Collections.sort(copy); + int rank = computeRank(data); + return copy.get(rank); + } + + /** + * Getter for {@link #percentile}. + * + * @return Retrieves the percentile this instance will return + */ + public double getPercentile() { + return percentile; + } + + /** + * Does this instance modify the passed in list or not? + * + * @return If true, this instance will sort the list passed in and then use + * it to compute the percentile; if false, it will operate on a copy + * of the list + * @see IntegerPercentileAggregatorFunction#IntegerPercentileAggregatorFunction(double, + * boolean) + */ + public boolean isUseCopy() { + return useCopy; + } + + @Override + public String toString() { + return IntegerPercentileAggregatorFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerPercentileAggregatorFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,53 @@ +/* + * 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.functions; + +import org.apache.commons.functor.BinaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} which + * sums up the 2 given numbers (hence the "Binary" in the name!). Counterpart of + * {@link IntegerSumAggregatorFunction}. + */ +public final class IntegerSumAggregatorBinaryFunction implements BinaryFunction { + /** + * Adds the 2 numbers together and returns the result. + * + * @param left + * first number to add. If null, then + * right will be returned. + * @param right + * second number to add. If null, then + * left will be returned. + * @return sum of the 2 int's as described above + */ + public Integer evaluate(Integer left, Integer right) { + if (left == null) { + return right; + } + if (right == null) { + return left; + } + return left + right; + } + + @Override + public String toString() { + return IntegerSumAggregatorBinaryFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java Thu May 31 14:56:47 2012 @@ -0,0 +1,53 @@ +/* + * 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.functions; + +import java.util.List; + +import org.apache.commons.functor.UnaryFunction; + +/** + * Aggregator function to be used with subclasses of + * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * which sums up all the numbers in the list. + */ +public final class IntegerSumAggregatorFunction implements UnaryFunction, Integer> { + /** + * Does the actual adding and returns the result. Please note that caller is + * responsible for synchronizing access to the list. + * + * @param data + * List to traverse and sum + * @return arithmetic sum of all the data in the list or null if the list is + * empty. + */ + public Integer evaluate(List data) { + if (data == null || data.size() == 0) { + return null; + } + int sum = 0; + for (Integer d : data) { + sum += d; + } + return sum; + } + + @Override + public String toString() { + return IntegerSumAggregatorFunction.class.getName(); + } +} Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java Thu May 31 14:56:47 2012 @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/** + *

+ * This package contains UnaryFunction's used by aggregators + * defined in org.apache.commons.functor.aggregator. + *

+ *

+ * These will normally be passed as parameters in constructors to classes + * such as {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator} + * to allow for customization of aggregation services. + *

+ */ +package org.apache.commons.functor.aggregator.functions; Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/package-info.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java (added) +++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java Thu May 31 14:56:47 2012 @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + *

+ * This package contains the interfaces and utilities needed to implement + * an aggregation service. + *

+ *

+ * Aggregation refers to being able to add data to a data "sink" which + * "aggregates" them automatically (e.g. sum them up or average, median etc). + *

+ *

+ * An example of an aggregation service is being able to average a series + * of int values (perhaps generated from a monitoring component) + * and be able to constantly report on the average (or mean) value of + * this series. There is no specification about the maximum amount of data that + * can be aggregated -- some subclasses might impose such restrictions, + * if that is the case then that will be specified in their JavaDoc's. + *

+ */ +package org.apache.commons.functor.aggregator; Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/package-info.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: commons/proper/functor/trunk/src/site/xdoc/aggregate.xml URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/site/xdoc/aggregate.xml?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/site/xdoc/aggregate.xml (added) +++ commons/proper/functor/trunk/src/site/xdoc/aggregate.xml Thu May 31 14:56:47 2012 @@ -0,0 +1,283 @@ + + + + + Aggregator + Aggregator + + + +
+

+ The aggregator package + provides a component which can be "fed" data from various sources and apply various + computations to this data to "aggregate" it. The design allows for a pluggable + implementation to be used for the purpose of aggregation and also provides flexibility + with regards to storing the data being fed to this component. +
+ There are 2 implementations as far as storage is concerned : nostore and + ArrayList-backed store. The former should be used when the aggregation + formula is simple enough to be applied on-the-fly without having to traverse a series + of data -- e.g. summarizing / adding the data (TODO need more explanation). +

+
+ +
+

The ArrayList-backed store implementation stores the whole data series in a + growing ArrayList such that when data is aggregated one can traverse the + series and apply complex formulas (find the median of a set of numeric values for instance). +

+ +

While the store implementation stores the data in a list, the nostore one + stores just a single object -- every time data is fed into the Aggregator, + the data stored in this object and the data + passed in + are "aggregated" there and then using the supplied formula and the result of this operation + is stored back in the object this implementation uses to store data. +
+ This has the implication that unlike the list-backed storage implementation (where the + result of aggregating the data is not known until evaluate() + is called) with the nostore implementation the result is known (and saved back) at + any moment. This arguably makes this class "faster", however this comes at the cost of a + slower add() + operation, as the aggregation formula is applied. Also, let's remind ourselves that not all + formulas can be implemented using the nostore implementation (see above). +

+
+ +
+

+ The data an aggregator handles can be "reset" at any point -- in the case of the + store implementation this means emptying the ArrayList; in the case + of nostore this means setting the "start value" to a "neutral" value -- for + instance 0 for implementations which involve additions (Y + 0 = Y), 1 for + multiplication (Y * 1 = Y) etc. This operation ultimately resets the + aggregator to the initial state it was in when created in the first place. This feature + allows for a caller to schedule regular resets to free up resources etc. +

+
+ +
+

+ Retrieving the data and regular intervals then flush/reset the aggregator was an + envisaged scenario for the aggregator -- so the base class + AbstractTimedAggregator + offers support to start a timer internally to do that. The class offers a listener + mechanism where classes can register to receive timer notifications (if timer support was configured) and after all listeners have been + notified the aggregator is reset. + The result of + evaluate() + (the result of aggregating data) is passed in to the listeners. This allows for an object + to simply register itself as a timer listener to the aggregator and only react to the + timer notifications (e.g. write the result to a file for offline analysis etc) while the + aggregator itself manages all the internals. +

+ +

+ There are 2 ways the + AbstractTimedAggregator + can be configured with timer support: +

+
    +
  • Using a per-instance timer : by default, when using the + 1 + parameter constructor with a value > 0, the aggregator will create a + Timer object internally and schedule the regular task of resetting the + aggregator under this Timer. While this helps preventing memory leaks + (both Aggregator and Timer will be recycled together) it + does increase the threading level in the system with each aggregator object created. + If your system creates a lot of AbstractTimedAggregator instances with + timer support, you might want to consider using the shared timer (see below).
  • +
  • Using a shared timer : the AbstractTimedAggregator + class creates a static + timer instance which can be shared amongst all instances of this class, if using + the + constructor with 2 params. When doing so, each such instance will schedule its + regular reset task against this timer. While this reduces the memory footprint and + threading on the system, it can lead to memory leaks if this is not handled correctly. + Therefore please make sure you invoke stop() + on such aggregators when finished working with them.
  • +
+

+ It is recommended you always invoke stop() + at the end of the lifecycle of an aggregator -- regardless of timer support (shared / + per instance) or not -- in particular calling stop() on an aggregator with + no timer support has no effect, however doing so ensures code uniformity and cleanliness. +

+
+ +
+

An example of usage for this component (though not necessarily the only one) could be in + a highly transactional system where, for instance, the average transaction time can be an + indication of the system health. While a fully-fledged monitoring system can say monitor + the system load, file system etc., you might also want your monitoring system to keep an + eye on the average transaction time. One way to do so is have an AbstractTimedAggregator + which is capturing each transaction execution time and every say 5 seconds it computes + the arithmetic mean (average) and writes that to a log file (which then your monitoring + system can tail). To do so you would use a piece of code like this: +

+ + +public class AggregatorTesting implements TimedAggregatorListener<Double> { + Aggregator<Double> agg; + + public AggregatorTesting() { + AbstractTimedAggregator<Double> aggregator = new ArrayListBackedAggregator<Double>(new DoubleMeanValueAggregatorFunction(), + 5000L); + aggregator.addTimerListener(this); + this.agg = aggregator; + } + + @Override + public void onTimer(AbstractTimedAggregator<Double> aggregator) { + double aggregated = aggregator.evaluate(); + /* log the value etc. */ + } + + private void add(double d) { + agg.add(d); + } + + public static void main(String[] args) { + AggregatorTesting t = new AggregatorTesting(); + /* add data */ + t.add( 1.0 ); + t.add( 2.0 ); + /* .. */ + } +} + + +

Now let's assume that you occasionally see the odd spike in transaction times -- which, + for the purpose of this example, we'll assume is normal. As such you are not concerned with + these spikes, so you want a formula to exclude them. Chances are an arithmetic median + would be more appropriate in this case; in which case the code above can suffer just a + small change: +

+ + + ... + AbstractTimedAggregator<Double> aggregator = new ArrayListBackedAggregator<Double>(new DoubleMedianValueAggregatorFunction(), + 5000L); + ... + + +

Or maybe you want to be more precise and ensure that lets say 95% of your transactions + take less than a certain execution time, so you replace the median formula with a + percentile one: +

+ + + ... + AbstractTimedAggregator<Double> aggregator = new ArrayListBackedAggregator<Double>(new DoublePercentileAggregatorFunction(95), + 5000L); + ... + + +

Or maybe your health indicator is the number of transactions going through the system + every 5 seconds. In this case you can use a nostore aggregator with a sum formula + like this: +

+ + +public class AggregatorTesting implements TimedAggregatorListener<Double> { + Aggregator<Double> agg; + + public AggregatorTesting() { + AbstractTimedAggregator<Double> aggregator = new AbstractNoStoreAggregator<Double>( + new DoubleSumAggregatorFunction2(), 5000L) { + @Override + protected Double initialValue() { + return 0.0; + } + }; + aggregator.addTimerListener(this); + this.agg = aggregator; + } + + @Override + public void onTimer(AbstractTimedAggregator<Double> aggregator) { + double aggregated = aggregator.evaluate(); + /* log the value etc. */ + } + + private void add(double d) { + agg.add(d); + } + + public static void main(String[] args) { + AggregatorTesting t = new AggregatorTesting(); + /* add data */ + t.add(1.0); + t.add(2.0); + /* .. */ + } +} + + +

(Bear in mind that there is also a IntCountAggregatorFunction2 too!) +

+ +

This has the advantage of a lower memory footprint as well (see above). If your healthcheck + indicator is based on the maximum transaction time over a 5 seconds interval, then you simply + replace the aggregation function with a max value implementation: +

+ + + ... + AbstractTimedAggregator<Double> aggregator = new AbstractNoStoreAggregator<Double>( + new DoubleMaxAggregatorFunction2(), 5000L) { + ... + + +

Or you can simply roll out your own code -- if using the nostore implementation, + all you need to do is implement a + BinaryFunction and pass + it to the Aggregator constructor. This function will receive the already-stored + aggregated value as the first parameter, and data just passed in (via add()) as the + second parameter; the result of this function will be stored back in the aggregator. +
+ For the list-based aggregators, use an instance of AbstractListBackedAggregator and pass in an instance of UnaryFunction + which accepts a List and returns a single object. +
+ Have a look at the + org.apache.commons.functor.aggregate.functions package which includes a set of functions to achieve + various of these tasks already. +

+ +

Note on class naming : You will notice in the org.apache.commons.functor.aggregate.functions package there are functions with similar names -- e.g. + DoubleSumAggregatorFunction and DoubleSumAggregatorFunction2. The naming convention is that if the function takes 2 + parameters (i.e. it is an instance of BinaryFunction then the + name of the class in this package will end in 2, otherwise, if it is an instance + of UnaryFunction then the + name will not end in a 2.
+ The reason behind it is that instances of BinaryFunction can be used with + AbstractNoStoreAggregator whereas the instances of UnaryFunction can be used + with AbstractTimedAggregator. +

+
+ +
Propchange: commons/proper/functor/trunk/src/site/xdoc/aggregate.xml ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/site/xdoc/aggregate.xml ------------------------------------------------------------------------------ svn:keywords = Date Revision Author HeadURL Id Propchange: commons/proper/functor/trunk/src/site/xdoc/aggregate.xml ------------------------------------------------------------------------------ svn:mime-type = text/xml Added: commons/proper/functor/trunk/src/site/xdoc/aggregator.xml URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/site/xdoc/aggregator.xml?rev=1344757&view=auto ============================================================================== --- commons/proper/functor/trunk/src/site/xdoc/aggregator.xml (added) +++ commons/proper/functor/trunk/src/site/xdoc/aggregator.xml Thu May 31 14:56:47 2012 @@ -0,0 +1,311 @@ + + + + + Aggregator + Aggregator + + + +
+

+ The aggregator package + provides a component which can be "fed" data from various sources and apply various + computations to this data to "aggregate" it. The design allows for a pluggable + implementation to be used for the purpose of aggregation and also provides flexibility + with regards to storing the data being fed to this component. +
+ There are 2 implementations as far as storage is concerned : nostore and + List-backed store. The former should be used when the aggregation + formula is simple enough to be applied on-the-fly without having to traverse a series + of data -- e.g. summarizing / adding the data -- while the latter can perform more advanced processing -- e.g. + statistical calculations: median, average, percentile etc. +

+
+ +
+

The List-backed store implementation stores the whole data series in a + growing List such that when data is aggregated one can traverse the + series and apply complex formulas (find the median of a set of numeric values for instance). +
+ The framework allows for any List-based implementation to be plugged in, by + implementing createList(), + however, there is also an ArrayList-based implementation provided in + ArrayListBackedAggregator + which can be used out-of-the-box. +

+ +

While the store implementation stores the data in a list, the nostore one + stores just a single object -- every time data is fed into the Aggregator, + the data stored in this object and the data + passed in + are "aggregated" there and then using the supplied + formula and the result of this operation + is stored back in the object this implementation uses to store data. +
+ This has the implication that unlike the list-backed storage implementation (where the + result of aggregating the data is not known until evaluate() + is called), with the nostore implementation the result is known (and saved back) at + any moment. This arguably makes this class "faster", however this comes at the cost of a + slower add() + operation, as the aggregation formula is applied. Also, let's remind ourselves that not all + formulas can be implemented using the nostore implementation (see above). +

+
+ +
+

+ The data an aggregator handles can be "reset" at any point -- in the case of the + store implementation this means emptying the List; in the case + of nostore this means setting the "start value" to a "neutral" value -- for + instance 0 for implementations which involve additions (Y + 0 = Y), 1 for + multiplication (Y * 1 = Y) etc. This operation ultimately resets the + aggregator to the initial state it was in when created in the first place. This feature + allows for a caller to schedule regular resets to free up resources etc. +

+
+ +
+

+ Retrieving the data and regular intervals then flush/reset the aggregator was an + envisaged scenario for the aggregator -- so the base class + AbstractTimedAggregator + offers support to start a timer internally to do that. The class offers a listener + mechanism where classes can register to receive timer notifications (if timer support was configured) and after all listeners have been + notified the aggregator is reset. + The result of + evaluate() + (the result of aggregating data) is passed in to the listeners. This allows for an object + to simply register itself as a timer listener to the aggregator and only react to the + timer notifications (e.g. write the result to a file for offline analysis etc) while the + aggregator itself manages all the internals. +

+ +

+ When the data is being flushed/reset, a + TimedAggregatorListener + can be registered to receive a notification. The notification is sent after the data is reset. + Prior to resetting the data, evaluate() + is called, and the result of the evaluation is sent to the listener.
+ This allows for data aggregated periodically to be processed (e.g. logged, written into a database etc) without + worrying about what happens in between. +

+ +

+ There are 2 ways the + AbstractTimedAggregator + can be configured with timer support: +

+
    +
  • Using a per-instance timer : by default, when using the + 1 + parameter constructor with a value > 0, the aggregator will create a + Timer object internally and schedule the regular task of resetting the + aggregator under this Timer. While this helps preventing memory leaks + (both Aggregator and Timer will be recycled together) it + does increase the threading level in the system with each aggregator object created. + If your system creates a lot of AbstractTimedAggregator instances with + timer support, you might want to consider using the shared timer (see below).
  • +
  • Using a shared timer : the AbstractTimedAggregator + class creates a static + timer instance which can be shared amongst all instances of this class, if using + the + constructor with 2 params. When doing so, each such instance will schedule its + regular reset task against this timer. While this reduces the memory footprint and + threading on the system, it can lead to memory leaks if this is not handled correctly. + Therefore please make sure you invoke stop() + on such aggregators when finished working with them.
  • +
+

+ It is recommended you always invoke stop() + at the end of the lifecycle of an aggregator -- regardless of timer support (shared / + per instance) or not -- in particular calling stop() on an aggregator with + no timer support has no effect, however doing so ensures code uniformity and cleanliness. +

+
+ +
+

An example of usage for this component (though not necessarily the only one) could be in + a highly transactional system where, for instance, the average transaction time can be an + indication of the system health. While a fully-fledged monitoring system can say monitor + the system load, file system etc., you might also want your monitoring system to keep an + eye on the average transaction time. One way to do so is have an AbstractTimedAggregator + which is capturing each transaction execution time and every say 5 seconds it computes + the arithmetic mean (average) and writes that to a log file (which then your monitoring + system can tail). To do so you would use a piece of code like this: +

+ + +public class AggregatorTesting implements TimedAggregatorListener<Double> { + Aggregator<Double> agg; + + public AggregatorTesting() { + AbstractTimedAggregator<Double> aggregator = new ArrayListBackedAggregator<Double>(new DoubleMeanValueAggregatorFunction(), + 5000L); + aggregator.addTimerListener(this); + this.agg = aggregator; + } + + @Override + public void onTimer(AbstractTimedAggregator<Double> aggregator) { + double aggregated = aggregator.evaluate(); + /* log the value etc. */ + } + + private void add(double d) { + agg.add(d); + } + + public static void main(String[] args) { + AggregatorTesting t = new AggregatorTesting(); + /* add data */ + t.add( 1.0 ); + t.add( 2.0 ); + /* .. */ + } +} + + +

Now let's assume that you occasionally see the odd spike in transaction times -- which, + for the purpose of this example, we'll assume is normal. As such you are not concerned with + these spikes, so you want a formula to exclude them. Chances are an arithmetic median + would be more appropriate in this case; in which case the code above can suffer just a + small change: +

+ + + ... + AbstractTimedAggregator<Double> aggregator = new ArrayListBackedAggregator<Double>(new DoubleMedianValueAggregatorFunction(), + 5000L); + ... + + +

Or maybe you want to be more precise and ensure that lets say 95% of your transactions + take less than a certain execution time, so you replace the median formula with a + percentile one: +

+ + + ... + AbstractTimedAggregator<Double> aggregator = new ArrayListBackedAggregator<Double>(new DoublePercentileAggregatorFunction(95), + 5000L); + ... + + +

Or maybe your health indicator is the number of transactions going through the system + every 5 seconds. In this case you can use a nostore aggregator with a sum formula + like this: +

+ + +public class AggregatorTesting implements TimedAggregatorListener<Double> { + Aggregator<Double> agg; + + public AggregatorTesting() { + AbstractTimedAggregator<Double> aggregator = new AbstractNoStoreAggregator<Double>( + new DoubleSumAggregatorBinaryFunction(), 5000L) { + @Override + protected Double initialValue() { + return 0.0; + } + }; + aggregator.addTimerListener(this); + this.agg = aggregator; + } + + @Override + public void onTimer(AbstractTimedAggregator<Double> aggregator) { + double aggregated = aggregator.evaluate(); + /* log the value etc. */ + } + + private void add(double d) { + agg.add(d); + } + + public static void main(String[] args) { + AggregatorTesting t = new AggregatorTesting(); + /* add data */ + t.add(1.0); + t.add(2.0); + /* .. */ + } +} + + +

(Bear in mind that there is also a + IntegerCountAggregatorBinaryFunction too!) +

+ +

This has the advantage of a lower memory footprint as well (see above). If your healthcheck + indicator is based on the maximum transaction time over a 5 seconds interval, then you simply + replace the aggregation + function with a max value implementation: +

+ + + ... + AbstractTimedAggregator<Double> aggregator = new AbstractNoStoreAggregator<Double>( + new DoubleMaxAggregatorBinaryFunction(), 5000L) { + ... + + +

Or you can simply roll out your own code -- if using the nostore implementation, + all you need to do is implement a + BinaryFunction and pass + it to the Aggregator + constructor. This function will receive the already-stored + aggregated value as the first parameter, and data just passed in (via add()) as the + second parameter; the result of this function will be stored back in the aggregator. +
+ For the list-based aggregators, use an instance of + AbstractListBackedAggregator + and pass in an instance of UnaryFunction + which accepts a List and returns a single object. +
+ Have a look at the + org.apache.commons.functor.aggregator.functions + package which includes a set of functions to achieve various of these tasks already. +

+ +

Note on class naming : You will notice in the + org.apache.commons.functor.aggregator.functions + package there are functions with similar names -- e.g. + DoubleSumAggregatorFunction + and DoubleSumAggregatorBinaryFunction. + The naming convention is that if the function takes 2 + parameters (i.e. it is an instance of BinaryFunction then the + name of the class in this package will contain BinaryFunction, otherwise, if it is an instance + of UnaryFunction then the + name will only contain Function.
+ The reason behind it is that instances of BinaryFunction can be used with + AbstractNoStoreAggregator + whereas the instances of UnaryFunction can be used + with AbstractTimedAggregator. +

+
+ +
Propchange: commons/proper/functor/trunk/src/site/xdoc/aggregator.xml ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/functor/trunk/src/site/xdoc/aggregator.xml ------------------------------------------------------------------------------ svn:keywords = Date Revision Author HeadURL Id Propchange: commons/proper/functor/trunk/src/site/xdoc/aggregator.xml ------------------------------------------------------------------------------ svn:mime-type = text/xml Modified: commons/proper/functor/trunk/src/site/xdoc/examples.xml URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/site/xdoc/examples.xml?rev=1344757&r1=1344756&r2=1344757&view=diff ============================================================================== --- commons/proper/functor/trunk/src/site/xdoc/examples.xml (original) +++ commons/proper/functor/trunk/src/site/xdoc/examples.xml Thu May 31 14:56:47 2012 @@ -20,6 +20,7 @@ Examples Apache Commons Development Team Rodney Waldhoff + Liviu Tudor @@ -115,7 +116,27 @@ The lines package demonstrates a functional approach to IO using Generators and the Algorithms class.

- + + + +

+ There are some code snippets / examples for the org.apache.commons.functor.aggregator package + available on this page. Also, to exemplify the usage of the Aggregator + classes, there are code examples in the test section. +
+ First such set of example involves the usage of the nostore Aggregator. Code can be found in + org.apache.commons.functor.example.aggregator.nostore. + This shows how can you use an aggregator which doesn't store the data series and processes them on the fly. + Also, there are examples provided which show how can you implement your own aggregation function + to be used with this Aggregator type. +
+ For using an Aggregator which stores the data series in a list, examples are in + org.apache.commons.functor.example.aggregator.list. + This shows how can you use the ArrayList-backed aggregator or provide your own List-based implementation. + Also, there are examples provided which show how can you implement your own aggregation function + to be used with this Aggregator type. +

+