MinimumAccumulator.java
/*
** Module : MinimumAccumulator.java
** Abstract : Accumulator implementation which determines minimum values
**
** Copyright (c) 2004-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
** 001 ECF 20051227 @23782 Created initial version. Reports minimum
** value from among all data values accumulated
** across a full loop, and within the current
** break group within the loop. "Sub-minimum" is
** available for the current break group only.
** 002 ECF 20060104 @23818 Consolidated constructors. Separate ctors
** which accepted a FieldReference and an
** Expression were replaced with a single ctor
** which accepts a Resolvable data source.
** 003 ECF 20060111 @23856 Added constructors for primitive types. These
** are needed to support accumulation of literal
** values.
** 004 ECF 20060118 @23986 Added support for break groups. Made mods to
** support new base class architecture.
** 005 ECF 20060503 @25952 Added support for accumulation using external
** data sources. Added features required by code
** converted from aggregators in display
** statements.
** 006 ECF 20070627 @34325 Added constructor variant. Accepts type of
** data source and creates a safe fallback
** instance.
** 007 CA 20080213 @37135 Added Data.deepCopy and Data.assign method
** implementation. Added new constructor -
** MinimumAccumulator(Resolvable, boolean) used
** by Accumulator.deepCopy() to instantiate a new
** accumulator of this type without registering
** to AccumulatorManager or TransactionManager.
** 008 ECF 20080702 @39029 Refactored constructors. This was done to
** support conversion changes made to fix a
** memory leak in the framework.
** 009 GES 20080917 @39853 Minor class name change. Also changed the
** default scope level to NEXT instead of
** CURRENT.
** 010 CA 20081008 @40059 Modified the c'tor which receive the expr type
** as a parameter. The default c'tor was removed.
** Fixed a flaw in Data.deepCopy().
** 011 CA 20160721 Cleaned up the c'tors - all accumulators register in the next scope,
** as they are defined and created as instance fields.
** 012 CA 20220514 Accumulators can be explicitly assigned via their associated variable - added
** stubbed setters.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
/**
* An accumulator implementation which determines the minimum value from
* among all values of a data source across all iterations of a loop, as well
* as across the current break group within the loop. Results are retrieved
* using one of the <code>getResult</code> method variants.
* <p>
* The comparison to determine the minimum value from among two data values
* being compared is specific to the particular {@link BaseDataType} type and
* instances being accumulated.
*/
public final class MinimumAccumulator
extends Accumulator
{
/** Relative weight of this accumulator type for sorting purposes */
static final int WEIGHT = MaximumAccumulator.WEIGHT + 1;
/**
* Constructor which stores no data source. This instance expects to be
* fed data from an external source via its <code>accumulate</code> method.
*
* @param cls
* Data type of the value being accumulated.
*/
public MinimumAccumulator(Class<? extends BaseDataType> cls)
{
super(cls);
}
/**
* Create an instance which accumulates an integral constant upon each loop
* iteration. The accumulator is registered with the AccumulatorManager and
* the TransactionManager, in the next scope.
*
* @param value
* Constant which will be accumulated at each iteration.
*/
public MinimumAccumulator(int value)
{
super(new integer(value));
}
/**
* Create an instance which accumulates an integral constant upon each loop
* iteration. The accumulator is registered with the AccumulatorManager and
* the TransactionManager, in the next scope
*
* @param value
* Constant which will be accumulated at each iteration.
*/
public MinimumAccumulator(double value)
{
super(new decimal(value));
}
/**
* Create an instance which accumulates an integral constant upon each loop
* iteration. The accumulator is registered with the AccumulatorManager and
* the TransactionManager, in the next scope.
*
* @param value
* Constant which will be accumulated at each iteration.
*/
public MinimumAccumulator(String value)
{
super(new character(value));
}
/**
* Create an instance which accumulates an integral constant upon each loop
* iteration. The accumulator is registered with the AccumulatorManager and
* the TransactionManager, in the next scope
*
* @param value
* Constant which will be accumulated at each iteration.
*/
public MinimumAccumulator(boolean value)
{
super(new logical(value));
}
/**
* Constructor which stores a mutable variable reference as the
* accumulator's data source. When an iteration occurs, the accumulator
* gathers its data using the current value of a mutable variable.
* The accumulator is registered with the AccumulatorManager and the
* TransactionManager, in the next scope
*
* @param variable
* Mutable variable from which data is collected.
*/
public MinimumAccumulator(BaseDataType variable)
{
super(variable);
}
/**
* Constructor which stores a <code>Resolvable</code> as the accumulator's
* data source. When an iteration occurs, the accumulator gathers its data
* by resolving the current value of the data source.
* <p>
* The accumulator will be automatically registered at the NEXT scope that
* is opened. This is perfect for use in class members that are
* initialized in an initializer which occurs before the scope is open.
*
* @param dataSource
* Data source from which data is collected.
*/
public MinimumAccumulator(Resolvable dataSource)
{
this(dataSource, true);
}
/**
* Constructor which stores a <code>Resolvable</code> as the accumulator's
* data source. When an iteration occurs, the accumulator gathers its data
* by resolving the current value of the data source. The accumulator is
* registered with the AccumulatorManager and the TransactionManager, in the next scope.
*
* @param dataSource
* Data source from which data is collected.
* @param register
* This flag will be <code>false</code> only if a copy object is instantiated.
* Because we use the copy only for roll-back purposes, we do not need to add it to
* the TransactionManager or AccumulatorManager.
*/
public MinimumAccumulator(Resolvable dataSource, boolean register)
{
super(dataSource, register);
}
/**
* Get the full result of all accumulations so far for this accumulator,
* across all break groups.
*
* @return Current full result.
*/
public BaseDataType getFullResult()
{
return getResult(null);
}
/**
* Get the current subgroup result for the first registered break group in
* this accumulator. Subsequent break groups, if any, are ignored.
*
* @return Subgroup result for first registered break group, or
* <code>null</code> if no subgroups are being tracked by this
* accumulator.
*/
public BaseDataType getSubResult()
{
Resolvable key = getFirstBreakGroupKey();
if (key == null)
{
return null;
}
return getResult(key);
}
/**
* Get the label associated with this accumulator type, for use in the UI.
*
* @return Label associated with this accumulator type.
*/
public String getLabel()
{
return "MIN";
}
/**
* Get the relative weight associated with this accumulator type, for use
* in sorting accumulator instances of different types according to their
* natural display order.
*
* @return An integer which represents this accumulator's sorting weight
* relative to other accumulator types.
*/
public int getWeight()
{
return WEIGHT;
}
/**
* Assign this accumulator's value.
*
* @param v
* The new value.
*/
public void setResult(double v)
{
UnimplementedFeature.missing("Accumulator assignment is not supported: MINIMUM");
}
/**
* Assign this accumulator's value.
*
* @param v
* The new value.
*/
public void setResult(String v)
{
UnimplementedFeature.missing("Accumulator assignment is not supported: MINIMUM");
}
/**
* Assign this accumulator's value.
*
* @param v
* The new value.
*/
public void setResult(BaseDataType v)
{
UnimplementedFeature.missing("Accumulator assignment is not supported: MINIMUM");
}
/**
* Get the minimum value of all instances of the accumulated data source
* across all iterations of the current break group.
*
* @return Minimum value across current break group. Unknown value if no
* iterations were performed since the break group state was last
* reset.
*/
public BaseDataType getResult()
{
return getResult(null);
}
/**
* Get the minimum value of all instances of the accumulated data source
* across all iterations of the specified break group.
*
* @param breakGroupKey
* Key identifying the break group for which the data is desired.
*
* @return Minimum value across specified break group. Unknown value if
* no iterations were performed since the break group state was
* last reset.
*/
public BaseDataType getResult(Resolvable breakGroupKey)
{
return calculate(breakGroupKey);
}
/**
* Create a data bundle which understands how to calculate a minimum value
* from among the values accumulated.
*
* @return An instance of {@link MinimumAccumulator.Data}.
*/
protected DataBundle createDataBundle()
{
return (new Data());
}
/**
* A <code>DataBundle</code> implementation which keeps track of the
* minimum data value accumulated, and returns it upon request.
*/
private class Data
implements DataBundle
{
/** The current minimum value */
private BaseDataType min = createUnknown();
/**
* Reset to unknown value the minimum value variable, in preparation
* for beginning a new break group.
*/
public void reset()
{
min = createUnknown();
}
/**
* Compare <code>datum</code> to the current minimum value. If the
* current minimum value is the unknown value, or if <code>datum</code>
* compares as less than the current minimum, <code>datum</code> is
* retained as the new minimum value. Otherwise, the old minimum value
* is left unchanged.
*
* @param datum
* Datum to be accumulated.
*/
public void accumulate(BaseDataType datum)
{
min.assign((min.isUnknown() ? datum : min.minimum(datum)));
}
/**
* Return the minimum value accumulated.
*
* @return Minimum value.
*/
public BaseDataType calculate()
{
return min.duplicate();
}
/**
* This is a form of a copy constructor that makes a deep copy of the
* current instance and returns this copy as a new instance of the same
* class.
*
* @return An instance of the same class whose data is identical to
* that of this instance.
*/
public Undoable deepCopy()
{
Data copy = new Data();
copy.min = (BaseDataType) this.min.deepCopy();
return copy;
}
/**
* Sets the state of this instance based on the state of the passed instance.
*
* @param value
* The instance from which to copy state.
*/
public void assign(Undoable value)
{
Data copy = (Data) value;
this.min.assign(copy.min);
}
}
}