package com.insightfullogic.honest_profiler.core.aggregation.aggregator;
import static java.util.stream.Collector.of;
import static java.util.stream.Collectors.groupingBy;
import java.util.Map;
import com.insightfullogic.honest_profiler.core.aggregation.AggregationProfile;
import com.insightfullogic.honest_profiler.core.aggregation.grouping.CombinedGrouping;
import com.insightfullogic.honest_profiler.core.aggregation.result.Aggregation;
import com.insightfullogic.honest_profiler.core.aggregation.result.Keyed;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Entry;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Node;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Tree;
import com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode;
/**
* Aggregator which takes an {@link Entry} and aggregates the descendants of all the {@link LeanNode}s aggregated by
* that {@link Entry} into a {@link Tree}.
*/
public class DescendantTreeAggregator implements SubAggregator<Entry, Node>
{
// Aggregator Implementation
/**
* @see SubAggregator#aggregate(Object)
*/
@Override
public Tree aggregate(Entry input)
{
Aggregation<Keyed<String>> aggregation = input.getAggregation();
AggregationProfile source = aggregation.getSource();
CombinedGrouping grouping = aggregation.getGrouping();
Tree result = new Tree(source, input.getAggregation().getGrouping());
Node root = new Node(input);
result.getData().add(root);
addChildren(source, root, result, grouping);
return result;
}
/**
* Recursive method for aggregating the children (and descendants) of the {@link LeanNode}s which are aggregated by
* the provided {@link Node}.
* <p>
* @param source the original {@link AggregationProfile}
* @param child the input {@link Node}
* @param tree the resulting {@link Tree}
* @param grouping the key calculation grouping
*/
private void addChildren(AggregationProfile source, Node child, Tree tree,
CombinedGrouping grouping)
{
Map<String, Node> result = child.getAggregatedNodes().stream()
// Create a stream of all LeanNodes aggregated by the Entry, and aggregate according to the Grouping
.flatMap(node -> node.getChildren().stream())
.collect(groupingBy(
// Group LeanNodes by calculated key
node -> grouping.apply(source, node),
// Downstream collector, collects LeanNodes in a single group
of(
// Supplier, creates an empty Node
() ->
{
Node node = new Node(tree);
// Set the reference by default for all nodes to the global aggregation.
node.setReference(source.getGlobalData());
return node;
},
// Accumulator, aggregates a LeanNode into the Node accumulator
(x, y) ->
{
x.add(y);
x.setKey(grouping.apply(source, y));
},
// Combiner, combines two Nodes with the same key
(x, y) -> x.combine(y)
)
));
// Add the aggregated children as children to the Node, and recurse
result.values().forEach(parent ->
{
child.addChild(parent);
// Recursively add descendants
addChildren(source, parent, tree, grouping);
});
}
}