/* (C) ActiveViam 2020
* ALL RIGHTS RESERVED. This material is the CONFIDENTIAL and PROPRIETARY
* property of ActiveViam Ltd. Any unauthorized use,
* reproduction or transfer of this material is strictly prohibited
*/
package com.activeviam.biz.pivot.filtering.impl;
import com.activeviam.fwk.ActiveViamException;
import com.activeviam.pivot.postprocessing.impl.AAdvancedPostProcessor;
import com.qfs.literal.ILiteralType;
import com.qfs.util.impl.QfsArrays;
import com.quartetfs.biz.pivot.ILocation;
import com.quartetfs.biz.pivot.cellset.IAggregatesRetrievalResult;
import com.quartetfs.biz.pivot.context.subcube.ICubeFilter;
import com.quartetfs.biz.pivot.cube.hierarchy.ILevel;
import com.quartetfs.biz.pivot.cube.hierarchy.ILevelInfo;
import com.quartetfs.biz.pivot.cube.hierarchy.axis.IAxisHierarchy;
import com.quartetfs.biz.pivot.cube.hierarchy.axis.IAxisMember;
import com.quartetfs.biz.pivot.cube.hierarchy.impl.HierarchiesUtil;
import com.quartetfs.biz.pivot.cube.hierarchy.measures.IMeasureMember;
import com.quartetfs.biz.pivot.cube.hierarchy.measures.IPostProcessorCreationContext;
import com.quartetfs.biz.pivot.impl.LocationUtil;
import com.quartetfs.biz.pivot.postprocessing.IPostProcessor;
import com.quartetfs.biz.pivot.postprocessing.IPrefetcher;
import com.quartetfs.biz.pivot.query.aggregates.IAdvancedAggregatesRetriever;
import com.quartetfs.biz.pivot.query.aggregates.impl.PrefetchRequest;
import com.quartetfs.fwk.QuartetExtendedPluginValue;
import com.quartetfs.fwk.filtering.impl.InCondition;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
/**
* <b>TrendPostProcessor</b><br>
* TrendPostProcessor does the difference between today and the day before if no measure retrieved
* from the day before then return null.
*
* @author ActiveViam
*/
@QuartetExtendedPluginValue(intf = IPostProcessor.class, key = TrendPostProcessor.PLUGIN_KEY)
public class TrendPostProcessor extends AAdvancedPostProcessor {
protected static final long serialVersionUID = 2722596108421670864L;
public static final String PLUGIN_KEY = "TREND";
public static final String LEVEL_DESCRIPTION_PROPERTY = "LEVEL";
public static final String HIERARCHY_DESCRIPTION_PROPERTY = "HIERARCHY";
protected static final String INCLUDE_PREFETCHER = "INCLUDE_PREFETCHER";
protected ILevelInfo levelInfo = null;
protected IAxisHierarchy hierarchy = null;
protected Set<IMeasureMember> measures;
public TrendPostProcessor(
final String name, final IPostProcessorCreationContext creationContext) {
super(name, creationContext);
}
@Override
public void init(final Properties properties) throws ActiveViamException {
properties.setProperty(OUTPUT_TYPE, ILiteralType.DOUBLE);
super.init(properties);
final String levelDescription = properties.getProperty(LEVEL_DESCRIPTION_PROPERTY);
final ILevel level = HierarchiesUtil.getLevel(getActivePivot(), levelDescription);
this.levelInfo = level.getLevelInfo();
// below required for prefetching
this.measures =
this.underlyingMeasures.stream()
.map(measureName -> this.measuresProvider.getMeasure(measureName))
.collect(Collectors.toSet());
// get the IHierarchy needed instance
final String hierarchyDescription = properties.getProperty(HIERARCHY_DESCRIPTION_PROPERTY);
this.hierarchy =
(IAxisHierarchy) HierarchiesUtil.getHierarchy(getActivePivot(), hierarchyDescription);
}
@Override
protected List<IPrefetcher<?>> initializePrefetchers(Properties properties) {
final IPrefetcher<?> prefetcher =
(location, filter) ->
Collections.singleton(
new PrefetchRequest<>(
computeLocation(location), computeFilter(location, filter), measures));
return QfsArrays.mutableList(IPrefetcher.name(INCLUDE_PREFETCHER, prefetcher));
}
protected ICubeFilter computeFilter(final ILocation location, final ICubeFilter queryFilter) {
final Object value = LocationUtil.getCoordinate(location, levelInfo);
ICubeFilter filter = queryFilter;
if (value == null) {
// we deal with a range location here, we add all the required
// members and edit the filter
final List<? extends IAxisMember> members =
queryFilter.retrieveMembers(hierarchy, levelInfo.getOrdinal());
final Set<Date> membersToInclude = new HashSet<>();
for (final IAxisMember member : members) {
membersToInclude.add((Date) member.getDiscriminator());
membersToInclude.add(TrainingUtils.retrievePreviousDate((Date) member.getDiscriminator()));
}
filter =
queryFilter
.edit()
.includeMembersWithConditions(
levelInfo.getHierarchyInfo(), new InCondition(membersToInclude))
.build();
}
return filter;
}
protected ILocation computeLocation(final ILocation location) {
final Object value = LocationUtil.getCoordinate(location, levelInfo);
if (value instanceof Date) {
// we deal with a point location here
// build range location with previous date,
// use a Set having current and previous dates
final Set<Object> dates = new HashSet<>();
dates.add(value);
dates.add(TrainingUtils.retrievePreviousDate((Date) value));
return createModifiedLocation(location, dates);
}
// nothing to do here as we deal with a range location
return location;
}
protected ILocation createModifiedLocation(final ILocation location, final Object membersToAdd) {
if (LocationUtil.isAtLevel(location, levelInfo)) {
final Object[] newMembers = LocationUtil.copyPath(location, levelInfo.getHierarchyInfo());
newMembers[levelInfo.getOrdinal()] = membersToAdd;
return LocationUtil.createModifiedLocation(
location, levelInfo.getHierarchyInfo(), newMembers);
}
return location;
}
@Override
public void compute(final ILocation location, final IAdvancedAggregatesRetriever retriever) {
final IAggregatesRetrievalResult results = retriever.retrieveAggregates(INCLUDE_PREFETCHER);
final int measureForResults = results.getMeasureId(underlyingMeasures.get(0));
results.forEachPoint(
(pointReader, rowId) -> {
final int rowIdPrevious = results.getRow(retrievePreviousDateLocation(pointReader));
final Double currentValue;
final Double previousValue;
if (rowIdPrevious != -1) { // -1 if the point does not exist
currentValue = (Double) results.read(rowId, measureForResults);
previousValue = (Double) results.read(rowIdPrevious, measureForResults);
if (currentValue != null && previousValue != null) {
retriever.write(retriever.addPoint(pointReader), currentValue - previousValue);
}
}
return true;
});
}
protected ILocation retrievePreviousDateLocation(final ILocation currentLocation) {
final Date currentDate = (Date) LocationUtil.getCoordinate(currentLocation, levelInfo);
return createModifiedLocation(currentLocation, TrainingUtils.retrievePreviousDate(currentDate));
}
@Override
public String getType() {
return PLUGIN_KEY;
}
}