/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.queryparser.flexible.core.processors;

import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;

This is a default implementation for the QueryNodeProcessor interface, it's an abstract class, so it should be extended by classes that want to process a QueryNode tree.

This class process QueryNodes from left to right in the tree. While it's walking down the tree, for every node, preProcessNode(QueryNode) is invoked. After a node's children are processed, postProcessNode(QueryNode) is invoked for that node. setChildrenOrder(List<QueryNode>) is invoked before postProcessNode(QueryNode) only if the node has at least one child, in setChildrenOrder(List<QueryNode>) the implementor might redefine the children order or remove any children from the children list.

Here is an example about how it process the nodes:

     a
    / \
   b   e
  / \
 c   d
Here is the order the methods would be invoked for the tree described above:
     preProcessNode( a );
     preProcessNode( b );
     preProcessNode( c );
     postProcessNode( c );
     preProcessNode( d );
     postProcessNode( d );
     setChildrenOrder( bChildrenList );
     postProcessNode( b );
     preProcessNode( e );
     postProcessNode( e );
     setChildrenOrder( aChildrenList );
     postProcessNode( a )
See Also:
/** * <p> * This is a default implementation for the {@link QueryNodeProcessor} * interface, it's an abstract class, so it should be extended by classes that * want to process a {@link QueryNode} tree. * </p> * <p> * This class process {@link QueryNode}s from left to right in the tree. While * it's walking down the tree, for every node, * {@link #preProcessNode(QueryNode)} is invoked. After a node's children are * processed, {@link #postProcessNode(QueryNode)} is invoked for that node. * {@link #setChildrenOrder(List)} is invoked before * {@link #postProcessNode(QueryNode)} only if the node has at least one child, * in {@link #setChildrenOrder(List)} the implementor might redefine the * children order or remove any children from the children list. * </p> * <p> * Here is an example about how it process the nodes: * </p> * * <pre> * a * / \ * b e * / \ * c d * </pre> * * Here is the order the methods would be invoked for the tree described above: * * <pre> * preProcessNode( a ); * preProcessNode( b ); * preProcessNode( c ); * postProcessNode( c ); * preProcessNode( d ); * postProcessNode( d ); * setChildrenOrder( bChildrenList ); * postProcessNode( b ); * preProcessNode( e ); * postProcessNode( e ); * setChildrenOrder( aChildrenList ); * postProcessNode( a ) * </pre> * * @see org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessor */
public abstract class QueryNodeProcessorImpl implements QueryNodeProcessor { private ArrayList<ChildrenList> childrenListPool = new ArrayList<>(); private QueryConfigHandler queryConfig; public QueryNodeProcessorImpl() { // empty constructor } public QueryNodeProcessorImpl(QueryConfigHandler queryConfigHandler) { this.queryConfig = queryConfigHandler; } @Override public QueryNode process(QueryNode queryTree) throws QueryNodeException { return processIteration(queryTree); } private QueryNode processIteration(QueryNode queryTree) throws QueryNodeException { queryTree = preProcessNode(queryTree); processChildren(queryTree); queryTree = postProcessNode(queryTree); return queryTree; }
This method is called every time a child is processed.
Params:
  • queryTree – the query node child to be processed
Throws:
/** * This method is called every time a child is processed. * * @param queryTree * the query node child to be processed * @throws QueryNodeException * if something goes wrong during the query node processing */
protected void processChildren(QueryNode queryTree) throws QueryNodeException { List<QueryNode> children = queryTree.getChildren(); ChildrenList newChildren; if (children != null && children.size() > 0) { newChildren = allocateChildrenList(); try { for (QueryNode child : children) { child = processIteration(child); if (child == null) { throw new NullPointerException(); } newChildren.add(child); } List<QueryNode> orderedChildrenList = setChildrenOrder(newChildren); queryTree.set(orderedChildrenList); } finally { newChildren.beingUsed = false; } } } private ChildrenList allocateChildrenList() { ChildrenList list = null; for (ChildrenList auxList : this.childrenListPool) { if (!auxList.beingUsed) { list = auxList; list.clear(); break; } } if (list == null) { list = new ChildrenList(); this.childrenListPool.add(list); } list.beingUsed = true; return list; }
For reference about this method check: QueryNodeProcessor.setQueryConfigHandler(QueryConfigHandler).
Params:
  • queryConfigHandler – the query configuration handler to be set.
See Also:
/** * For reference about this method check: * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}. * * @param queryConfigHandler * the query configuration handler to be set. * * @see QueryNodeProcessor#getQueryConfigHandler() * @see QueryConfigHandler */
@Override public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) { this.queryConfig = queryConfigHandler; }
For reference about this method check: QueryNodeProcessor.getQueryConfigHandler().
See Also:
Returns:QueryConfigHandler the query configuration handler to be set.
/** * For reference about this method check: * {@link QueryNodeProcessor#getQueryConfigHandler()}. * * @return QueryConfigHandler the query configuration handler to be set. * * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler) * @see QueryConfigHandler */
@Override public QueryConfigHandler getQueryConfigHandler() { return this.queryConfig; }
This method is invoked for every node when walking down the tree.
Params:
  • node – the query node to be pre-processed
Throws:
Returns:a query node
/** * This method is invoked for every node when walking down the tree. * * @param node * the query node to be pre-processed * * @return a query node * * @throws QueryNodeException * if something goes wrong during the query node processing */
abstract protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException;
This method is invoked for every node when walking up the tree.
Params:
  • node – node the query node to be post-processed
Throws:
Returns:a query node
/** * This method is invoked for every node when walking up the tree. * * @param node * node the query node to be post-processed * * @return a query node * * @throws QueryNodeException * if something goes wrong during the query node processing */
abstract protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException;
This method is invoked for every node that has at least on child. It's invoked right before postProcessNode(QueryNode) is invoked.
Params:
  • children – the list containing all current node's children
Throws:
Returns:a new list containing all children that should be set to the current node
/** * This method is invoked for every node that has at least on child. It's * invoked right before {@link #postProcessNode(QueryNode)} is invoked. * * @param children * the list containing all current node's children * * @return a new list containing all children that should be set to the * current node * * @throws QueryNodeException * if something goes wrong during the query node processing */
abstract protected List<QueryNode> setChildrenOrder(List<QueryNode> children) throws QueryNodeException; private static class ChildrenList extends ArrayList<QueryNode> { boolean beingUsed; } }