pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / queryparser / src / java / org / apache / lucene / queryParser / core / processors / QueryNodeProcessorImpl.java
1 package org.apache.lucene.queryParser.core.processors;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.apache.lucene.queryParser.core.QueryNodeException;
24 import org.apache.lucene.queryParser.core.config.QueryConfigHandler;
25 import org.apache.lucene.queryParser.core.nodes.QueryNode;
26
27 /**
28  * <p>
29  * This is a default implementation for the {@link QueryNodeProcessor}
30  * interface, it's an abstract class, so it should be extended by classes that
31  * want to process a {@link QueryNode} tree.
32  * </p>
33  * <p>
34  * This class process {@link QueryNode}s from left to right in the tree. While
35  * it's walking down the tree, for every node,
36  * {@link #preProcessNode(QueryNode)} is invoked. After a node's children are
37  * processed, {@link #postProcessNode(QueryNode)} is invoked for that node.
38  * {@link #setChildrenOrder(List)} is invoked before
39  * {@link #postProcessNode(QueryNode)} only if the node has at least one child,
40  * in {@link #setChildrenOrder(List)} the implementor might redefine the
41  * children order or remove any children from the children list.
42  * </p>
43  * <p>
44  * Here is an example about how it process the nodes:
45  * </p>
46  * 
47  * <pre>
48  *      a
49  *     / \
50  *    b   e
51  *   / \
52  *  c   d
53  * </pre>
54  * 
55  * Here is the order the methods would be invoked for the tree described above:
56  * 
57  * <pre>
58  *      preProcessNode( a );
59  *      preProcessNode( b );
60  *      preProcessNode( c );
61  *      postProcessNode( c );
62  *      preProcessNode( d );
63  *      postProcessNode( d );
64  *      setChildrenOrder( bChildrenList );
65  *      postProcessNode( b );
66  *      preProcessNode( e );
67  *      postProcessNode( e );
68  *      setChildrenOrder( aChildrenList );
69  *      postProcessNode( a )
70  * </pre>
71  * 
72  * @see org.apache.lucene.queryParser.core.processors.QueryNodeProcessor
73  */
74 public abstract class QueryNodeProcessorImpl implements QueryNodeProcessor {
75
76   private ArrayList<ChildrenList> childrenListPool = new ArrayList<ChildrenList>();
77
78   private QueryConfigHandler queryConfig;
79
80   public QueryNodeProcessorImpl() {
81     // empty constructor
82   }
83
84   public QueryNodeProcessorImpl(QueryConfigHandler queryConfigHandler) {
85     this.queryConfig = queryConfigHandler;
86   }
87
88   public QueryNode process(QueryNode queryTree) throws QueryNodeException {
89     return processIteration(queryTree);
90   }
91
92   private QueryNode processIteration(QueryNode queryTree)
93       throws QueryNodeException {
94     queryTree = preProcessNode(queryTree);
95
96     processChildren(queryTree);
97
98     queryTree = postProcessNode(queryTree);
99
100     return queryTree;
101
102   }
103
104   /**
105    * This method is called every time a child is processed.
106    * 
107    * @param queryTree
108    *          the query node child to be processed
109    * @throws QueryNodeException
110    *           if something goes wrong during the query node processing
111    */
112   protected void processChildren(QueryNode queryTree) throws QueryNodeException {
113
114     List<QueryNode> children = queryTree.getChildren();
115     ChildrenList newChildren;
116
117     if (children != null && children.size() > 0) {
118
119       newChildren = allocateChildrenList();
120
121       try {
122
123         for (QueryNode child : children) {
124           child = processIteration(child);
125
126           if (child == null) {
127             throw new NullPointerException();
128
129           }
130
131           newChildren.add(child);
132
133         }
134
135         List<QueryNode> orderedChildrenList = setChildrenOrder(newChildren);
136
137         queryTree.set(orderedChildrenList);
138
139       } finally {
140         newChildren.beingUsed = false;
141       }
142
143     }
144
145   }
146
147   private ChildrenList allocateChildrenList() {
148     ChildrenList list = null;
149
150     for (ChildrenList auxList : this.childrenListPool) {
151
152       if (!auxList.beingUsed) {
153         list = auxList;
154         list.clear();
155
156         break;
157
158       }
159
160     }
161
162     if (list == null) {
163       list = new ChildrenList();
164       this.childrenListPool.add(list);
165
166     }
167
168     list.beingUsed = true;
169
170     return list;
171
172   }
173
174   /**
175    * For reference about this method check:
176    * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}.
177    * 
178    * @param queryConfigHandler
179    *          the query configuration handler to be set.
180    * 
181    * @see QueryNodeProcessor#getQueryConfigHandler()
182    * @see QueryConfigHandler
183    */
184   public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) {
185     this.queryConfig = queryConfigHandler;
186   }
187
188   /**
189    * For reference about this method check:
190    * {@link QueryNodeProcessor#getQueryConfigHandler()}.
191    * 
192    * @return QueryConfigHandler the query configuration handler to be set.
193    * 
194    * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)
195    * @see QueryConfigHandler
196    */
197   public QueryConfigHandler getQueryConfigHandler() {
198     return this.queryConfig;
199   }
200
201   /**
202    * This method is invoked for every node when walking down the tree.
203    * 
204    * @param node
205    *          the query node to be pre-processed
206    * 
207    * @return a query node
208    * 
209    * @throws QueryNodeException
210    *           if something goes wrong during the query node processing
211    */
212   abstract protected QueryNode preProcessNode(QueryNode node)
213       throws QueryNodeException;
214
215   /**
216    * This method is invoked for every node when walking up the tree.
217    * 
218    * @param node
219    *          node the query node to be post-processed
220    * 
221    * @return a query node
222    * 
223    * @throws QueryNodeException
224    *           if something goes wrong during the query node processing
225    */
226   abstract protected QueryNode postProcessNode(QueryNode node)
227       throws QueryNodeException;
228
229   /**
230    * This method is invoked for every node that has at least on child. It's
231    * invoked right before {@link #postProcessNode(QueryNode)} is invoked.
232    * 
233    * @param children
234    *          the list containing all current node's children
235    * 
236    * @return a new list containing all children that should be set to the
237    *         current node
238    * 
239    * @throws QueryNodeException
240    *           if something goes wrong during the query node processing
241    */
242   abstract protected List<QueryNode> setChildrenOrder(List<QueryNode> children)
243       throws QueryNodeException;
244
245   private static class ChildrenList extends ArrayList<QueryNode> {
246
247     private static final long serialVersionUID = -2613518456949297135L;
248
249     boolean beingUsed;
250
251   }
252
253 }