use of org.apache.commons.jexl2.parser.JexlNodes.children in project datawave by NationalSecurityAgency.
the class ExecutableExpansionVisitor method distribute.
/**
* Distribute a parent andNode into the orNode, using the andNodeChild to determine which children of the andNode should be distributed and which contain
* the orNode. orNode should have been passed to canExpand() and returned true prior to calling.
*
* @param andNode
* the first andNode parent from the orNode
* @param andNodeChild
* the direct child of the andNode that is also a parent of orNode
* @param orNode
* the orNode to distribute the andNode into
* @return a new orNode to be substituted for the andNode in the original query tree with a logically equivalent (and executable) state
* @throws IllegalStateException
* if a single node path can't be traced between the andNode and orNode
*/
private ASTOrNode distribute(ASTAndNode andNode, JexlNode andNodeChild, ASTOrNode orNode) {
// hold the list of nodes that are to be distributed into the orNode grab everything in the and that isn't the branch to be expanded into
List<JexlNode> otherNodes = new ArrayList<>(andNode.jjtGetNumChildren() - 1);
for (int i = 0; i < andNode.jjtGetNumChildren(); i++) {
JexlNode candidate = andNode.jjtGetChild(i);
if (candidate != andNodeChild) {
otherNodes.add(candidate);
}
}
// create a top level orNode to join together the distributed elements
ASTOrNode newOr = new ASTOrNode(ParserTreeConstants.JJTORNODE);
// single child check if there is a set of nodes between the child and orNode that need to be passed along
if (andNodeChild == orNode) {
// clear the child, its the same as the orNode and there is nothing to bridge
andNodeChild = null;
} else if (orNode.jjtGetParent().jjtGetNumChildren() == 1) {
// replace the orNode with a null so it won't be copied below
JexlNodes.children(orNode.jjtGetParent(), new JexlNode[0]);
} else {
// log an error and abort the distribute, this should never happen
log.warn("Unexpected number of children on the orNode parent, expected 1 got " + orNode.jjtGetParent().jjtGetNumChildren() + " aborting distribute");
throw new IllegalStateException("Unexpected number of children on the orNode parent, expected 1 got " + orNode.jjtGetParent().jjtGetNumChildren() + " aborting distribute");
}
// fetch the minimal expansion terms instead of expanding everything
List<JexlNode> orTerms = getOrTerms(orNode, andNodeChild);
// everything goes together, abort
if (orTerms.size() == 1) {
return null;
}
// expand each expansion term
for (int i = 0; i < orTerms.size(); i++) {
// hold the new combined terms
ASTAndNode newAnd = new ASTAndNode(ParserTreeConstants.JJTANDNODE);
// get new term, unwrapping it as necessary
JexlNode term = JexlASTHelper.dereferenceSafely(orTerms.get(i));
// link the new andNode and the old orNode
newAnd.jjtAddChild(term, 0);
term.jjtSetParent(newAnd);
// make a copy of each otherNode and add them to the newAnd
int otherNodeCount = 0;
for (JexlNode otherNode : otherNodes) {
JexlNode copy = RebuildingVisitor.copy(otherNode);
copy.jjtSetParent(newAnd);
newAnd.jjtAddChild(copy, otherNodeCount + 1);
otherNodeCount++;
}
// attach newAnd to the newOr
newAnd.jjtSetParent(newOr);
newOr.jjtAddChild(newAnd, newOr.jjtGetNumChildren());
}
return newOr;
}
use of org.apache.commons.jexl2.parser.JexlNodes.children in project datawave by NationalSecurityAgency.
the class QueryModelVisitor method expandRangeNodeFromModel.
public Object expandRangeNodeFromModel(LiteralRange range, ASTAndNode node, Object data) {
if (isFieldExcluded(range.getFieldName())) {
return node;
}
// this is the set of fields that have an upper and a lower bound operand
// make a copy of the intersection, as I will be modifying lowererBounds and upperBounds below
List<JexlNode> aliasedBounds = Lists.newArrayList();
Collection<String> aliases = getAliasesForField(range.getFieldName());
if (aliases.isEmpty()) {
aliases = Lists.newArrayList(range.getFieldName());
}
for (String alias : aliases) {
if (alias != null) {
BoundedRange rangeNode = BoundedRange.create(JexlNodes.children(new ASTAndNode(ParserTreeConstants.JJTANDNODE), JexlASTHelper.setField(RebuildingVisitor.copy(range.getLowerNode()), alias), JexlASTHelper.setField(RebuildingVisitor.copy(range.getUpperNode()), alias)));
aliasedBounds.add(rangeNode);
this.expandedNodes.add((ASTAndNode) JexlASTHelper.dereference(rangeNode));
}
}
JexlNode nodeToAdd;
if (1 == aliasedBounds.size()) {
nodeToAdd = JexlASTHelper.dereference(aliasedBounds.get(0));
} else {
ASTOrNode unionOfAliases = new ASTOrNode(ParserTreeConstants.JJTORNODE);
nodeToAdd = JexlNodes.children(unionOfAliases, aliasedBounds.toArray(new JexlNode[aliasedBounds.size()]));
}
return nodeToAdd;
}
use of org.apache.commons.jexl2.parser.JexlNodes.children in project datawave by NationalSecurityAgency.
the class QueryPruningVisitor method replaceAndAssign.
/**
* Prune a tree, optionally with an assignment showing the portion of the tree that was pruned. This will be more verbose, but will clearly identify what
* was removed. Only remove a node if rewrite is enabled, only write an assignment node showing the pruned tree is queryString is not null
*
* @param toReplace
* the node to replace in the tree with an assignment
* @param queryString
* the string to use if building an assignment node for the portion of the tree that was pruned, may be null
* @param baseReplacement
* what to replace toReplace with
*/
private void replaceAndAssign(JexlNode toReplace, String queryString, JexlNode baseReplacement) {
if (rewrite && toReplace != null) {
JexlNode parent = toReplace.jjtGetParent();
if (parent != null && parent != toReplace) {
if (queryString != null && log.isDebugEnabled()) {
if (this.debugPrune && baseReplacement != null) {
log.debug("Pruning " + queryString + " to " + (baseReplacement instanceof ASTTrueNode ? "true" : "false"));
}
}
if (baseReplacement != null) {
JexlNodes.swap(parent, toReplace, baseReplacement);
} else {
// remove the node entirely
List<JexlNode> children = new ArrayList<>(parent.jjtGetNumChildren() - 1);
for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
JexlNode child = parent.jjtGetChild(i);
if (child != toReplace) {
children.add(child);
} else {
// clear the old nodes parentage
child.jjtSetParent(null);
}
}
JexlNodes.children(parent, children.toArray(new JexlNode[children.size()]));
}
}
}
}
use of org.apache.commons.jexl2.parser.JexlNodes.children in project datawave by NationalSecurityAgency.
the class DistributeAndedNodesVisitor method visit.
/**
* Checks each of the child nodes, and determines how the anded nodes should be applied.
*
* @param node
* The node that we will be distributing the anded nodes into
* @param data
* The nodes which we will be distributing into the root node
* @return An updated script with the anded nodes distributed throughout
*/
@Override
public Object visit(ASTAndNode node, Object data) {
DistributeAndedNodesVisitor.DistAndData parentData = (DistributeAndedNodesVisitor.DistAndData) data;
if (initialNode == null || initialNode instanceof ASTReference || initialNode instanceof ASTReferenceExpression)
initialNode = node;
// if this node is one of the anded nodes, or a whindex
// comprised of one of the anded nodes, halt recursion
List<JexlNode> usedAndedNodes = usesAndedNodes(node);
if (!usedAndedNodes.isEmpty()) {
parentData.usedAndedNodes.addAll(usedAndedNodes);
return node;
}
// this logic is dependent upon identifying whindex nodes by their address
if (whindexNodes.containsKey(node)) {
return node;
}
// check each child node to see how many of the desired andedNodes are present
List<JexlNode> rebuiltChildren = new ArrayList<>();
for (JexlNode child : JexlNodes.children(node)) {
DistributeAndedNodesVisitor.DistAndData foundData = new DistributeAndedNodesVisitor.DistAndData();
rebuiltChildren.add((JexlNode) child.jjtAccept(this, foundData));
parentData.usedAndedNodes.addAll(foundData.usedAndedNodes);
}
// are some anded nodes missing, and is this the initial node?
if (!parentData.usedAndedNodes.containsAll(andedNodes) && node.equals(initialNode)) {
// 'and' with the missing anded nodes, and return
List<JexlNode> nodes = andedNodes.stream().filter(andedNode -> !parentData.usedAndedNodes.contains(andedNode)).map(RebuildingVisitor::copy).collect(Collectors.toList());
nodes.add(node);
// this is probably unnecessary, but to be safe, let's set it
parentData.usedAndedNodes.addAll(andedNodes);
return WhindexVisitor.createUnwrappedAndNode(nodes);
}
return WhindexVisitor.createUnwrappedAndNode(rebuiltChildren);
}
use of org.apache.commons.jexl2.parser.JexlNodes.children in project datawave by NationalSecurityAgency.
the class WhindexVisitor method getLeafNodes.
/**
* This method checks each of the child nodes, and returns those which are leaf nodes. Range nodes are also considered leaf nodes for our purposes. If the
* root node is a range node, then that node will be returned. Reference, ReferenceExpression, and 'and' or 'or' nodes with a single child are passed
* through in search of the actual leaf node.
*
* @param rootNode
* The node whose children we will check
* @param otherNodes
* Non-leaf child nodes of the root node
* @return A multimap of field name to leaf node
*/
private Multimap<String, JexlNode> getLeafNodes(JexlNode rootNode, Collection<JexlNode> otherNodes) {
Multimap<String, JexlNode> childrenLeafNodes = ArrayListMultimap.create();
if (rootNode instanceof ASTAndNode) {
// check to see if this node is a range node, if so, this is our leaf node
JexlNode leafKid = getLeafNode(rootNode);
if (leafKid != null) {
String kidFieldName;
LiteralRange range = JexlASTHelper.findRange().getRange(leafKid);
kidFieldName = (range != null) ? range.getFieldName() : JexlASTHelper.getIdentifier(leafKid);
childrenLeafNodes.put(kidFieldName, rootNode);
}
}
if (childrenLeafNodes.isEmpty()) {
for (JexlNode child : JexlNodes.children(rootNode)) {
JexlNode leafKid = getLeafNode(child);
if (leafKid != null) {
Set<String> kidFieldNames = new LinkedHashSet<>();
LiteralRange range = JexlASTHelper.findRange().getRange(leafKid);
if (range != null) {
kidFieldNames.add(range.getFieldName());
} else {
if (leafKid instanceof ASTEQNode) {
kidFieldNames.add(JexlASTHelper.getIdentifier(leafKid));
} else if (leafKid instanceof ASTFunctionNode) {
JexlArgumentDescriptor descriptor = JexlFunctionArgumentDescriptorFactory.F.getArgumentDescriptor((ASTFunctionNode) leafKid);
if (descriptor instanceof GeoWaveFunctionsDescriptor.GeoWaveJexlArgumentDescriptor || descriptor instanceof GeoFunctionsDescriptor.GeoJexlArgumentDescriptor) {
kidFieldNames.addAll(descriptor.fields(metadataHelper, Collections.emptySet()));
} else {
if (otherNodes != null) {
otherNodes.add(child);
}
}
}
}
for (String kidFieldName : kidFieldNames) {
// note: we save the actual direct sibling of the and node, including
// any reference nodes. those will be trimmed off later
childrenLeafNodes.put(kidFieldName, child);
}
} else {
if (otherNodes != null)
otherNodes.add(child);
}
}
}
return childrenLeafNodes;
}
Aggregations