com.espertech.esper.epl.join.assemble.BaseAssemblyNodeFactory Maven / Gradle / Ivy
Show all versions of esper Show documentation
/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.epl.join.assemble;
import com.espertech.esper.util.IndentWriter;
import java.util.*;
/**
* Represents the factory of a node in a tree responsible for assembling outer join query results.
*
* The tree of factory nodes is double-linked, child nodes know each parent and parent know all child nodes.
*/
public abstract class BaseAssemblyNodeFactory {
/**
* Parent node.
*/
protected BaseAssemblyNodeFactory parentNode;
/**
* Child nodes.
*/
protected final List childNodes;
/**
* Stream number.
*/
protected final int streamNum;
/**
* Number of streams in statement.
*/
protected final int numStreams;
/**
* Ctor.
*
* @param streamNum - stream number of the event stream that this node assembles results for.
* @param numStreams - number of streams
*/
protected BaseAssemblyNodeFactory(int streamNum, int numStreams) {
this.streamNum = streamNum;
this.numStreams = numStreams;
childNodes = new ArrayList(4);
}
public abstract BaseAssemblyNode makeAssemblerUnassociated();
/**
* Output this node using writer, not outputting child nodes.
*
* @param indentWriter to use for output
*/
public abstract void print(IndentWriter indentWriter);
/**
* Set parent node.
*
* @param parent parent node
*/
public void setParent(BaseAssemblyNodeFactory parent) {
this.parentNode = parent;
}
public BaseAssemblyNodeFactory getParentNode() {
return parentNode;
}
/**
* Add a child node.
*
* @param childNode to add
*/
public void addChild(BaseAssemblyNodeFactory childNode) {
childNode.parentNode = this;
childNodes.add(childNode);
}
/**
* Returns the stream number.
*
* @return stream number
*/
protected int getStreamNum() {
return streamNum;
}
/**
* Returns child nodes.
*
* @return child nodes
*/
public List getChildNodes() {
return childNodes;
}
/**
* Output this node and all descendent nodes using writer, outputting child nodes.
*
* @param indentWriter to output to
*/
public void printDescendends(IndentWriter indentWriter) {
this.print(indentWriter);
for (BaseAssemblyNodeFactory child : childNodes) {
indentWriter.incrIndent();
child.print(indentWriter);
indentWriter.decrIndent();
}
}
/**
* Returns all descendent nodes to the top node in a list in which the utmost descendants are
* listed first and the top node itself is listed last.
*
* @param topNode is the root node of a tree structure
* @return list of nodes with utmost descendants first ordered by level of depth in tree with top node last
*/
public static List getDescendentNodesBottomUp(BaseAssemblyNodeFactory topNode) {
List result = new LinkedList();
// Map to hold per level of the node (1 to N depth) of node a list of nodes, if any
// exist at that level
TreeMap> nodesPerLevel = new TreeMap>();
// Recursively enter all aggregate functions and their level into map
recursiveAggregateEnter(topNode, nodesPerLevel, 1);
// Done if none found
if (nodesPerLevel.isEmpty()) {
throw new IllegalStateException("Empty collection for nodes per level");
}
// From the deepest (highest) level to the lowest, add aggregates to list
int deepLevel = nodesPerLevel.lastKey();
for (int i = deepLevel; i >= 1; i--) {
List list = nodesPerLevel.get(i);
if (list == null) {
continue;
}
result.addAll(list);
}
return result;
}
private static void recursiveAggregateEnter(BaseAssemblyNodeFactory currentNode, Map> nodesPerLevel, int currentLevel) {
// ask all child nodes to enter themselves
for (BaseAssemblyNodeFactory node : currentNode.childNodes) {
recursiveAggregateEnter(node, nodesPerLevel, currentLevel + 1);
}
// Add myself to list
List aggregates = nodesPerLevel.get(currentLevel);
if (aggregates == null) {
aggregates = new LinkedList();
nodesPerLevel.put(currentLevel, aggregates);
}
aggregates.add(currentNode);
}
}