PostProcessorUtils
This class groups several small utility functions.
Level and hierarchy tools
These functions generate an ILevelInfo
or IHierarchyInfo
object from a String
with the help of the IActivePivot
object.
Formats:
- level string: “level@hierarchy@dimension”
- hierarchy string: “hierarchy@dimension”
optionalLevelInfo
Returns null or ILevelInfo
object depending on the nullability or emptiness of the input string.
toLevelInfo
Returns a list of ILevelInfo
from an input list string, comma-separated by default.
toHierarchyInfo
Returns a list of IHierarchyInfo
from an input list string, comma-separated by default.
toLevelInfoMap
Returns a map ILevelInfo
=> String
from an input list string, comma-separated by default with equality between level and value.
toLevelInfoByHierarchy
Returns a map IHierarchyInfo
=> ILevelInfo
from an input list string of levels, the level belonging to the key hierarchy.
Aggregation
createAggregationFunction
Creates an aggregation function from a plugin key or the “aggregationFunction” property.
addPartitioningLevel(s)
Modifies or creates a list of levels by adding one or more extra levels.
removePartitioningLevel(s)
Modifies or creates a list of levels by removing one or more levels.
reduce
Aggregates several partitioned results into one single result.
Location manipulation
This section contains all the functions that can be used to manipulate the location; modifying the ILocation
or the ICubeFilter
.
truncateToLevelZero
Performs a drill-up to the top-level location for a selected sub-set of hierarchies.
truncateOrSetWildCardsToLevel
Performs a drill-up or drill-down to the selected level, and fills the empty levels with null or a wildcard value.
setWildCardsToLevel
Performs a drill-down to the selected level, and fills the empty levels with null or a wildcard value.
truncateToLevel
Performs a drill-up to the selected level or returns null if the corresponding hierarchy hasn’t reached the selected level.
removeWildcards
Performs a drill-up through every hierarchy until it removes any wildcard.
setCoordinate
Sets the location level to the specified value, and performs a drill-down if needed.
setFilter
Sets the location level to the specified value, only if the current location is a range compatible with the value.
checkFilter
Checks if the current location is a range compatible with the value.
shift
Sets the location level to the specified new value, only if the current location is compatible with the old specified value.
childLocation
Performs a drill-down or drill-up to the levels, with wildcards.
descendentLocation
Performs a drill-down to the levels, with wildcards.
filterMembers
Creates a filter from a list of levels and a list of allowed members (separated with “:”).
createPath
Creates a path with wildcard and the desired member at the selected level.
ancestorLocation
Gets ancestor location along risk factor hierarchy up to level in original location.
Copper Levels and Hierarchy
Converts hierarchy and level identifiers into Copper objects.
copperLevel
Transforms the input String
or LevelIdentifier
into a CopperLevel
object.
copperHierarchy
Transforms the input String
or HierarchyIdentifier
into a CopperHierarchy
object.
Caching
Functions used to handle a concurrent map (like the query cache) into a cache object.
getInCacheOrComputeNeverNull
Retrieves an object from the cache or calls the lambda to compute it if not found. The computation is not synchronized and cannot be done twice. It is assumed that the cached value is never null.
getInCacheOrCompute
Retrieves an object from the cache or calls the lambda to compute it if not found. The computation is not synchronized and can be done twice. The cached value could be null.
Atoti plugin injection
Here are the utility functions used to inject beans into Atoti plugins. To be injected, the plugin must follow this pattern:
public abstract class FXPostProcessor extends ADynamicAggregationPostProcessor implements IFXRatesAware {
IFxRates fxRates;
@Override
public void setFxRates(IFxRates fxRates) {
this.fxRates = fxRates;
}
}
The Aware
interface must follow this specific pattern:
public interface IFXRatesAware {
// This is used to find the setter, the value must match.
// The name of the constant (PROPERTY_NAME) is also fixed.
String PROPERTY_NAME = "FxRates";
void setFxRates(IFxRates fxRates);
}
injectAll
Injects a bean to all plugins.
injectAllExtendedPlugin
Injects into extended plugins.
injectAllPlugin
Injects into simple plugins.
dateSearch
Finds the first available date matching the requirements. It calls the lambda to perform an initial date step and then again every time the result value is null.
The function IStepDate::stepDate
provides a useful stepper feature that steps from one asOfDate to another inside a table.
var fx = dateSearch(
asOfDate,
(date, first) -> myFunctionThatMoveToTheRightDate(date, first),
maxFallbackDays,
date -> myFunctionThatReturnTheValueOrNullIfNotAvailable());
Post-processor helpers
hasANullEntry
Checks that an input value is null. It is useful for Copper::map
or the post-processor compute phase.
return Copper.combine(topPnL, childPnL, timePeriod, roundingMethod, quuantile2Rank)
.map((reader, writer) -> {
if(hasANullEntry(reader, 0, 1, 3, 4)) {
writer.writeNull();
} else {
writer.writeDouble(componentVaR(reader));
}}, ILiteralType.DOUBLE);
checkOutputType
The type must be set for every post-processor. However, for most of them the type is fixed and can’t be changed. So this method should be used inside a post-processor to check that the specified type is the expected one.
@QuartetExtendedPluginValue(intf = IPostProcessor.class, key = PLUGIN_KEY)
public class MyPostProcessor extends ABasicPostProcessor {
@Override public void init(Properties properties) throws ActiveViamException {
PostProcessorUtils.checkOutputType(properties, ILiteralType.DOUBLE);
super.init(properties);
}
}
checkLeafType
For dynamic post-processors, the leaf must also be typed. So this method should be used inside a post-processor to check that the specified type is the expected one.
@QuartetExtendedPluginValue(intf = IPostProcessor.class, key = PLUGIN_KEY)
public class MyPostProcessor extends ABasicPostProcessor {
@Override public void init(Properties properties) throws ActiveViamException {
PostProcessorUtils.checkOutputType(properties, ILiteralType.DOUBLE);
PostProcessorUtils.checkLeafType(properties, ILiteralType.DOUBLE);
super.init(properties);
}
}
checkPassThroughUnderlyingType
When a post-processor only has a single parameter it may return a metric of the same type as the underlying parameter. This function checks that the types match.
Use the function as follows:
@QuartetExtendedPluginValue(intf = IPostProcessor.class, key = PLUGIN_KEY)
public class MyPostProcessor extends ABasicPostProcessor {
@Override
protected int computeOutputType(final @NonNull Properties properties) throws PostProcessorInitializationException {
return checkPassThroughUnderlyingType(getMeasuresProvider(), underlyingMeasures.get(0), super.computeOutputType(properties));
}
}
getDictionary
In the latest version of Atoti, the datastore dictionaries are hidden. This method can be used to access them.
toFieldPath
This function is the reverse of FieldPath::toString
. It can be used to stream out a FieldPath.
getKeyFields
This function returns the positions of the key fields inside a table. It can be used to extract the key from a tuple.
transfer
This is a set of functions that are intended to copy a value from one holder to another by taking case of its type. It can copy :
- From a
IRecordReader
slot to aIWritableCell
- From a
IArrayReader
slot to aIWritableCell
- From a
IArrayReader
slot to another slot on aIArrayWriter
registerExtraLeafs
This function is intended to be called on the init phase of a postprocessor just before the call of the super init. It will add some extra required field required by the extra leaf coordinate feature. Here is a sample :
@QuartetExtendedPluginValue(intf = IPostProcessor.class, key = MyPostProcessor.PLUGIN_KEY)
public class MyPostProcessor extends ADynamicAggregationPostProcessor implements ICustomParametersAware {
protected ICustomParameters customParameters;
protected LocationFunction locationFunction;
@Override
public void init(Properties properties) throws ActiveViamException {
locationFunction = (customParameters != null) ? customParameters.getLeafCoordinatesFunction(pivot, properties, getType()) : null;
var orgLeafs = PostProcessorUtils.registerExtraLeafs(locationFunction, pivot, properties);
super.init(properties);
// Extra setup
// orgLeaf contains the leafs passed to the PP in its properties
}
@Override
public void setCustomParameters(ICustomParameters customParameters) {
this.customParameters = customParameters;
}
@Override
protected void evaluateLeaf(@NonNull ILocation leafLocation, @NonNull IRecordReader underlyingMeasures, @NonNull IWritableCell resultCell) {
var leafCoordinates = locationFunction != null ? locationFunction.apply(leafLocation, getQueryCache()) : List.of();
// Call a service that requires leafCoordinates as a parameter
}
}