Index: solr/src/java/org/apache/solr/search/SolrConstantScoreQuery.java
===================================================================
--- solr/src/java/org/apache/solr/search/SolrConstantScoreQuery.java	(revision 1065304)
+++ solr/src/java/org/apache/solr/search/SolrConstantScoreQuery.java	Thu Apr 28 14:55:02 NZST 2011
@@ -3,6 +3,7 @@
 import org.apache.lucene.search.*;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.solr.search.function.ValueSource;
 import org.apache.solr.common.SolrException;
 
@@ -47,7 +48,7 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     return this;
   }
 
Index: lucene/src/java/org/apache/lucene/search/ConstantScoreQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/ConstantScoreQuery.java	(revision 1061499)
+++ lucene/src/java/org/apache/lucene/search/ConstantScoreQuery.java	Thu Apr 28 14:38:09 NZST 2011
@@ -20,6 +20,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 import java.io.IOException;
@@ -73,9 +74,9 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor queryProcessor) throws IOException {
     if (query != null) {
-      Query rewritten = query.rewrite(reader);
+      Query rewritten = queryProcessor.processQuery(query, reader);
       if (rewritten != query) {
         rewritten = new ConstantScoreQuery(rewritten);
         rewritten.setBoost(this.getBoost());
Index: lucene/src/java/org/apache/lucene/search/function/CustomScoreQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/function/CustomScoreQuery.java	(revision 1065410)
+++ lucene/src/java/org/apache/lucene/search/function/CustomScoreQuery.java	Thu Apr 28 14:40:30 NZST 2011
@@ -30,6 +30,7 @@
 import org.apache.lucene.search.Weight;
 import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 /**
@@ -88,17 +89,17 @@
 
   /*(non-Javadoc) @see org.apache.lucene.search.Query#rewrite(org.apache.lucene.index.IndexReader) */
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     CustomScoreQuery clone = null;
     
-    final Query sq = subQuery.rewrite(reader);
+    final Query sq = processor.processQuery(subQuery, reader);
     if (sq != subQuery) {
       clone = (CustomScoreQuery) clone();
       clone.subQuery = sq;
     }
 
     for(int i = 0; i < valSrcQueries.length; i++) {
-      final ValueSourceQuery v = (ValueSourceQuery) valSrcQueries[i].rewrite(reader);
+      final ValueSourceQuery v = (ValueSourceQuery) processor.processQuery(valSrcQueries[i], reader);
       if (v != valSrcQueries[i]) {
         if (clone == null) clone = (CustomScoreQuery) clone();
         clone.valSrcQueries[i] = v;
Index: lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SimpleTerm.java
===================================================================
--- lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SimpleTerm.java	(revision 917019)
+++ lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SimpleTerm.java	Thu Apr 28 14:57:13 NZST 2011
@@ -24,6 +24,7 @@
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.process.QueryProcessor;
 
 public abstract class SimpleTerm
   extends SrndQuery
@@ -82,7 +83,7 @@
       }
       
       @Override
-      public Query rewrite(IndexReader reader) throws IOException {
+      public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
         final List<Query> luceneSubQueries = new ArrayList<Query>();
         visitMatchingTerms( reader, fieldName,
             new MatchingTermVisitor() {
Index: lucene/src/java/org/apache/lucene/search/BooleanQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/BooleanQuery.java	(revision 1097133)
+++ lucene/src/java/org/apache/lucene/search/BooleanQuery.java	Thu Apr 28 14:26:22 NZST 2011
@@ -20,6 +20,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 import org.apache.lucene.search.BooleanClause.Occur;
 
@@ -359,12 +360,12 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     if (minNrShouldMatch == 0 && clauses.size() == 1) {                    // optimize 1-clause queries
       BooleanClause c = clauses.get(0);
       if (!c.isProhibited()) {			  // just return clause
 
-        Query query = c.getQuery().rewrite(reader);    // rewrite first
+        Query query = processor.processQuery(c.getQuery(), reader);    // rewrite first
 
         if (getBoost() != 1.0f) {                 // incorporate boost
           if (query == c.getQuery()) {                   // if rewrite was no-op
@@ -383,7 +384,7 @@
     BooleanQuery clone = null;                    // recursively rewrite
     for (int i = 0 ; i < clauses.size(); i++) {
       BooleanClause c = clauses.get(i);
-      Query query = c.getQuery().rewrite(reader);
+      Query query = processor.processQuery(c.getQuery(), reader);
       if (query != c.getQuery()) {                     // clause rewrote: must clone
         if (clone == null) {
           // The BooleanQuery clone is lazily initialized so only initialize
Index: lucene/src/java/org/apache/lucene/search/spans/SpanNearQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/spans/SpanNearQuery.java	(revision 1062775)
+++ lucene/src/java/org/apache/lucene/search/spans/SpanNearQuery.java	Thu Apr 28 14:51:05 NZST 2011
@@ -30,6 +30,7 @@
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 /** Matches spans which are near one another.  One can specify <i>slop</i>, the
@@ -130,11 +131,11 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     SpanNearQuery clone = null;
     for (int i = 0 ; i < clauses.size(); i++) {
       SpanQuery c = clauses.get(i);
-      SpanQuery query = (SpanQuery) c.rewrite(reader);
+      SpanQuery query = (SpanQuery) processor.processQuery(c, reader);
       if (query != c) {                     // clause rewrote: must clone
         if (clone == null)
           clone = (SpanNearQuery) this.clone();
Index: solr/src/java/org/apache/solr/schema/LatLonType.java
===================================================================
--- solr/src/java/org/apache/solr/schema/LatLonType.java	(revision 1082638)
+++ solr/src/java/org/apache/solr/schema/LatLonType.java	Thu Apr 28 14:54:48 NZST 2011
@@ -21,6 +21,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.search.*;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.spatial.DistanceUtils;
 import org.apache.lucene.spatial.tier.InvalidGeoException;
 import org.apache.lucene.util.Bits;
@@ -326,7 +327,7 @@
 
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor queryProcessor) throws IOException {
     return this;
   }
 
Index: lucene/src/java/org/apache/lucene/search/process/QueryProcessor.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/process/QueryProcessor.java	Thu Apr 28 15:24:19 NZST 2011
+++ lucene/src/java/org/apache/lucene/search/process/QueryProcessor.java	Thu Apr 28 15:24:19 NZST 2011
@@ -0,0 +1,28 @@
+package org.apache.lucene.search.process;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Query;
+
+import java.io.IOException;
+
+public abstract class QueryProcessor {
+
+  public abstract Query processQuery(Query query, IndexReader reader) throws IOException;
+}
Index: lucene/src/java/org/apache/lucene/util/MethodDispatchException.java
===================================================================
--- lucene/src/java/org/apache/lucene/util/MethodDispatchException.java	Tue Apr 26 21:23:40 NZST 2011
+++ lucene/src/java/org/apache/lucene/util/MethodDispatchException.java	Tue Apr 26 21:23:40 NZST 2011
@@ -0,0 +1,28 @@
+package org.apache.lucene.util;
+
+/*
+ * 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.
+ */
+public class MethodDispatchException extends RuntimeException {
+
+    public MethodDispatchException(String message) {
+        super(message);
+    }
+
+    public MethodDispatchException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
Index: lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java
===================================================================
--- lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java	(revision 1079707)
+++ lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java	Thu Apr 28 14:44:51 NZST 2011
@@ -30,6 +30,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.MultiFields;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.AttributeSource;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.PriorityQueue;
@@ -250,7 +251,7 @@
     }
             
     @Override
-    public Query rewrite(IndexReader reader) throws IOException
+    public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException
     {
         if(rewrittenQuery!=null)
         {
Index: lucene/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java	(revision 1061499)
+++ lucene/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java	Thu Apr 28 14:41:26 NZST 2011
@@ -25,6 +25,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 
 /**
  * A query that generates the union of documents produced by its subqueries, and that scores each document with the maximum
@@ -185,11 +186,11 @@
    * @param reader the IndexReader we query
    * @return an optimized copy of us (which may not be a copy if there is nothing to optimize) */
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     int numDisjunctions = disjuncts.size();
     if (numDisjunctions == 1) {
       Query singleton = disjuncts.get(0);
-      Query result = singleton.rewrite(reader);
+      Query result = processor.processQuery(singleton, reader);
       if (getBoost() != 1.0f) {
         if (result == singleton) result = (Query)result.clone();
         result.setBoost(getBoost() * result.getBoost());
@@ -199,7 +200,7 @@
     DisjunctionMaxQuery clone = null;
     for (int i = 0 ; i < numDisjunctions; i++) {
       Query clause = disjuncts.get(i);
-      Query rewrite = clause.rewrite(reader);
+      Query rewrite = processor.processQuery(clause, reader);
       if (rewrite != clause) {
         if (clone == null) clone = (DisjunctionMaxQuery)this.clone();
         clone.disjuncts.set(i, rewrite);
Index: lucene/src/java/org/apache/lucene/search/process/DispatchingQueryProcessor.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/process/DispatchingQueryProcessor.java	Thu Apr 28 15:09:31 NZST 2011
+++ lucene/src/java/org/apache/lucene/search/process/DispatchingQueryProcessor.java	Thu Apr 28 15:09:31 NZST 2011
@@ -0,0 +1,72 @@
+package org.apache.lucene.search.process;
+
+/*
+ * 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.
+ */
+
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.InvocationDispatcher;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class DispatchingQueryProcessor extends QueryProcessor {
+
+  private static final Map<Class, InvocationDispatcher<Query, Query>> dispatcherByClass =
+      new ConcurrentHashMap<Class, InvocationDispatcher<Query, Query>>();
+
+  private final InvocationDispatcher<Query, Query> dispatcher;
+  protected IndexReader indexReader; // nocommit decide whether this should be stored or passed around
+
+  /**
+   * Creates a new QueryProcessor that will dispatch to process methods in the
+   * given Class
+   *
+   * @param processorClass Class whose process methods will be dispatched to
+   */
+  public DispatchingQueryProcessor(Class<? extends DispatchingQueryProcessor> processorClass) {
+    InvocationDispatcher<Query, Query> dispatcher = dispatcherByClass.get(processorClass);
+    if (dispatcher == null) {
+      dispatcher = new InvocationDispatcher<Query, Query>(processorClass, "process", Query.class, Query.class);
+      dispatcherByClass.put(processorClass, dispatcher);
+    }
+    this.dispatcher = dispatcher;
+  }
+
+  /**
+   * Dispatches the given Query to be processed
+   * 
+   * @param query Query to process
+   * @return Result of processing the query
+   * @throws IOException Can be thrown during the processing of a Query
+   */
+  public final Query processQuery(Query query, IndexReader indexReader) throws IOException {
+    this.indexReader = indexReader;
+    return dispatcher.dispatch(this, query);
+  }
+
+  /**
+   * Default receiver for dispatched Query process calls.
+   *
+   * @param query Query to process
+   * @return Result of processing
+   * @throws IOException Can be thrown while processing
+   */
+  protected abstract Query process(Query query) throws IOException;
+}
Index: lucene/src/java/org/apache/lucene/search/spans/SpanNotQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/spans/SpanNotQuery.java	(revision 1062775)
+++ lucene/src/java/org/apache/lucene/search/spans/SpanNotQuery.java	Thu Apr 28 14:52:43 NZST 2011
@@ -21,6 +21,7 @@
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 import java.io.IOException;
@@ -167,15 +168,15 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     SpanNotQuery clone = null;
 
-    SpanQuery rewrittenInclude = (SpanQuery) include.rewrite(reader);
+    SpanQuery rewrittenInclude = (SpanQuery) processor.processQuery(include, reader);
     if (rewrittenInclude != include) {
       clone = (SpanNotQuery) this.clone();
       clone.include = rewrittenInclude;
     }
-    SpanQuery rewrittenExclude = (SpanQuery) exclude.rewrite(reader);
+    SpanQuery rewrittenExclude = (SpanQuery) processor.processQuery(exclude, reader);
     if (rewrittenExclude != exclude) {
       if (clone == null) clone = (SpanNotQuery) this.clone();
       clone.exclude = rewrittenExclude;
Index: lucene/src/java/org/apache/lucene/search/Query.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/Query.java	(revision 1068526)
+++ lucene/src/java/org/apache/lucene/search/Query.java	Thu Apr 28 14:31:24 NZST 2011
@@ -23,6 +23,8 @@
 
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
+import org.apache.lucene.search.process.SimpleQueryProcessor;
 
 /** The abstract base class for queries.
     <p>Instantiable subclasses are:
@@ -104,14 +106,17 @@
     weight.normalize(norm);
     return weight;
   }
-  
+
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
+    return this;
+  }
 
   /** Expert: called to re-write queries into primitive queries. For example,
    * a PrefixQuery will be rewritten into a BooleanQuery that consists
    * of TermQuerys.
    */
   public Query rewrite(IndexReader reader) throws IOException {
-    return this;
+    return rewrite(reader, new SimpleQueryProcessor());
   }
   
   /**
Index: lucene/src/java/org/apache/lucene/search/process/SimpleQueryProcessor.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/process/SimpleQueryProcessor.java	Thu Apr 28 15:25:38 NZST 2011
+++ lucene/src/java/org/apache/lucene/search/process/SimpleQueryProcessor.java	Thu Apr 28 15:25:38 NZST 2011
@@ -0,0 +1,31 @@
+package org.apache.lucene.search.process;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Query;
+
+import java.io.IOException;
+
+public class SimpleQueryProcessor extends QueryProcessor {
+
+  @Override
+  public final Query processQuery(Query query, IndexReader reader) throws IOException {
+    return query.rewrite(reader, this);
+  }
+}
Index: lucene/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java	(revision 1065327)
+++ lucene/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java	Thu Apr 28 14:54:04 NZST 2011
@@ -21,6 +21,7 @@
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.process.QueryProcessor;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -87,10 +88,10 @@
 
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     SpanPositionCheckQuery clone = null;
 
-    SpanQuery rewritten = (SpanQuery) match.rewrite(reader);
+    SpanQuery rewritten = (SpanQuery) processor.processQuery(match, reader);
     if (rewritten != match) {
       clone = (SpanPositionCheckQuery) this.clone();
       clone.match = rewritten;
Index: lucene/src/java/org/apache/lucene/util/InvocationDispatcher.java
===================================================================
--- lucene/src/java/org/apache/lucene/util/InvocationDispatcher.java	Wed Apr 27 23:36:36 NZST 2011
+++ lucene/src/java/org/apache/lucene/util/InvocationDispatcher.java	Wed Apr 27 23:36:36 NZST 2011
@@ -0,0 +1,175 @@
+package org.apache.lucene.util;
+
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * Generic Method invocation dispatcher that simulates simple multi dispatch.
+ * <p/>
+ * The dispatcher will scan all methods in a Class and its supertypes, identifying
+ * those of a given name.  When a method invocation is dispatched, the
+ * Dispatcher will resolve the method from those initially identified that
+ * accepts a parameter of the most specific type relative to the type of the
+ * given parameter.
+ */
+public class InvocationDispatcher<P, R> {
+
+  private final List<Method> dispatchableMethods;
+  private final Map<Class, Method> methodByType = new HashMap<Class, Method>();
+
+  /**
+   * Creates a new InvocationDispatcher that will dispatch to methods of the given
+   * method name, belonging to the given Class and its supertypes
+   *
+   * @param receiverType Class whose methods will be dispatched to
+   * @param methodName Name of the methods to consider dispatching to
+   * @param parameterType Type of the parameters that will be dispatched to the
+   *                      methods
+   * @param returnType Excepted return type of the dispatchable methods
+   */
+  public InvocationDispatcher(Class receiverType, String methodName, Class<P> parameterType, Class<R> returnType) {
+    this.dispatchableMethods = new ArrayList<Method>();
+
+    for (; receiverType != Object.class; receiverType = receiverType.getSuperclass()) {
+      for (Method method : receiverType.getDeclaredMethods()) {
+        if (isDispatchableMethod(method, methodName, parameterType, returnType)) {
+          method.setAccessible(true);
+          dispatchableMethods.add(method);
+        }
+      }
+    }
+
+    Collections.sort(dispatchableMethods, new Comparator<Method>() {
+
+      public int compare(Method o1, Method o2) {
+        return isSuperType(o1, o2) ? 1 : -1;
+      }
+    });
+  }
+
+  /**
+   * Dispatches the invocation of the most specific method resolveable given
+   * the type of parameter.
+   *
+   * @param invokeReceiver Object to invoke the method on
+   * @param parameter Parameter to dispatch in the method invocation.  Also
+   *                  used to determine the method to dispatch to
+   * @return Return value of the method invocation
+   */
+  @SuppressWarnings("unchecked")
+  public final R dispatch(Object invokeReceiver, P parameter) {
+    Class parameterType = parameter.getClass();
+    Method method = methodByType.get(parameterType);
+    if (method == null) {
+      List<Method> possibleMethods = new ArrayList<Method>();
+      for (Method dispatchableMethod : dispatchableMethods) {
+        if (isSuperType(dispatchableMethod.getParameterTypes()[0], parameterType) &&
+            !isSuperType(dispatchableMethod, possibleMethods)) {
+          possibleMethods.add(dispatchableMethod);
+        }
+      }
+
+      if (possibleMethods.size() == 0) {
+        throw new MethodDispatchException("No methods were resolved for parameter type");
+      } else if (possibleMethods.size() > 1) {
+        throw new MethodDispatchException("Multiple methods resolved for parameter type, cannot disambiguate");
+      }
+
+      method = possibleMethods.get(0);
+      methodByType.put(parameterType, method);
+    }
+    try {
+      return (R) method.invoke(invokeReceiver, parameter);
+    } catch (Exception e) {
+      throw new MethodDispatchException("Exception dispatching call to resolved method", e);
+    }
+  }
+
+  /**
+   * Determines whether the given method is a dispatchable method by checking if it
+   * meets the given criteria
+   *
+   * @param method Methd to check if it is dispatchable
+   * @param methodName Name that the method must have
+   * @param parameterType Type that the method's single parameter should be equal
+   *                      to or subtype of
+   * @param returnType Type that the method's return value should be equal to or
+   *                   subtype of
+   * @return {@code true} if the method meets the criteria and can receive dispatches,
+   *         {@code false} otherwise
+   */
+  private boolean isDispatchableMethod(Method method,
+                                       String methodName,
+                                       Class<P> parameterType,
+                                       Class<R> returnType) {
+    return methodName.equals(method.getName()) &&
+        method.getParameterTypes().length == 1 &&
+        isSuperType(parameterType, method.getParameterTypes()[0]) &&
+        isSuperType(returnType, method.getReturnType());
+  }
+
+  /**
+   * Determines if superType is a supertype of subType.
+   *
+   * @param superType Type to see if its a supertype of subType
+   * @param subType Type to see if its a subtype of superType
+   * @return {@code true} if superType is the supertype, {@code false}
+   *         otherwise
+   */
+  private boolean isSuperType(Class superType, Class subType) {
+    return superType.isAssignableFrom(subType);
+  }
+
+  /**
+   * Determines if superTypeMethod is a supertype of subTypeMethod.  The
+   * supertype relationship is defined as method A is a supertype of
+   * method B iff the first parameter if A is a supertype of the first
+   * parameter of B.
+   *
+   * @param superTypeMethod Method to see if its a supertype of the other
+   * @param subTypeMethod Method to see if its a subtype of superTypeMethod
+   * @return {@code true} if superTypeMethod is a supertype of subTypeMethod,
+   *         {@code false} otherwise
+   * @see #isSuperType(Class, Class) for parameter supertype relation explaination
+   */
+  private boolean isSuperType(Method superTypeMethod, Method subTypeMethod) {
+    return isSuperType(superTypeMethod.getParameterTypes()[0], subTypeMethod.getParameterTypes()[0]);
+  }
+
+  /**
+   * Determines if the given method is a supertype of any of the methods
+   * provided in the given list.
+   *
+   * @param superTypeMethod Method to see if it is a supertype of the others
+   * @param methods Methods to check if they are a subtype of the provided
+   *                supertype method
+   * @return {@code true} if superTypeMethod is a supertype of any of the
+   *         methods, {@code false} otherwise
+   * @see #isSuperType(Method, Method) for Method supertype relation explaination
+   */
+  private boolean isSuperType(Method superTypeMethod, List<Method> methods) {
+    for (Method method : methods) {
+      if (isSuperType(superTypeMethod, method)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
Index: lucene/src/java/org/apache/lucene/search/function/ValueSourceQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/function/ValueSourceQuery.java	(revision 1061499)
+++ lucene/src/java/org/apache/lucene/search/function/ValueSourceQuery.java	Thu Apr 28 14:54:31 NZST 2011
@@ -21,6 +21,7 @@
 import org.apache.lucene.search.*;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 import org.apache.lucene.util.Bits;
 
@@ -53,7 +54,7 @@
 
   /*(non-Javadoc) @see org.apache.lucene.search.Query#rewrite(org.apache.lucene.index.IndexReader) */
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor queryProcessor) throws IOException {
     return this;
   }
 
Index: lucene/src/java/org/apache/lucene/search/spans/SpanOrQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/spans/SpanOrQuery.java	(revision 1079707)
+++ lucene/src/java/org/apache/lucene/search/spans/SpanOrQuery.java	Thu Apr 28 14:53:22 NZST 2011
@@ -28,6 +28,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.PriorityQueue;
 import org.apache.lucene.util.ToStringUtils;
 import org.apache.lucene.search.Query;
@@ -86,11 +87,11 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     SpanOrQuery clone = null;
     for (int i = 0 ; i < clauses.size(); i++) {
       SpanQuery c = clauses.get(i);
-      SpanQuery query = (SpanQuery) c.rewrite(reader);
+      SpanQuery query = (SpanQuery) processor.processQuery(c, reader);
       if (query != c) {                     // clause rewrote: must clone
         if (clone == null)
           clone = (SpanOrQuery) this.clone();
Index: lucene/contrib/queries/src/java/org/apache/lucene/search/BoostingQuery.java
===================================================================
--- lucene/contrib/queries/src/java/org/apache/lucene/search/BoostingQuery.java	(revision 1061050)
+++ lucene/contrib/queries/src/java/org/apache/lucene/search/BoostingQuery.java	Thu Apr 28 14:30:12 NZST 2011
@@ -23,6 +23,7 @@
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.process.QueryProcessor;
 
 /**
  * The BoostingQuery class can be used to effectively demote results that match a given query. 
@@ -53,7 +54,7 @@
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
       BooleanQuery result = new BooleanQuery() {
         @Override
         public Weight createWeight(IndexSearcher searcher) throws IOException {
Index: solr/src/java/org/apache/solr/search/function/FunctionQuery.java
===================================================================
--- solr/src/java/org/apache/solr/search/function/FunctionQuery.java	(revision 1061499)
+++ solr/src/java/org/apache/solr/search/function/FunctionQuery.java	Thu Apr 28 14:56:09 NZST 2011
@@ -21,6 +21,7 @@
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.search.*;
 import org.apache.lucene.index.MultiFields;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.Bits;
 
 import java.io.IOException;
@@ -52,7 +53,7 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor queryProcessor) throws IOException {
     return this;
   }
 
Index: solr/src/java/org/apache/solr/search/function/BoostedQuery.java
===================================================================
--- solr/src/java/org/apache/solr/search/function/BoostedQuery.java	(revision 1065304)
+++ solr/src/java/org/apache/solr/search/function/BoostedQuery.java	Thu Apr 28 14:56:33 NZST 2011
@@ -20,6 +20,7 @@
 import org.apache.lucene.search.*;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 import java.io.IOException;
@@ -42,8 +43,8 @@
   public ValueSource getValueSource() { return boostVal; }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query newQ = q.rewrite(reader);
+  public Query rewrite(IndexReader reader, QueryProcessor queryProcessor) throws IOException {
+    Query newQ = queryProcessor.processQuery(q, reader);
     if (newQ == q) return this;
     BoostedQuery bq = (BoostedQuery)this.clone();
     bq.q = newQ;
Index: lucene/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java	(revision 1062775)
+++ lucene/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java	Thu Apr 28 14:50:18 NZST 2011
@@ -27,6 +27,7 @@
 import org.apache.lucene.search.TopTermsRewrite;
 import org.apache.lucene.search.ScoringRewrite;
 import org.apache.lucene.search.BooleanClause.Occur; // javadocs only
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.PerReaderTermState;
 
 /**
@@ -108,8 +109,8 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query q = query.rewrite(reader);
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
+    final Query q = processor.processQuery(query, reader);
     if (!(q instanceof SpanQuery))
       throw new UnsupportedOperationException("You can only use SpanMultiTermQueryWrapper with a suitable SpanRewriteMethod.");
     return q;
Index: lucene/src/java/org/apache/lucene/search/process/CachingQueryProcessor.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/process/CachingQueryProcessor.java	Thu Apr 28 15:24:04 NZST 2011
+++ lucene/src/java/org/apache/lucene/search/process/CachingQueryProcessor.java	Thu Apr 28 15:24:04 NZST 2011
@@ -0,0 +1,51 @@
+package org.apache.lucene.search.process;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Query;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+public class CachingQueryProcessor extends DispatchingQueryProcessor {
+
+  private final Map<IndexReader, Map<Query, Query>> queryCacheByIndexReader =
+      new WeakHashMap<IndexReader, Map<Query, Query>>();
+
+  public CachingQueryProcessor() {
+    super(CachingQueryProcessor.class);
+  }
+
+  @Override
+  protected Query process(Query query) throws IOException {
+    Map<Query, Query> queryCache = queryCacheByIndexReader.get(indexReader);
+    if (queryCache == null) {
+      queryCache = new HashMap<Query, Query>();
+      queryCacheByIndexReader.put(indexReader, queryCache);
+    }
+    Query cachedQuery = queryCache.get(query);
+    if (cachedQuery == null) {
+      cachedQuery = query.rewrite(indexReader, this);
+      queryCache.put(query, cachedQuery);
+    }
+    return cachedQuery;
+  }
+}
Index: lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThisQuery.java
===================================================================
--- lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThisQuery.java	(revision 834847)
+++ lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThisQuery.java	Thu Apr 28 14:45:37 NZST 2011
@@ -29,6 +29,7 @@
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.search.similar.MoreLikeThis;
 
 /**
@@ -61,7 +62,7 @@
     }
     
     @Override
-    public Query rewrite(IndexReader reader) throws IOException
+    public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException
     {
         MoreLikeThis mlt=new MoreLikeThis(reader);
         
Index: lucene/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java	(revision 1062775)
+++ lucene/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java	Thu Apr 28 14:42:03 NZST 2011
@@ -26,6 +26,7 @@
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Weight;
 import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 /**
@@ -107,10 +108,10 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     FieldMaskingSpanQuery clone = null;
 
-    SpanQuery rewritten = (SpanQuery) maskedQuery.rewrite(reader);
+    SpanQuery rewritten = (SpanQuery) processor.processQuery(maskedQuery, reader);
     if (rewritten != maskedQuery) {
       clone = (FieldMaskingSpanQuery) this.clone();
       clone.maskedQuery = rewritten;
Index: lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/DistanceQuery.java
===================================================================
--- lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/DistanceQuery.java	(revision 917019)
+++ lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/DistanceQuery.java	Thu Apr 28 14:57:23 NZST 2011
@@ -24,6 +24,7 @@
 
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.search.spans.SpanNearQuery;
 import org.apache.lucene.search.spans.SpanQuery;
 
@@ -81,7 +82,7 @@
       }
       
       @Override
-      public Query rewrite(IndexReader reader) throws IOException {
+      public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
         return getSpanNearQuery(reader, fieldName, getBoost(), qf);
       }
       
Index: lucene/src/java/org/apache/lucene/search/FilteredQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/FilteredQuery.java	(revision 1061499)
+++ lucene/src/java/org/apache/lucene/search/FilteredQuery.java	Thu Apr 28 14:42:54 NZST 2011
@@ -20,6 +20,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 
 import java.io.IOException;
@@ -169,8 +170,8 @@
 
   /** Rewrites the wrapped query. */
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query rewritten = query.rewrite(reader);
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
+    Query rewritten = processor.processQuery(query, reader);
     if (rewritten != query) {
       FilteredQuery clone = (FilteredQuery)this.clone();
       clone.query = rewritten;
Index: lucene/src/java/org/apache/lucene/search/MultiTermQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/MultiTermQuery.java	(revision 1068526)
+++ lucene/src/java/org/apache/lucene/search/MultiTermQuery.java	Thu Apr 28 14:47:41 NZST 2011
@@ -24,6 +24,7 @@
 import org.apache.lucene.index.Terms;
 import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.AttributeSource;
 import org.apache.lucene.util.PerReaderTermState;
 
@@ -302,7 +303,8 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
+    // nocommit decide whether to forward the processor onto the rewrite methods
     return rewriteMethod.rewrite(reader, this);
   }
 
Index: lucene/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java
===================================================================
--- lucene/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java	(revision 1091132)
+++ lucene/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java	Thu Apr 28 14:57:02 NZST 2011
@@ -30,6 +30,7 @@
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryUtils;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.LuceneTestCase;
 
@@ -145,7 +146,7 @@
     SpanQuery q = new FieldMaskingSpanQuery
       (new SpanTermQuery(new Term("last", "sally")) {
           @Override
-          public Query rewrite(IndexReader reader) {
+          public Query rewrite(IndexReader reader, QueryProcessor processor) {
             return new SpanOrQuery(new SpanTermQuery(new Term("first", "sally")),
                 new SpanTermQuery(new Term("first", "james")));
           }
Index: lucene/src/java/org/apache/lucene/search/PhraseQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/PhraseQuery.java	(revision 1074357)
+++ lucene/src/java/org/apache/lucene/search/PhraseQuery.java	Thu Apr 28 14:48:29 NZST 2011
@@ -26,6 +26,7 @@
 import org.apache.lucene.index.DocsAndPositionsEnum;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.Explanation.IDFExplanation;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ToStringUtils;
 import org.apache.lucene.util.ArrayUtil;
 import org.apache.lucene.util.Bits;
@@ -111,7 +112,7 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) throws IOException {
     if (terms.size() == 1) {
       TermQuery tq = new TermQuery(terms.get(0));
       tq.setBoost(getBoost());
Index: lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java	(revision 1079707)
+++ lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java	Thu Apr 28 14:45:52 NZST 2011
@@ -26,6 +26,7 @@
 import org.apache.lucene.index.DocsEnum;
 import org.apache.lucene.index.DocsAndPositionsEnum;
 import org.apache.lucene.search.Explanation.IDFExplanation;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.util.ArrayUtil;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.ToStringUtils;
@@ -314,7 +315,7 @@
   }
 
   @Override
-  public Query rewrite(IndexReader reader) {
+  public Query rewrite(IndexReader reader, QueryProcessor processor) {
     if (termArrays.size() == 1) {                 // optimize one-term case
       Term[] terms = termArrays.get(0);
       BooleanQuery boq = new BooleanQuery(true);
Index: lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java
===================================================================
--- lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java	(revision 1075210)
+++ lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java	Thu Apr 28 14:36:11 NZST 2011
@@ -33,6 +33,7 @@
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.TermRangeQuery;
+import org.apache.lucene.search.process.QueryProcessor;
 import org.apache.lucene.search.spans.SpanNearQuery;
 import org.apache.lucene.search.spans.SpanNotQuery;
 import org.apache.lucene.search.spans.SpanOrQuery;
@@ -225,7 +226,7 @@
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexReader reader, QueryProcessor queryProccesor) throws IOException {
       // ArrayList spanClauses = new ArrayList();
       if (contents instanceof TermQuery) {
         return contents;
@@ -248,7 +249,7 @@
         // HashSet bclauseterms=new HashSet();
         Query qc = bclauses[i].getQuery();
         // Rewrite this clause e.g one* becomes (one OR onerous)
-        qc = qc.rewrite(reader);
+        qc = queryProccesor.processQuery(qc, reader);
         if (bclauses[i].getOccur().equals(BooleanClause.Occur.MUST_NOT)) {
           numNegatives++;
         }
