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.straight.Node; import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Tree; import com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode; import com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile; /** * Aggregator which takes an {@link AggregationProfile}, and uses the data to aggregate the values into a {@link Tree}. */ public class TreeProfileAggregator implements ProfileAggregator<Node> { // Aggregator Implementation /** * Aggregates an {@link AggregationProfile} into a {@link Tree}. The {@link CombinedGrouping} specifies which * {@link LeanNode}s are aggregated together. * * @see ProfileAggregator#aggregate(AggregationProfile, CombinedGrouping) */ @Override public Tree aggregate(AggregationProfile input, CombinedGrouping grouping) { // Prepare result. Tree result = new Tree(input, grouping); LeanProfile profile = input.getSource(); Map<String, Node> nodeMap = profile.getThreads().values().stream().collect( groupingBy( // Group LeanNodes by calculated key node -> grouping.apply(input, node), // Downstream collector, aggregates LeanNodes in a single group of( // Supplier, creates an empty Node () -> new Node(result), // Accumulator, aggregates a LeanNode into the Node accumulator (node, leanNode) -> { node.add(leanNode); node.setKey(grouping.apply(input, leanNode)); // Aggregate descendants of a LeanNode recursively into children of accumulator. The recursion // happens inside the Node.addChild() method, triggered by the boolean parameter. leanNode.getChildren() .forEach(child -> node.addChild(child, grouping, true)); }, // Combiner, combines two Nodes with the same key (node1, node2) -> node1.combine(node2) ) ) ); // Set the reference by default for all nodes to the global aggregation. // We do this here because the addChild() method doesn't propagate the reference, and proably shouldn't. nodeMap.values().stream().flatMap(Node::flatten).forEach(node -> { node.setReference(input.getGlobalData()); }); result.getData().addAll(nodeMap.values()); return result; } }