All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jagg.model.AggregateValue Maven / Gradle / Ivy

Go to download

jAgg is a Java 5.0 API that supports “group by” operations on Lists of Java objects: aggregate operations such as count, sum, max, min, avg, and many more. It also allows custom aggregate operations.

The newest version!
package net.sf.jagg.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.jagg.AggregateFunction;
import net.sf.jagg.Aggregator;

/**
 * This class represents the result of a "group by" operation, where certain
 * fields of a type are selected for a "group by", and certain values can
 * be extracted by referring to AggregateFunctions.
 *
 * @author Randy Gettman
 * @since 0.1.0
 */
public class AggregateValue
{
   private T myObject;
   private Map myValuesMap;
   private List myValuesList;
   private List myAggregators;
   private List myProperties;
   private List myGroupingSet;

   /**
    * Create an AggregateValue that wraps the given object.  It
    * will also store aggregation values.
    *
    * @param object The object for which this AggregateValue will
    *    wrap.
    */
   public AggregateValue(T object)
   {
      myObject = object;
      myValuesMap = new HashMap();
      myValuesList = new ArrayList();
      myAggregators = null;
   }

   /**
    * Create an AggregateValue using another
    * AggregateValue.  This will wrap the same object that the
    * other AggregateValue wraps.
    * @param other Another AggregateValue.
    * @since 0.7.0
    */
   public AggregateValue(AggregateValue other)
   {
      this(other.myObject);
   }

