Search in sources :

Example 6 with JexlNodes.children

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;
}
Also used : ASTOrNode(org.apache.commons.jexl2.parser.ASTOrNode) ArrayList(java.util.ArrayList) JexlNode(org.apache.commons.jexl2.parser.JexlNode) ASTAndNode(org.apache.commons.jexl2.parser.ASTAndNode)

Example 7 with JexlNodes.children

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;
}
Also used : ASTOrNode(org.apache.commons.jexl2.parser.ASTOrNode) JexlNode(org.apache.commons.jexl2.parser.JexlNode) BoundedRange(datawave.query.jexl.nodes.BoundedRange) ASTAndNode(org.apache.commons.jexl2.parser.ASTAndNode)

Example 8 with JexlNodes.children

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()]));
            }
        }
    }
}
Also used : ASTTrueNode(org.apache.commons.jexl2.parser.ASTTrueNode) ArrayList(java.util.ArrayList) JexlNode(org.apache.commons.jexl2.parser.JexlNode)

Example 9 with JexlNodes.children

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);
}
Also used : ASTReferenceExpression(org.apache.commons.jexl2.parser.ASTReferenceExpression) ArrayList(java.util.ArrayList) JexlNode(org.apache.commons.jexl2.parser.JexlNode) ASTReference(org.apache.commons.jexl2.parser.ASTReference)

Example 10 with JexlNodes.children

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;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ASTFunctionNode(org.apache.commons.jexl2.parser.ASTFunctionNode) ASTEQNode(org.apache.commons.jexl2.parser.ASTEQNode) ExceededValueThresholdMarkerJexlNode(datawave.query.jexl.nodes.ExceededValueThresholdMarkerJexlNode) JexlNode(org.apache.commons.jexl2.parser.JexlNode) JexlArgumentDescriptor(datawave.query.jexl.functions.arguments.JexlArgumentDescriptor) LiteralRange(datawave.query.jexl.LiteralRange) ASTAndNode(org.apache.commons.jexl2.parser.ASTAndNode)

Aggregations

JexlNode (org.apache.commons.jexl2.parser.JexlNode)14 ArrayList (java.util.ArrayList)8 ASTAndNode (org.apache.commons.jexl2.parser.ASTAndNode)7 ASTOrNode (org.apache.commons.jexl2.parser.ASTOrNode)6 ExceededValueThresholdMarkerJexlNode (datawave.query.jexl.nodes.ExceededValueThresholdMarkerJexlNode)3 LinkedList (java.util.LinkedList)3 ASTReference (org.apache.commons.jexl2.parser.ASTReference)3 ASTReferenceExpression (org.apache.commons.jexl2.parser.ASTReferenceExpression)3 BoundedRange (datawave.query.jexl.nodes.BoundedRange)2 List (java.util.List)2 ASTEQNode (org.apache.commons.jexl2.parser.ASTEQNode)2 ASTFunctionNode (org.apache.commons.jexl2.parser.ASTFunctionNode)2 IpAddressType (datawave.data.type.IpAddressType)1 Type (datawave.data.type.Type)1 DatawaveFatalQueryException (datawave.query.exceptions.DatawaveFatalQueryException)1 ContainerType (datawave.query.jexl.JexlNodeFactory.ContainerType)1 LiteralRange (datawave.query.jexl.LiteralRange)1 JexlArgumentDescriptor (datawave.query.jexl.functions.arguments.JexlArgumentDescriptor)1 QueryException (datawave.webservice.query.exception.QueryException)1 LinkedHashMap (java.util.LinkedHashMap)1