   /**
    * 

Retrieves the T representing the "group-by" aggregation. * This method is used to directly access the property values, when * aggregating by calling Aggregation.groupByComparable.

*

If Aggregation.groupBy is called instead, then this * method will still succeed. However, if super-aggregation is used (cube, * rollups, grouping sets), the object returned here will not indicate that * this AggregateValue represents "all values" for a certain * property. In this case, either of the two overloaded * getPropertyValue methods will correctly return the * null value if that property represents "all values".

* * @return The T object representing the "group-by" aggregation. * @see net.sf.jagg.Aggregation#groupByComparable * @see #getPropertyValue(String) * @see #getPropertyValue(int) */ public T getObject() { return myObject; } /** *

Retrieves a property value representing a "group-by" category by name. * This method is used to access the property values, when aggregating by * calling Aggregation.groupBy after specifying "group-by" * properties. Because super-aggregation is possible in this case, if the * referenced property represents "all values", then this method will return * null instead of the actual property value.

* @param property The property name. * @return The property value. * @since 0.7.0 * @see net.sf.jagg.Aggregation#groupBy */ public Object getPropertyValue(String property) { if (myObject == null) return null; if (myProperties != null) { int index = myProperties.indexOf(property); // Return null for "super-aggregate" columns. if (!myGroupingSet.contains(index)) return null; } return Aggregator.getValueFromProperty(myObject, property); } /** *

Retrieves a property value representing a "group-by" category, with * the property specified by a 0-based index into the original list of * properties that was specified in Builder.getProperties.

*

If Aggregation.groupByComparable was called, then there * are no "group-by" properties, so this method would return * null. * @param propIndex The 0-based index into the list of properties. * @return The property value. * @since 0.7.0 */ public Object getPropertyValue(int propIndex) { if (myProperties != null && myObject != null) { return getPropertyValue(myProperties.get(propIndex)); } return null; } /** * This method is used internally to store the given value * associated with the given AggregateFunction for later retrieval. * It also appends the given value to an internal list for * later retrieval by index. * * @param agg An AggregateFunction. * @param value The aggregated value. * @see AggregateFunction */ public void setAggregateValue(AggregateFunction agg, Object value) { myValuesMap.put(agg, value); myValuesList.add(value); } /** * Retrieves the value for the given AggregateFunction. * * @param agg An AggregateFunction. * @return The aggregated value, or null if no such * AggregateFunction is found. */ public Object getAggregateValue(AggregateFunction agg) { return myValuesMap.get(agg); } /** * Retrieves the value for the AggregateFunction at the given index. * @param index The 0-based index. * @return The aggregated value. * @throws IndexOutOfBoundsException If the index is out of range. * @since 0.3.0 */ public Object getAggregateValue(int index) { return myValuesList.get(index); } /** *

Determines whether the referenced field represents the set of all * values in a super-aggregate value. This can be used to distinguish an * actual null value in normal aggregation vs. a * null that represents "all values" in super-aggregation.

*

For example, if there are 4 group-by properties, and super-aggregation * is used, and this aggregate value happens to represent the grouping set * {0, 1}, then properties 2 and 3 are "all values", and ...

*
    *
  • isGrouping(0) == isGrouping(1) == false *
  • isGrouping(2) == isGrouping(3) == true *
* @param field A field reference integer, from 0 to n - 1, where * n is the the number of group-by properties. * @return true if the field represents "all values" in * super-aggregation, false otherwise. * @throws IllegalArgumentException If the integer field reference is out of * range. * @since 0.7.0 */ public boolean isGrouping(int field) { if (field < 0 || field >= myProperties.size()) throw new IllegalArgumentException("isGrouping: integer field reference out of range: " + field); return !myGroupingSet.contains(field); } /** *

Determines whether the referenced field represents the set of all * values in a super-aggregate value. This can be used to distinguish an * actual null value in normal aggregation vs. a * null that represents "all values" in super-aggregation.

*

For example, if there are 4 group-by properties ({"prop0", "prop1", * "prop2", "prop3"}), and super-aggregation is used, and this aggregate * value happens to represent the grouping set {0, 1}, then properties 2 * and 3 are "all values", and ...

*
    *
  • isGrouping("prop0") == isGrouping("prop1") == false *
  • isGrouping("prop2") == isGrouping("prop3") == true *
* @param propertyName A property name. * @return true if the field represents "all values" in * super-aggregation, false otherwise. * @throws IllegalArgumentException If the property name is not a group-by * property. * @since 0.7.0 */ public boolean isGrouping(String propertyName) { int index = myProperties.indexOf(propertyName); if (index == -1) { // Property name not found. // Try as integer field reference. try { index = Integer.parseInt(propertyName); return isGrouping(index); } catch (NumberFormatException e) { // Property name not found and it's not an integer. throw new IllegalArgumentException("isGrouping: Not a group-by property name or an integer field reference: " + propertyName); } } return isGrouping(myProperties.indexOf(propertyName)); } /** *

Determines the distinct grouping ID of the given referenced fields by * determining whether each given referenced field represents "all values" * in super-aggregation.

*

For example, if there are 4 group-by properties ({"prop0", "prop1", * "prop2", "prop3"}), and super-aggregation is used, and this aggregate * value happens to represent the grouping set {0, 1}, then properties 2 and * 3 are "all values", and ...

*
    *
  • getGroupingId({0}) == getGroupingId({1}) == 0 *
  • getGroupingId({2}) == getGroupingId({3}) == 1 *
  • getGroupingId({0, 1}) == getGroupingId({1, 0}) == 0 *
  • getGroupingId({0, 2}) == getGroupingId({0, 3}) == 1 *
  • getGroupingId({1, 2}) == getGroupingId({1, 3}) == 1 *
  • getGroupingId({2, 0}) == getGroupingId({2, 1}) == 2 *
  • getGroupingId({3, 0}) == getGroupingId({3, 1}) == 2 *
  • getGroupingId({2, 3}) == getGroupingId({3, 2}) == 3 *
*

In the above examples, each integer n reference can be freely * substituted with the equivalent property name, e.g. 0 is * equivalent to "prop0".

* @param fields A List of field references, which can be * integer field references, from 0 to n - 1, where n * is the number of group-by properties, or they can be property names. * Each field reference maps to a bit in the returned number. * @return An integer, with each set bit corresponding to an "all values" * determination. The most significant bit corresponds to the first * element. * @throws IllegalArgumentException If any of the fields represent integer * field references that are out of range, or they represent string * property names that aren't group-by properties. * @since 0.7.0 */ public int getGroupingId(List fields) { // Note: This assumes that there are 32 or less fields passed in. int groupingId = 0; for (Object field : fields) { groupingId <<= 1; int fieldRef; if (field instanceof Number) { fieldRef = ((Number) field).intValue(); } else { String propertyName = field.toString(); fieldRef = myProperties.indexOf(propertyName); if (fieldRef == -1) { // Property name not found. // Try as integer field reference. try { fieldRef = Integer.parseInt(propertyName); } catch (NumberFormatException e) { // Property name not found and it's not an integer. throw new IllegalArgumentException("getGroupingId: Not a group-by property name or an integer field reference: " + propertyName); } } } if (fieldRef < 0 || fieldRef >= myProperties.size()) { throw new IllegalArgumentException("getGroupingId: integer field reference out of range: " + field); } // Mark the bit if it's "all values". if (isGrouping(fieldRef)) { groupingId |= 1; } } return groupingId; } /** * Assign a List of AggregateFunctions used to * make this AggregateValue. These AggregateFunctions * are stored here for the purposes of super-aggregation later. * @param aggs A List of AggregateFunctions. * @since 0.7.0 */ public void assignAggregators(List aggs) { myAggregators = aggs; } /** * Retrieves the List of AggregateFunctions that * are responsible for the aggregate values in this AggregateValue. * @return The List of AggregateFunctions. * @since 0.7.0 */ public List retrieveAggregators() { return myAggregators; } /** * Mark all AggregateFunctions as no longer in use and no * longer maintain the list of assigned AggregateFunctions. * @since 0.7.0 */ public void releaseAggregators() { for (AggregateFunction agg : myAggregators) agg.setInUse(false); myAggregators.clear(); } /** * Assign a List of properties and a grouping set, which is a * List of 0-based property name indexes. * @param properties A List of property names. * @param groupingSet A List of 0-based property name indexes. * @since 0.7.0 */ public void assignPropsAndGroupingSet(List properties, List groupingSet) { myProperties = properties; myGroupingSet = groupingSet; } /** * Returns the string representation. * @return The string representation. * @since 0.7.0 */ @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append("AggregateValue:(object => "); buf.append(myObject.toString()); buf.append(", valuesList =>"); buf.append(myValuesList.toString()); buf.append(", aggregators =>"); buf.append(myAggregators.toString()); buf.append(", properties =>"); buf.append(myProperties.toString()); buf.append(", groupingSet =>"); buf.append(myGroupingSet.toString()); buf.append(")"); return buf.toString(); } }