You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2013/01/08 04:40:37 UTC

svn commit: r1430130 [21/27] - in /lucene/dev/branches/lucene4547: ./ dev-tools/ dev-tools/eclipse/ dev-tools/idea/.idea/libraries/ dev-tools/maven/ dev-tools/maven/solr/ dev-tools/maven/solr/contrib/analysis-extras/ dev-tools/maven/solr/contrib/cluste...

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LRUCache.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LRUCache.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LRUCache.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LRUCache.java Tue Jan  8 03:40:16 2013
@@ -56,6 +56,7 @@ public class LRUCache<K,V> extends SolrC
   private Map<K,V> map;
   private String description="LRU Cache";
 
+  @Override
   public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
     super.init(args, regenerator);
     String str = (String)args.get("size");
@@ -102,12 +103,14 @@ public class LRUCache<K,V> extends SolrC
     return description;
   }
 
+  @Override
   public int size() {
     synchronized(map) {
       return map.size();
     }
   }
 
+  @Override
   public V put(K key, V value) {
     synchronized (map) {
       if (getState() == State.LIVE) {
@@ -121,6 +124,7 @@ public class LRUCache<K,V> extends SolrC
     }
   }
 
+  @Override
   public V get(K key) {
     synchronized (map) {
       V val = map.get(key);
@@ -137,12 +141,14 @@ public class LRUCache<K,V> extends SolrC
     }
   }
 
+  @Override
   public void clear() {
     synchronized(map) {
       map.clear();
     }
   }
 
+  @Override
   public void warm(SolrIndexSearcher searcher, SolrCache<K,V> old) {
     if (regenerator==null) return;
     long warmingStartTime = System.currentTimeMillis();
@@ -192,6 +198,7 @@ public class LRUCache<K,V> extends SolrC
   }
 
 
+  @Override
   public void close() {
   }
 
@@ -199,18 +206,22 @@ public class LRUCache<K,V> extends SolrC
   //////////////////////// SolrInfoMBeans methods //////////////////////
 
 
+  @Override
   public String getName() {
     return LRUCache.class.getName();
   }
 
+  @Override
   public String getDescription() {
      return description;
   }
 
+  @Override
   public String getSource() {
     return "$URL$";
   }
 
+  @Override
   public NamedList getStatistics() {
     NamedList lst = new SimpleOrderedMap();
     synchronized (map) {

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LuceneQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LuceneQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LuceneQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/LuceneQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -36,6 +36,7 @@ import java.util.List;
 public class LuceneQParserPlugin extends QParserPlugin {
   public static String NAME = "lucene";
 
+  @Override
   public void init(NamedList args) {
   }
 

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/NestedQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/NestedQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/NestedQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/NestedQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -34,6 +34,7 @@ import org.apache.solr.request.SolrQuery
 public class NestedQParserPlugin extends QParserPlugin {
   public static String NAME = "query";
 
+  @Override
   public void init(NamedList args) {
   }
 

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/OldLuceneQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/OldLuceneQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/OldLuceneQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/OldLuceneQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -28,6 +28,7 @@ import org.apache.solr.request.SolrQuery
 public class OldLuceneQParserPlugin extends QParserPlugin {
   public static String NAME = "lucenePlusSort";
 
+  @Override
   public void init(NamedList args) {
   }
 

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -32,6 +32,7 @@ import org.apache.solr.request.SolrQuery
 public class PrefixQParserPlugin extends QParserPlugin {
   public static String NAME = "prefix";
 
+  @Override
   public void init(NamedList args) {
   }
 

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/RawQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/RawQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/RawQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/RawQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -36,6 +36,7 @@ import org.apache.solr.request.SolrQuery
 public class RawQParserPlugin extends QParserPlugin {
   public static String NAME = "raw";
 
+  @Override
   public void init(NamedList args) {
   }
 

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ReturnFields.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ReturnFields.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ReturnFields.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ReturnFields.java Tue Jan  8 03:40:16 2013
@@ -18,25 +18,7 @@ package org.apache.solr.search;
 
 import java.util.*;
 
-import org.apache.commons.io.FilenameUtils;
-import org.apache.lucene.queries.function.FunctionQuery;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.valuesource.QueryValueSource;
-import org.apache.lucene.search.Query;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.params.MapSolrParams;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.transform.DocTransformer;
-import org.apache.solr.response.transform.DocTransformers;
-import org.apache.solr.response.transform.RenameFieldTransformer;
-import org.apache.solr.response.transform.ScoreAugmenter;
-import org.apache.solr.response.transform.TransformerFactory;
-import org.apache.solr.response.transform.ValueSourceAugmenter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * A class representing the return fields
@@ -44,376 +26,24 @@ import org.slf4j.LoggerFactory;
  *
  * @since solr 4.0
  */
-public class ReturnFields
-{
-  static final Logger log = LoggerFactory.getLogger( ReturnFields.class );
+public abstract class ReturnFields {
+  /**
+   * Set of field names with their exact names from the lucene index.
+   * <p>
+   * Class such as ResponseWriters pass this to {@link SolrIndexSearcher#doc(int, Set)}.
+   * @return Set of field names or <code>null</code> (all fields).
+   */
+  public abstract Set<String> getLuceneFieldNames();
+
+  /** Returns <code>true</code> if the specified field should be returned. */
+  public abstract boolean wantsField(String name);
 
-  // Special Field Keys
-  public static final String SCORE = "score";
+  /** Returns <code>true</code> if all fields should be returned. */
+  public abstract boolean wantsAllFields();
 
-  private final List<String> globs = new ArrayList<String>(1);
-  
-  // The lucene field names to request from the SolrIndexSearcher
-  // Order is important for CSVResponseWriter
-  private final Set<String> fields = new LinkedHashSet<String>();
-  
-  // Field names that are OK to include in the response.
-  // This will include pseudo fields, lucene fields, and matching globs
-  private Set<String> okFieldNames = new HashSet<String>(); 
+  /** Returns <code>true</code> if the score should be returned. */
+  public abstract boolean wantsScore();
 
-  // The list of explicitly requested fields
-  private Set<String> reqFieldNames = null;
-  
-  private DocTransformer transformer;
-  private boolean _wantsScore = false;
-  private boolean _wantsAllFields = false;
-
-  public ReturnFields() {
-    _wantsAllFields = true;
-  }
-
-  public ReturnFields(SolrQueryRequest req) {
-    this( req.getParams().getParams(CommonParams.FL), req );
-  }
-
-  public ReturnFields(String fl, SolrQueryRequest req) {
-//    this( (fl==null)?null:SolrPluginUtils.split(fl), req );
-    if( fl == null ) {
-      parseFieldList((String[])null, req);
-    }
-    else {
-      if( fl.trim().length() == 0 ) {
-        // legacy thing to support fl='  ' => fl=*,score!
-        // maybe time to drop support for this?
-        // See ConvertedLegacyTest
-        _wantsScore = true;
-        _wantsAllFields = true;
-        transformer = new ScoreAugmenter(SCORE);
-      }
-      else {
-        parseFieldList( new String[]{fl}, req);
-      }
-    }
-  }
-
-  public ReturnFields(String[] fl, SolrQueryRequest req) {
-    parseFieldList(fl, req);
-  }
-
-  private void parseFieldList(String[] fl, SolrQueryRequest req) {
-    _wantsScore = false;
-    _wantsAllFields = false;
-    if (fl == null || fl.length == 0 || fl.length == 1 && fl[0].length()==0) {
-      _wantsAllFields = true;
-      return;
-    }
-
-    NamedList<String> rename = new NamedList<String>();
-    DocTransformers augmenters = new DocTransformers();
-    for (String fieldList : fl) {
-      add(fieldList,rename,augmenters,req);
-    }
-    for( int i=0; i<rename.size(); i++ ) {
-      String from = rename.getName(i);
-      String to = rename.getVal(i);
-      okFieldNames.add( to );
-      boolean copy = (reqFieldNames!=null && reqFieldNames.contains(from));
-      if(!copy) {
-        // Check that subsequent copy/rename requests have the field they need to copy
-        for(int j=i+1; j<rename.size(); j++) {
-          if(from.equals(rename.getName(j))) {
-            rename.setName(j, to); // copy from the current target
-            if(reqFieldNames==null) {
-              reqFieldNames = new HashSet<String>();
-            }
-            reqFieldNames.add(to); // don't rename our current target
-          }
-        }
-      }
-      augmenters.addTransformer( new RenameFieldTransformer( from, to, copy ) );     
-    }
-
-    if( !_wantsAllFields ) {
-      if( !globs.isEmpty() ) {
-        // TODO??? need to fill up the fields with matching field names in the index
-        // and add them to okFieldNames?
-        // maybe just get all fields?
-        // this would disable field selection optimization... i think thatis OK
-        fields.clear(); // this will get all fields, and use wantsField to limit
-      }
-      okFieldNames.addAll( fields );
-    }
-
-    if( augmenters.size() == 1 ) {
-      transformer = augmenters.getTransformer(0);
-    }
-    else if( augmenters.size() > 1 ) {
-      transformer = augmenters;
-    }
-  }
-
-
-  // like getId, but also accepts dashes for legacy fields
-  String getFieldName(QueryParsing.StrParser sp) {
-    sp.eatws();
-    int id_start = sp.pos;
-    char ch;
-    if (sp.pos < sp.end && (ch = sp.val.charAt(sp.pos)) != '$' && Character.isJavaIdentifierStart(ch)) {
-      sp.pos++;
-      while (sp.pos < sp.end) {
-        ch = sp.val.charAt(sp.pos);
-        if (!Character.isJavaIdentifierPart(ch) && ch != '.' && ch != '-') {
-          break;
-        }
-        sp.pos++;
-      }
-      return sp.val.substring(id_start, sp.pos);
-    }
-
-    return null;
-  }
-
-  private void add(String fl, NamedList<String> rename, DocTransformers augmenters, SolrQueryRequest req) {
-    if( fl == null ) {
-      return;
-    }
-    try {
-      QueryParsing.StrParser sp = new QueryParsing.StrParser(fl);
-
-      for(;;) {
-        sp.opt(',');
-        sp.eatws();
-        if (sp.pos >= sp.end) break;
-
-        int start = sp.pos;
-
-        // short circuit test for a really simple field name
-        String key = null;
-        String field = getFieldName(sp);
-        char ch = sp.ch();
-
-        if (field != null) {
-          if (sp.opt(':')) {
-            // this was a key, not a field name
-            key = field;
-            field = null;
-            sp.eatws();
-            start = sp.pos;
-          } else {
-            if (Character.isWhitespace(ch) || ch == ',' || ch==0) {
-              addField( field, key, augmenters, req );
-              continue;
-            }
-            // an invalid field name... reset the position pointer to retry
-            sp.pos = start;
-            field = null;
-          }
-        }
-
-        if (key != null) {
-          // we read "key : "
-          field = sp.getId(null);
-          ch = sp.ch();
-          if (field != null && (Character.isWhitespace(ch) || ch == ',' || ch==0)) {
-            rename.add(field, key);
-            addField( field, key, augmenters, req );
-            continue;
-          }
-          // an invalid field name... reset the position pointer to retry
-          sp.pos = start;
-          field = null;
-        }
-
-        if (field == null) {
-          // We didn't find a simple name, so let's see if it's a globbed field name.
-          // Globbing only works with field names of the recommended form (roughly like java identifiers)
-
-          field = sp.getGlobbedId(null);
-          ch = sp.ch();
-          if (field != null && (Character.isWhitespace(ch) || ch == ',' || ch==0)) {
-            // "*" looks and acts like a glob, but we give it special treatment
-            if ("*".equals(field)) {
-              _wantsAllFields = true;
-            } else {
-              globs.add(field);
-            }
-            continue;
-          }
-
-          // an invalid glob
-          sp.pos = start;
-        }
-
-        String funcStr = sp.val.substring(start);
-
-        // Is it an augmenter of the form [augmenter_name foo=1 bar=myfield]?
-        // This is identical to localParams syntax except it uses [] instead of {!}
-
-        if (funcStr.startsWith("[")) {
-          Map<String,String> augmenterArgs = new HashMap<String,String>();
-          int end = QueryParsing.parseLocalParams(funcStr, 0, augmenterArgs, req.getParams(), "[", ']');
-          sp.pos += end;
-          
-          // [foo] is short for [type=foo] in localParams syntax
-          String augmenterName = augmenterArgs.remove("type"); 
-          String disp = key;
-          if( disp == null ) {
-            disp = '['+augmenterName+']';
-          }
-
-          TransformerFactory factory = req.getCore().getTransformerFactory( augmenterName );
-          if( factory != null ) {
-            MapSolrParams augmenterParams = new MapSolrParams( augmenterArgs );
-            augmenters.addTransformer( factory.create(disp, augmenterParams, req) );
-          }
-          else {
-            // unknown transformer?
-          }
-          addField(field, disp, augmenters, req);
-          continue;
-        }
-
-
-        // let's try it as a function instead
-        QParser parser = QParser.getParser(funcStr, FunctionQParserPlugin.NAME, req);
-        Query q = null;
-        ValueSource vs = null;
-
-        try {
-          if (parser instanceof FunctionQParser) {
-            FunctionQParser fparser = (FunctionQParser)parser;
-            fparser.setParseMultipleSources(false);
-            fparser.setParseToEnd(false);
-
-            q = fparser.getQuery();
-
-            if (fparser.localParams != null) {
-              if (fparser.valFollowedParams) {
-                // need to find the end of the function query via the string parser
-                int leftOver = fparser.sp.end - fparser.sp.pos;
-                sp.pos = sp.end - leftOver;   // reset our parser to the same amount of leftover
-              } else {
-                // the value was via the "v" param in localParams, so we need to find
-                // the end of the local params themselves to pick up where we left off
-                sp.pos = start + fparser.localParamsEnd;
-              }
-            } else {
-              // need to find the end of the function query via the string parser
-              int leftOver = fparser.sp.end - fparser.sp.pos;
-              sp.pos = sp.end - leftOver;   // reset our parser to the same amount of leftover
-            }
-          } else {
-            // A QParser that's not for function queries.
-            // It must have been specified via local params.
-            q = parser.getQuery();
-
-            assert parser.getLocalParams() != null;
-            sp.pos = start + parser.localParamsEnd;
-          }
-
-
-          if (q instanceof FunctionQuery) {
-            vs = ((FunctionQuery)q).getValueSource();
-          } else {
-            vs = new QueryValueSource(q, 0.0f);
-          }
-
-          if (key==null) {
-            SolrParams localParams = parser.getLocalParams();
-            if (localParams != null) {
-              key = localParams.get("key");
-            }
-            if (key == null) {
-              // use the function name itself as the field name
-              key = sp.val.substring(start, sp.pos);
-            }
-          }
-
-
-          if (key==null) {
-            key = funcStr;
-          }
-          okFieldNames.add( key );
-          okFieldNames.add( funcStr );
-          augmenters.addTransformer( new ValueSourceAugmenter( key, parser, vs ) );
-        }
-        catch (SyntaxError e) {
-          // try again, simple rules for a field name with no whitespace
-          sp.pos = start;
-          field = sp.getSimpleString();
-
-          if (req.getSchema().getFieldOrNull(field) != null) {
-            // OK, it was an oddly named field
-            fields.add(field);
-            if( key != null ) {
-              rename.add(field, key);
-            }
-          } else {
-            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error parsing fieldname: " + e.getMessage(), e);
-          }
-        }
-
-       // end try as function
-
-      } // end for(;;)
-    } catch (SyntaxError e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error parsing fieldname", e);
-    }
-  }
-
-  private void addField( String field, String key, DocTransformers augmenters, SolrQueryRequest req )
-  {
-    if(key==null) {
-      if(reqFieldNames==null) {
-        reqFieldNames = new HashSet<String>();
-      }
-      reqFieldNames.add(field);
-    }
-    
-    fields.add(field); // need to put in the map to maintain order for things like CSVResponseWriter
-    okFieldNames.add( field );
-    okFieldNames.add( key );
-    // a valid field name
-    if(SCORE.equals(field)) {
-      _wantsScore = true;
-
-      String disp = (key==null) ? field : key;
-      augmenters.addTransformer( new ScoreAugmenter( disp ) );
-    }
-  }
-
-  public Set<String> getLuceneFieldNames()
-  {
-    return (_wantsAllFields || fields.isEmpty()) ? null : fields;
-  }
-
-  public boolean wantsAllFields()
-  {
-    return _wantsAllFields;
-  }
-
-  public boolean wantsScore()
-  {
-    return _wantsScore;
-  }
-
-  public boolean wantsField( String name )
-  {
-    if( _wantsAllFields || okFieldNames.contains( name ) ){
-      return true;
-    }
-    for( String s : globs ) {
-      // TODO something better?
-      if( FilenameUtils.wildcardMatch( name, s ) ) {
-        okFieldNames.add(name); // Don't calculate it again
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public DocTransformer getTransformer()
-  {
-    return transformer;
-  }
+  /** Returns the DocTransformer used to modify documents, or <code>null</code> */
+  public abstract DocTransformer getTransformer();
 }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java Tue Jan  8 03:40:16 2013
@@ -38,19 +38,26 @@ public class SolrFieldCacheMBean impleme
 
   protected FieldCacheSanityChecker checker = new FieldCacheSanityChecker();
 
+  @Override
   public String getName() { return this.getClass().getName(); }
+  @Override
   public String getVersion() { return SolrCore.version; }
+  @Override
   public String getDescription() {
     return "Provides introspection of the Lucene FieldCache, "
       +    "this is **NOT** a cache that is managed by Solr.";
   }
+  @Override
   public Category getCategory() { return Category.CACHE; } 
+  @Override
   public String getSource() { 
     return "$URL$";
   }
+  @Override
   public URL[] getDocs() {
     return null;
   }
+  @Override
   public NamedList getStatistics() {
     NamedList stats = new SimpleOrderedMap();
     CacheEntry[] entries = FieldCache.DEFAULT.getCacheEntries();

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java Tue Jan  8 03:40:16 2013
@@ -109,6 +109,8 @@ public class SolrIndexSearcher extends I
   private final SolrCache[] cacheList;
   private static final SolrCache[] noCaches = new SolrCache[0];
   
+  private final FieldInfos fieldInfos;
+  // TODO: do we need this separate set of field names? we can just use the fieldinfos?
   private final Collection<String> fieldNames;
   private Collection<String> storedHighlightFieldNames;
   private DirectoryFactory directoryFactory;
@@ -199,7 +201,8 @@ public class SolrIndexSearcher extends I
     optimizer = null;
     
     fieldNames = new HashSet<String>();
-    for(FieldInfo fieldInfo : atomicReader.getFieldInfos()) {
+    fieldInfos = atomicReader.getFieldInfos();
+    for(FieldInfo fieldInfo : fieldInfos) {
       fieldNames.add(fieldInfo.name);
     }
 
@@ -252,6 +255,7 @@ public class SolrIndexSearcher extends I
    *
    * In particular, the underlying reader and any cache's in use are closed.
    */
+  @Override
   public void close() throws IOException {
     if (debug) {
       if (cachingEnabled) {
@@ -331,6 +335,7 @@ public class SolrIndexSearcher extends I
     if (solrConfig.fieldValueCacheConfig != null && solrConfig.fieldValueCacheConfig.getRegenerator() == null) {
       solrConfig.fieldValueCacheConfig.setRegenerator(
               new CacheRegenerator() {
+                @Override
                 public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache, SolrCache oldCache, Object oldKey, Object oldVal) throws IOException {
                   if (oldVal instanceof UnInvertedField) {
                     UnInvertedField.getUnInvertedField((String)oldKey, newSearcher);
@@ -344,6 +349,7 @@ public class SolrIndexSearcher extends I
     if (solrConfig.filterCacheConfig != null && solrConfig.filterCacheConfig.getRegenerator() == null) {
       solrConfig.filterCacheConfig.setRegenerator(
               new CacheRegenerator() {
+                @Override
                 public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache, SolrCache oldCache, Object oldKey, Object oldVal) throws IOException {
                   newSearcher.cacheDocSet((Query)oldKey, null, false);
                   return true;
@@ -356,6 +362,7 @@ public class SolrIndexSearcher extends I
       final int queryResultWindowSize = solrConfig.queryResultWindowSize;
       solrConfig.queryResultCacheConfig.setRegenerator(
               new CacheRegenerator() {
+                @Override
                 public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache, SolrCache oldCache, Object oldKey, Object oldVal) throws IOException {
                   QueryResultKey key = (QueryResultKey)oldKey;
                   int nDocs=1;
@@ -438,6 +445,7 @@ public class SolrIndexSearcher extends I
       lazyDoc = new LazyDocument(reader, docID);
     }
 
+    @Override
     public Status needsField(FieldInfo fieldInfo) {
       if (fieldsToLoad.contains(fieldInfo.name)) {
         return Status.YES;
@@ -504,21 +512,65 @@ public class SolrIndexSearcher extends I
   }
 
   /** Visit a document's fields using a {@link StoredFieldVisitor}
-   *  This method does not currently use the Solr document cache.
+   *  This method does not currently add to the Solr document cache.
    * 
    * @see IndexReader#document(int, StoredFieldVisitor) */
   @Override
   public void doc(int n, StoredFieldVisitor visitor) throws IOException {
+    if (documentCache != null) {
+      StoredDocument cached = documentCache.get(n);
+      if (cached != null) {
+        visitFromCached(cached, visitor);
+        return;
+      }
+    }
     getIndexReader().document(n, visitor);
   }
+  
+  /** Executes a stored field visitor against a hit from the document cache */
+  private void visitFromCached(StoredDocument document, StoredFieldVisitor visitor) throws IOException {
+    for (StorableField f : document) {
+      FieldInfo info = fieldInfos.fieldInfo(f.name());
+      switch(visitor.needsField(info)) {
+        case YES:
+          if (f.binaryValue() != null) {
+            BytesRef binaryValue = f.binaryValue();
+            byte copy[] = new byte[binaryValue.length];
+            System.arraycopy(binaryValue.bytes, binaryValue.offset, copy, 0, copy.length);
+            visitor.binaryField(info, copy);
+          } else if (f.numericValue() != null) {
+            Number numericValue = f.numericValue();
+            if (numericValue instanceof Double) {
+              visitor.doubleField(info, numericValue.doubleValue());
+            } else if (numericValue instanceof Integer) {
+              visitor.intField(info, numericValue.intValue());
+            } else if (numericValue instanceof Float) {
+              visitor.floatField(info, numericValue.floatValue());
+            } else if (numericValue instanceof Long) {
+              visitor.longField(info, numericValue.longValue());
+            } else {
+              throw new AssertionError();
+            }
+          } else {
+            visitor.stringField(info, f.stringValue());
+          }
+          break;
+        case NO:
+          break;
+        case STOP:
+          return;
+      }
+    }
+  }
 
   /**
    * Retrieve the {@link Document} instance corresponding to the document id.
-   *
-   * Note: The document will have all fields accessable, but if a field
+   * <p>
+   * Note: The document will have all fields accessible, but if a field
    * filter is provided, only the provided fields will be loaded (the 
    * remainder will be available lazily).
    */
+  @Override
   public StoredDocument doc(int i, Set<String> fields) throws IOException {
     
     StoredDocument d;
@@ -594,7 +646,7 @@ public class SolrIndexSearcher extends I
     if (!termsEnum.seekExact(termBytes, false)) {
       return -1;
     }
-    DocsEnum docs = termsEnum.docs(atomicReader.getLiveDocs(), null, 0);
+    DocsEnum docs = termsEnum.docs(atomicReader.getLiveDocs(), null, DocsEnum.FLAG_NONE);
     if (docs == null) return -1;
     int id = docs.nextDoc();
     return id == DocIdSetIterator.NO_MORE_DOCS ? -1 : id;
@@ -616,7 +668,7 @@ public class SolrIndexSearcher extends I
       
       TermsEnum te = terms.iterator(null);
       if (te.seekExact(idBytes, true)) {
-        DocsEnum docs = te.docs(reader.getLiveDocs(), null, 0);
+        DocsEnum docs = te.docs(reader.getLiveDocs(), null, DocsEnum.FLAG_NONE);
         int id = docs.nextDoc();
         if (id == DocIdSetIterator.NO_MORE_DOCS) continue;
         assert docs.nextDoc() == DocIdSetIterator.NO_MORE_DOCS;
@@ -920,7 +972,7 @@ public class SolrIndexSearcher extends I
     int bitsSet = 0;
     OpenBitSet obs = null;
 
-    DocsEnum docsEnum = deState.termsEnum.docs(deState.liveDocs, deState.docsEnum, 0);
+    DocsEnum docsEnum = deState.termsEnum.docs(deState.liveDocs, deState.docsEnum, DocsEnum.FLAG_NONE);
     if (deState.docsEnum == null) {
       deState.docsEnum = docsEnum;
     }
@@ -998,7 +1050,7 @@ public class SolrIndexSearcher extends I
           if (terms != null) {
             final TermsEnum termsEnum = terms.iterator(null);
             if (termsEnum.seekExact(termBytes, false)) {
-              docsEnum = termsEnum.docs(liveDocs, null, 0);
+              docsEnum = termsEnum.docs(liveDocs, null, DocsEnum.FLAG_NONE);
             }
           }
 
@@ -1953,36 +2005,44 @@ public class SolrIndexSearcher extends I
   // SolrInfoMBean stuff: Statistics and Module Info
   /////////////////////////////////////////////////////////////////////
 
+  @Override
   public String getName() {
     return SolrIndexSearcher.class.getName();
   }
 
+  @Override
   public String getVersion() {
     return SolrCore.version;
   }
 
+  @Override
   public String getDescription() {
     return "index searcher";
   }
 
+  @Override
   public Category getCategory() {
     return Category.CORE;
   }
 
+  @Override
   public String getSource() {
     return "$URL$";
   }
 
+  @Override
   public URL[] getDocs() {
     return null;
   }
 
+  @Override
   public NamedList<Object> getStatistics() {
     NamedList<Object> lst = new SimpleOrderedMap<Object>();
     lst.add("searcherName", name);
     lst.add("caching", cachingEnabled);
     lst.add("numDocs", reader.numDocs());
     lst.add("maxDoc", reader.maxDoc());
+    lst.add("deletedDocs", reader.maxDoc() - reader.numDocs());
     lst.add("reader", reader.toString());
     lst.add("readerDir", reader.directory());
     lst.add("indexVersion", reader.getVersion());

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java Tue Jan  8 03:40:16 2013
@@ -50,8 +50,10 @@ public class SortedIntDocSet extends Doc
 
   public int[] getDocs() { return docs; }
 
+  @Override
   public int size()      { return docs.length; }
 
+  @Override
   public long memSize() {
     return (docs.length<<2)+8;
   }
@@ -219,6 +221,7 @@ public class SortedIntDocSet extends Doc
     return false;
   }
 
+  @Override
   public int intersectionSize(DocSet other) {
     if (!(other instanceof SortedIntDocSet)) {
       // assume other implementations are better at random access than we are,
@@ -567,6 +570,7 @@ public class SortedIntDocSet extends Doc
   }
 
 
+  @Override
   public boolean exists(int doc) {
     // this could be faster by estimating where in the list the doc is likely to appear,
     // but we should get away from using exists() anyway.
@@ -591,13 +595,16 @@ public class SortedIntDocSet extends Doc
   }
   
 
+  @Override
   public DocIterator iterator() {
     return new DocIterator() {
       int pos=0;
+      @Override
       public boolean hasNext() {
         return pos < docs.length;
       }
 
+      @Override
       public Integer next() {
         return nextDoc();
       }
@@ -605,14 +612,17 @@ public class SortedIntDocSet extends Doc
       /**
        * The remove  operation is not supported by this Iterator.
        */
+      @Override
       public void remove() {
         throw new UnsupportedOperationException("The remove  operation is not supported by this Iterator.");
       }
 
+      @Override
       public int nextDoc() {
         return docs[pos++];
       }
 
+      @Override
       public float score() {
         return 0.0f;
       }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SpatialFilterQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SpatialFilterQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SpatialFilterQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/SpatialFilterQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -58,6 +58,7 @@ public class SpatialFilterQParserPlugin 
     return new SpatialFilterQParser(qstr, localParams, params, req, false);
   }
 
+  @Override
   public void init(NamedList args) {
 
   }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/TermQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/TermQParserPlugin.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/TermQParserPlugin.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/TermQParserPlugin.java Tue Jan  8 03:40:16 2013
@@ -43,6 +43,7 @@ import org.apache.solr.schema.FieldType;
 public class TermQParserPlugin extends QParserPlugin {
   public static String NAME = "term";
 
+  @Override
   public void init(NamedList args) {
   }
 

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java Tue Jan  8 03:40:16 2013
@@ -55,6 +55,7 @@ public abstract class ValueSourceParser 
   /**
    * Initialize the plugin.
    */
+  @Override
   public void init(NamedList args) {}
 
   /**

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/function/FileFloatSource.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/function/FileFloatSource.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/function/FileFloatSource.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/function/FileFloatSource.java Tue Jan  8 03:40:16 2013
@@ -305,7 +305,7 @@ public class FileFloatSource extends Val
           continue;
         }
 
-        docsEnum = termsEnum.docs(null, docsEnum, 0);
+        docsEnum = termsEnum.docs(null, docsEnum, DocsEnum.FLAG_NONE);
         int doc;
         while ((doc = docsEnum.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
           vals[doc] = fval;

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/collector/FilterCollector.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/collector/FilterCollector.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/collector/FilterCollector.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/collector/FilterCollector.java Tue Jan  8 03:40:16 2013
@@ -41,10 +41,12 @@ public class FilterCollector extends Col
     this.delegate = delegate;
   }
 
+  @Override
   public void setScorer(Scorer scorer) throws IOException {
     delegate.setScorer(scorer);
   }
 
+  @Override
   public void collect(int doc) throws IOException {
     matches++;
     if (filter.exists(doc + docBase)) {
@@ -52,11 +54,13 @@ public class FilterCollector extends Col
     }
   }
 
+  @Override
   public void setNextReader(AtomicReaderContext context) throws IOException {
     this.docBase = context.docBase;
     delegate.setNextReader(context);
   }
 
+  @Override
   public boolean acceptsDocsOutOfOrder() {
     return delegate.acceptsDocsOutOfOrder();
   }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java Tue Jan  8 03:40:16 2013
@@ -123,6 +123,7 @@ public class QueryCommand implements Com
     this.queryString = queryString;
   }
 
+  @Override
   public List<Collector> create() throws IOException {
     if (sort == null || sort == Sort.RELEVANCE) {
       collector = TopScoreDocCollector.create(docsToCollect, true);
@@ -133,18 +134,22 @@ public class QueryCommand implements Com
     return Arrays.asList((Collector) filterCollector);
   }
 
+  @Override
   public QueryCommandResult result() {
     return new QueryCommandResult(collector.topDocs(), filterCollector.getMatches());
   }
 
+  @Override
   public String getKey() {
     return queryString != null ? queryString : query.toString();
   }
 
+  @Override
   public Sort getGroupSort() {
     return sort;
   }
 
+  @Override
   public Sort getSortWithinGroup() {
     return null;
   }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java Tue Jan  8 03:40:16 2013
@@ -86,6 +86,7 @@ public class SearchGroupsFieldCommand im
     this.includeGroupCount = includeGroupCount;
   }
 
+  @Override
   public List<Collector> create() throws IOException {
     List<Collector> collectors = new ArrayList<Collector>();
     if (topNGroups > 0) {
@@ -99,6 +100,7 @@ public class SearchGroupsFieldCommand im
     return collectors;
   }
 
+  @Override
   public Pair<Integer, Collection<SearchGroup<BytesRef>>> result() {
     final Collection<SearchGroup<BytesRef>> topGroups;
     if (topNGroups > 0) {
@@ -115,14 +117,17 @@ public class SearchGroupsFieldCommand im
     return new Pair<Integer, Collection<SearchGroup<BytesRef>>>(groupCount, topGroups);
   }
 
+  @Override
   public Sort getSortWithinGroup() {
     return null;
   }
 
+  @Override
   public Sort getGroupSort() {
     return groupSort;
   }
 
+  @Override
   public String getKey() {
     return field.getName();
   }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java Tue Jan  8 03:40:16 2013
@@ -119,6 +119,7 @@ public class TopGroupsFieldCommand imple
     this.needMaxScore = needMaxScore;
   }
 
+  @Override
   public List<Collector> create() throws IOException {
     if (firstPhaseGroups.isEmpty()) {
       return Collections.emptyList();
@@ -132,6 +133,7 @@ public class TopGroupsFieldCommand imple
     return collectors;
   }
 
+  @Override
   @SuppressWarnings("unchecked")
   public TopGroups<BytesRef> result() {
     if (firstPhaseGroups.isEmpty()) {
@@ -141,14 +143,17 @@ public class TopGroupsFieldCommand imple
     return secondPassCollector.getTopGroups(0);
   }
 
+  @Override
   public String getKey() {
     return field.getName();
   }
 
+  @Override
   public Sort getGroupSort() {
     return groupSort;
   }
 
+  @Override
   public Sort getSortWithinGroup() {
     return sortWithinGroup;
   }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/SearchGroupsRequestFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/SearchGroupsRequestFactory.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/SearchGroupsRequestFactory.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/SearchGroupsRequestFactory.java Tue Jan  8 03:40:16 2013
@@ -36,6 +36,7 @@ public class SearchGroupsRequestFactory 
   /**
    * {@inheritDoc}
    */
+  @Override
   public ShardRequest[] constructRequest(ResponseBuilder rb) {
     ShardRequest sreq = new ShardRequest();
     GroupingSpecification groupingSpecification = rb.getGroupingSpec();

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java Tue Jan  8 03:40:16 2013
@@ -50,6 +50,7 @@ public class TopGroupsShardRequestFactor
   /**
    * {@inheritDoc}
    */
+  @Override
   public ShardRequest[] constructRequest(ResponseBuilder rb) {
     // If we have a group.query we need to query all shards... Or we move this to the group first phase queries
     boolean containsGroupByQuery = rb.getGroupingSpec().getQueries().length > 0;

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java Tue Jan  8 03:40:16 2013
@@ -41,6 +41,7 @@ public class SearchGroupShardResponsePro
   /**
    * {@inheritDoc}
    */
+  @Override
   public void process(ResponseBuilder rb, ShardRequest shardRequest) {
     SortSpec ss = rb.getSortSpec();
     Sort groupSort = rb.getGroupingSpec().getGroupSort();

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java Tue Jan  8 03:40:16 2013
@@ -35,6 +35,7 @@ public class StoredFieldsShardResponsePr
   /**
    * {@inheritDoc}
    */
+  @Override
   public void process(ResponseBuilder rb, ShardRequest shardRequest) {
     boolean returnScores = (rb.getFieldFlags() & SolrIndexSearcher.GET_SCORES) != 0;
     ShardResponse srsp = shardRequest.responses.get(0);

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java Tue Jan  8 03:40:16 2013
@@ -48,6 +48,7 @@ public class TopGroupsShardResponseProce
   /**
    * {@inheritDoc}
    */
+  @Override
   @SuppressWarnings("unchecked")
   public void process(ResponseBuilder rb, ShardRequest shardRequest) {
     Sort groupSort = rb.getGroupingSpec().getGroupSort();

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/SearchGroupsResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/SearchGroupsResultTransformer.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/SearchGroupsResultTransformer.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/SearchGroupsResultTransformer.java Tue Jan  8 03:40:16 2013
@@ -47,6 +47,7 @@ public class SearchGroupsResultTransform
   /**
    * {@inheritDoc}
    */
+  @Override
   public NamedList transform(List<Command> data) throws IOException {
     NamedList<NamedList> result = new NamedList<NamedList>();
     for (Command command : data) {
@@ -74,6 +75,7 @@ public class SearchGroupsResultTransform
   /**
    * {@inheritDoc}
    */
+  @Override
   public Map<String, Pair<Integer, Collection<SearchGroup<BytesRef>>>> transformToNative(NamedList<NamedList> shardResponse, Sort groupSort, Sort sortWithinGroup, String shard) {
     Map<String, Pair<Integer, Collection<SearchGroup<BytesRef>>>> result = new HashMap<String, Pair<Integer, Collection<SearchGroup<BytesRef>>>>();
     for (Map.Entry<String, NamedList> command : shardResponse) {

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java Tue Jan  8 03:40:16 2013
@@ -17,7 +17,6 @@ package org.apache.solr.search.grouping.
  * limitations under the License.
  */
 
-import org.apache.lucene.document.Document;
 import org.apache.lucene.document.DocumentStoredFieldVisitor;
 import org.apache.lucene.index.StoredDocument;
 import org.apache.lucene.search.FieldDoc;
@@ -38,6 +37,8 @@ import org.apache.solr.search.grouping.C
 import org.apache.solr.search.grouping.distributed.command.QueryCommand;
 import org.apache.solr.search.grouping.distributed.command.QueryCommandResult;
 import org.apache.solr.search.grouping.distributed.command.TopGroupsFieldCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -53,6 +54,8 @@ public class TopGroupsResultTransformer 
 
   private final ResponseBuilder rb;
 
+  private static final Logger log = LoggerFactory.getLogger(TopGroupsResultTransformer.class);
+
   public TopGroupsResultTransformer(ResponseBuilder rb) {
     this.rb = rb;
   }
@@ -60,6 +63,7 @@ public class TopGroupsResultTransformer 
   /**
    * {@inheritDoc}
    */
+  @Override
   public NamedList transform(List<Command> data) throws IOException {
     NamedList<NamedList> result = new NamedList<NamedList>();
     for (Command command : data) {
@@ -83,6 +87,7 @@ public class TopGroupsResultTransformer 
   /**
    * {@inheritDoc}
    */
+  @Override
   public Map<String, ?> transformToNative(NamedList<NamedList> shardResponse, Sort groupSort, Sort sortWithinGroup, String shard) {
     Map<String, Object> result = new HashMap<String, Object>();
 
@@ -103,12 +108,24 @@ public class TopGroupsResultTransformer 
         ScoreDoc[] scoreDocs = new ScoreDoc[documents.size()];
         int j = 0;
         for (NamedList<Object> document : documents) {
-          Object uniqueId = document.get("id").toString();
+          Object docId = document.get("id");
+          Object uniqueId = null;
+          if (docId != null)
+            uniqueId = docId.toString();
+          else
+            log.warn("doc {} has null 'id'", document);
           Float score = (Float) document.get("score");
           if (score == null) {
             score = Float.NaN;
           }
-          Object[] sortValues = ((List) document.get("sortValues")).toArray();
+          Object[] sortValues = null;
+          Object sortValuesVal = document.get("sortValues");
+          if (sortValuesVal != null) {
+            sortValues = ((List) sortValuesVal).toArray();
+          }
+          else {
+            log.warn("doc {} has null 'sortValues'", document);
+          }
           scoreDocs[j++] = new ShardDoc(score, sortValues, uniqueId, shard);
         }
         result.put(key, new QueryCommandResult(new TopDocs(totalHits, scoreDocs, maxScore), matches));

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java Tue Jan  8 03:40:16 2013
@@ -48,6 +48,7 @@ public class GroupedEndResultTransformer
   /**
    * {@inheritDoc}
    */
+  @Override
   public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) {
     NamedList<Object> commands = new NamedList<Object>();
     for (Map.Entry<String, ?> entry : result.entrySet()) {

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/MainEndResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/MainEndResultTransformer.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/MainEndResultTransformer.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/MainEndResultTransformer.java Tue Jan  8 03:40:16 2013
@@ -35,6 +35,7 @@ public class MainEndResultTransformer im
   /**
    * {@inheritDoc}
    */
+  @Override
   public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) {
     Object value = result.get(rb.getGroupingSpec().getFields()[0]);
     if (TopGroups.class.isInstance(value)) {

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/SimpleEndResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/SimpleEndResultTransformer.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/SimpleEndResultTransformer.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/SimpleEndResultTransformer.java Tue Jan  8 03:40:16 2013
@@ -36,6 +36,7 @@ public class SimpleEndResultTransformer 
   /**
    * {@inheritDoc}
    */
+  @Override
   public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) {
     NamedList<Object> commands = new SimpleOrderedMap<Object>();
     for (Map.Entry<String, ?> entry : result.entrySet()) {

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java Tue Jan  8 03:40:16 2013
@@ -19,7 +19,8 @@ package org.apache.solr.servlet;
 
 import java.io.InputStream;
 import java.io.IOException;
-import java.io.PrintWriter;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
 
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -30,7 +31,6 @@ import org.apache.commons.lang.StringUti
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.solr.core.CoreContainer;
 
-
 /**
  * A simple servlet to load the Solr Admin UI
  * 
@@ -42,15 +42,15 @@ public final class LoadAdminUiServlet ex
   public void doGet(HttpServletRequest request,
                     HttpServletResponse response)
       throws IOException {
-    response.setCharacterEncoding("UTF-8");
-    response.setContentType("text/html");
+    // This attribute is set by the SolrDispatchFilter
+    CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
 
-    PrintWriter out = response.getWriter();
     InputStream in = getServletContext().getResourceAsStream("/admin.html");
-    if(in != null) {
+    if(in != null && cores != null) {
       try {
-        // This attribute is set by the SolrDispatchFilter
-        CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
+        response.setCharacterEncoding("UTF-8");
+        response.setContentType("text/html");
+        Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
 
         String html = IOUtils.toString(in, "UTF-8");
 
@@ -63,19 +63,14 @@ public final class LoadAdminUiServlet ex
             StringEscapeUtils.escapeJavaScript(cores.getAdminPath())
         };
         
-        out.println( StringUtils.replaceEach(html, search, replace) );
+        out.write( StringUtils.replaceEach(html, search, replace) );
+        out.flush();
       } finally {
         IOUtils.closeQuietly(in);
       }
     } else {
-      out.println("solr");
+      response.sendError(404);
     }
   }
 
-  @Override
-  public void doPost(HttpServletRequest request,
-                     HttpServletResponse response)
-      throws IOException {
-    doGet(request, response);
-  }
 }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/RedirectServlet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/RedirectServlet.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/RedirectServlet.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/RedirectServlet.java Tue Jan  8 03:40:16 2013
@@ -35,6 +35,7 @@ public class RedirectServlet extends Htt
   String destination;
   int code = HttpServletResponse.SC_MOVED_PERMANENTLY;
   
+  @Override
   public void init(ServletConfig config) throws ServletException {
     super.init(config);
     
@@ -53,6 +54,7 @@ public class RedirectServlet extends Htt
     }
   }
   
+  @Override
   public void doGet(HttpServletRequest req, HttpServletResponse res)
           throws ServletException,IOException {
       
@@ -60,8 +62,4 @@ public class RedirectServlet extends Htt
     res.setHeader("Location", destination);
   }
 
-  public void doPost(HttpServletRequest req, HttpServletResponse res)
-          throws ServletException,IOException {
-    doGet(req,res);
-  }
 }
\ No newline at end of file

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java Tue Jan  8 03:40:16 2013
@@ -17,13 +17,13 @@
 
 package org.apache.solr.servlet;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.nio.charset.Charset;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -45,6 +45,8 @@ import org.apache.solr.common.cloud.Slic
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.ContentStreamBase;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
@@ -53,7 +55,6 @@ import org.apache.solr.core.CoreContaine
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.handler.ContentStreamHandlerBase;
-import org.apache.solr.request.ServletSolrParams;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequestBase;
 import org.apache.solr.request.SolrRequestHandler;
@@ -66,7 +67,6 @@ import org.apache.solr.servlet.cache.Met
 import org.apache.solr.util.FastWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.xml.sax.InputSource;
 
 /**
  * This filter looks at the incoming URL maps them to handlers defined in solrconfig.xml
@@ -82,19 +82,10 @@ public class SolrDispatchFilter implemen
   protected String pathPrefix = null; // strip this from the beginning of a path
   protected String abortErrorMessage = null;
   protected final Map<SolrConfig, SolrRequestParsers> parsers = new WeakHashMap<SolrConfig, SolrRequestParsers>();
-  protected final SolrRequestParsers adminRequestParser;
   
   private static final Charset UTF8 = Charset.forName("UTF-8");
 
-  public SolrDispatchFilter() {
-    try {
-      adminRequestParser = new SolrRequestParsers(new Config(null,"solr",new InputSource(new ByteArrayInputStream("<root/>".getBytes("UTF-8"))),"") );
-    } catch (Exception e) {
-      //unlikely
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,e);
-    }
-  }
-
+  @Override
   public void init(FilterConfig config) throws ServletException
   {
     log.info("SolrDispatchFilter.init()");
@@ -125,6 +116,7 @@ public class SolrDispatchFilter implemen
     return new CoreContainer.Initializer();
   }
   
+  @Override
   public void destroy() {
     if (cores != null) {
       cores.shutdown();
@@ -132,6 +124,7 @@ public class SolrDispatchFilter implemen
     }    
   }
 
+  @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
     if( abortErrorMessage != null ) {
       ((HttpServletResponse)response).sendError( 500, abortErrorMessage );
@@ -177,14 +170,14 @@ public class SolrDispatchFilter implemen
         // Check for the core admin page
         if( path.equals( cores.getAdminPath() ) ) {
           handler = cores.getMultiCoreHandler();
-          solrReq =  adminRequestParser.parse(null,path, req);
+          solrReq =  SolrRequestParsers.DEFAULT.parse(null,path, req);
           handleAdminRequest(req, response, handler, solrReq);
           return;
         }
         // Check for the core admin collections url
         if( path.equals( "/admin/collections" ) ) {
           handler = cores.getCollectionsHandler();
-          solrReq =  adminRequestParser.parse(null,path, req);
+          solrReq =  SolrRequestParsers.DEFAULT.parse(null,path, req);
           handleAdminRequest(req, response, handler, solrReq);
           return;
         }
@@ -472,7 +465,15 @@ public class SolrDispatchFilter implemen
         core = cores.getCore(""); // default core
       }
       if(req==null) {
-        req = new SolrQueryRequestBase(core,new ServletSolrParams(request)) {};
+        final SolrParams solrParams;
+        if (request instanceof HttpServletRequest) {
+          // use GET parameters if available:
+          solrParams = SolrRequestParsers.parseQueryString(((HttpServletRequest) request).getQueryString());
+        } else {
+          // we have no params at all, use empty ones:
+          solrParams = new MapSolrParams(Collections.<String,String>emptyMap());
+        }
+        req = new SolrQueryRequestBase(core, solrParams) {};
       }
       QueryResponseWriter writer = core.getQueryResponseWriter(req);
       writeResponse(solrResp, response, writer, req, Method.GET);

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java Tue Jan  8 03:40:16 2013
@@ -32,6 +32,8 @@ import java.util.Locale;
 import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.input.BoundedInputStream;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -46,7 +48,6 @@ import org.apache.solr.common.util.Conte
 import org.apache.solr.common.util.ContentStreamBase;
 import org.apache.solr.core.Config;
 import org.apache.solr.core.SolrCore;
-import org.apache.solr.request.ServletSolrParams;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequestBase;
 
@@ -57,47 +58,63 @@ public class SolrRequestParsers 
   
   // Should these constants be in a more public place?
   public static final String MULTIPART = "multipart";
+  public static final String FORMDATA = "formdata";
   public static final String RAW = "raw";
   public static final String SIMPLE = "simple";
   public static final String STANDARD = "standard";
   
-  private HashMap<String, SolrRequestParser> parsers;
-  private boolean enableRemoteStreams = false;
-  private boolean handleSelect = true;
+  private final HashMap<String, SolrRequestParser> parsers =
+      new HashMap<String, SolrRequestParser>();
+  private final boolean enableRemoteStreams;
   private StandardRequestParser standard;
+  private boolean handleSelect = true;
   
+  /** Default instance for e.g. admin requests. Limits to 2 MB uploads and does not allow remote streams. */
+  public static final SolrRequestParsers DEFAULT = new SolrRequestParsers();
+
   /**
    * Pass in an xml configuration.  A null configuration will enable
-   * everythign with maximum values.
+   * everything with maximum values.
    */
-  public SolrRequestParsers( Config globalConfig )
-  {
-    long uploadLimitKB = 1048;  // 2MB default
+  public SolrRequestParsers( Config globalConfig ) {
+    final int multipartUploadLimitKB, formUploadLimitKB;
     if( globalConfig == null ) {
-      uploadLimitKB = Long.MAX_VALUE; 
+      multipartUploadLimitKB = formUploadLimitKB = Integer.MAX_VALUE; 
       enableRemoteStreams = true;
       handleSelect = true;
-    }
-    else {
-      uploadLimitKB = globalConfig.getInt( 
-          "requestDispatcher/requestParsers/@multipartUploadLimitInKB", (int)uploadLimitKB );
+    } else {
+      multipartUploadLimitKB = globalConfig.getInt( 
+          "requestDispatcher/requestParsers/@multipartUploadLimitInKB", 2048 );
+      
+      formUploadLimitKB = globalConfig.getInt( 
+          "requestDispatcher/requestParsers/@formdataUploadLimitInKB", 2048 );
       
       enableRemoteStreams = globalConfig.getBool( 
           "requestDispatcher/requestParsers/@enableRemoteStreaming", false ); 
   
       // Let this filter take care of /select?xxx format
       handleSelect = globalConfig.getBool( 
-          "requestDispatcher/@handleSelect", handleSelect ); 
+          "requestDispatcher/@handleSelect", true ); 
     }
-       
-    MultipartRequestParser multi = new MultipartRequestParser( uploadLimitKB );
+    init(multipartUploadLimitKB, formUploadLimitKB);
+  }
+  
+  private SolrRequestParsers() {
+    enableRemoteStreams = false;
+    handleSelect = false;
+    init(2048, 2048);
+  }
+
+  private void init( int multipartUploadLimitKB, int formUploadLimitKB) {       
+    MultipartRequestParser multi = new MultipartRequestParser( multipartUploadLimitKB );
     RawRequestParser raw = new RawRequestParser();
-    standard = new StandardRequestParser( multi, raw );
+    FormDataRequestParser formdata = new FormDataRequestParser( formUploadLimitKB );
+    standard = new StandardRequestParser( multi, raw, formdata );
     
     // I don't see a need to have this publicly configured just yet
     // adding it is trivial
-    parsers = new HashMap<String, SolrRequestParser>();
     parsers.put( MULTIPART, multi );
+    parsers.put( FORMDATA, formdata );
     parsers.put( RAW, raw );
     parsers.put( SIMPLE, new SimpleRequestParser() );
     parsers.put( STANDARD, standard );
@@ -175,24 +192,32 @@ public class SolrRequestParsers 
     return q;
   }
   
-
   /**
-   * Given a standard query string map it into solr params
+   * Given a url-encoded query string (UTF-8), map it into solr params
    */
-  public static MultiMapSolrParams parseQueryString(String queryString) 
-  {
+  public static MultiMapSolrParams parseQueryString(String queryString) {
     Map<String,String[]> map = new HashMap<String, String[]>();
+    parseQueryString(queryString, "UTF-8", map);
+    return new MultiMapSolrParams(map);
+  }
+
+  /**
+   * Given a url-encoded query string, map it into the given map
+   * @param queryString as given from URL
+   * @param charset to be used to decode %-encoding
+   * @param map place all parameters in this map
+   */
+  static void parseQueryString(String queryString, String charset, Map<String,String[]> map) {
     if( queryString != null && queryString.length() > 0 ) {
       try {
         for( String kv : queryString.split( "&" ) ) {
           int idx = kv.indexOf( '=' );
-          if( idx > 0 ) {
-            String name = URLDecoder.decode( kv.substring( 0, idx ), "UTF-8");
-            String value = URLDecoder.decode( kv.substring( idx+1 ), "UTF-8");
+          if( idx >= 0 ) {
+            String name = URLDecoder.decode( kv.substring( 0, idx ), charset);
+            String value = URLDecoder.decode( kv.substring( idx+1 ), charset);
             MultiMapSolrParams.addParam( name, value, map );
-          }
-          else {
-            String name = URLDecoder.decode( kv, "UTF-8" );
+          } else {
+            String name = URLDecoder.decode( kv, charset );
             MultiMapSolrParams.addParam( name, "", map );
           }
         }
@@ -201,7 +226,6 @@ public class SolrRequestParsers 
         throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, uex );
       }
     }
-    return new MultiMapSolrParams( map );
   }
 
   public boolean isHandleSelect() {
@@ -228,14 +252,15 @@ interface SolrRequestParser 
 //-----------------------------------------------------------------
 
 /**
- * The simple parser just uses the params directly
+ * The simple parser just uses the params directly, does not support POST URL-encoded forms
  */
 class SimpleRequestParser implements SolrRequestParser
 {
+  @Override
   public SolrParams parseParamsAndFillStreams( 
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
-    return new ServletSolrParams(req);
+    return SolrRequestParsers.parseQueryString(req.getQueryString());
   }
 }
 
@@ -259,6 +284,7 @@ class HttpRequestContentStream extends C
     }
   }
 
+  @Override
   public InputStream getStream() throws IOException {
     return req.getInputStream();
   }
@@ -281,6 +307,7 @@ class FileItemContentStream extends Cont
     size = item.getSize();
   }
     
+  @Override
   public InputStream getStream() throws IOException {
     return item.getInputStream();
   }
@@ -291,16 +318,10 @@ class FileItemContentStream extends Cont
  */
 class RawRequestParser implements SolrRequestParser
 {
+  @Override
   public SolrParams parseParamsAndFillStreams( 
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
-    // The javadocs for HttpServletRequest are clear that req.getReader() should take
-    // care of any character encoding issues.  BUT, there are problems while running on
-    // some servlet containers: including Tomcat 5 and resin.
-    //
-    // Rather than return req.getReader(), this uses the default ContentStreamBase method
-    // that checks for charset definitions in the ContentType.
-    
     streams.add( new HttpRequestContentStream( req ) );
     return SolrRequestParsers.parseQueryString( req.getQueryString() );
   }
@@ -313,13 +334,14 @@ class RawRequestParser implements SolrRe
  */
 class MultipartRequestParser implements SolrRequestParser
 {
-  private long uploadLimitKB;
+  private final int uploadLimitKB;
   
-  public MultipartRequestParser( long limit )
+  public MultipartRequestParser( int limit )
   {
     uploadLimitKB = limit;
   }
   
+  @Override
   public SolrParams parseParamsAndFillStreams( 
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
@@ -338,7 +360,7 @@ class MultipartRequestParser implements 
 
     // Create a new file upload handler
     ServletFileUpload upload = new ServletFileUpload(factory);
-    upload.setSizeMax( uploadLimitKB*1024 );
+    upload.setSizeMax( ((long) uploadLimitKB) * 1024L );
 
     // Parse the request
     List items = upload.parseRequest(req);
@@ -363,39 +385,126 @@ class MultipartRequestParser implements 
 
 
 /**
+ * Extract application/x-www-form-urlencoded form data for POST requests
+ */
+class FormDataRequestParser implements SolrRequestParser
+{
+  private final int uploadLimitKB;
+  
+  public FormDataRequestParser( int limit )
+  {
+    uploadLimitKB = limit;
+  }
+  
+  @Override
+  public SolrParams parseParamsAndFillStreams( 
+      final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
+  {
+    if (!isFormData(req)) {
+      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Not application/x-www-form-urlencoded content: "+req.getContentType() );
+    }
+    
+    String charset = ContentStreamBase.getCharsetFromContentType(req.getContentType());
+    if (charset == null) charset = "UTF-8";
+    
+    final Map<String,String[]> map = new HashMap<String, String[]>();
+    
+    // also add possible URL parameters and include into the map (parsed using UTF-8):
+    final String qs = req.getQueryString();
+    if (qs != null) {
+      SolrRequestParsers.parseQueryString(qs, "UTF-8", map);
+    }
+    
+    // may be -1, so we check again later. But if its already greater we can stop processing!
+    final long totalLength = req.getContentLength();
+    final long maxLength = ((long) uploadLimitKB) * 1024L;
+    if (totalLength > maxLength) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content length (" +
+        totalLength + " bytes) exceeds upload limit of " + uploadLimitKB + " KB");
+    }
+    
+    // get query String from request body, using the charset given in content-type:
+    final InputStream in;
+    try {
+      in = req.getInputStream();
+    } catch (IllegalStateException ise) {
+      throw (SolrException) getParameterIncompatibilityException().initCause(ise);
+    }
+    try {
+      final String data = IOUtils.toString(new BoundedInputStream(in, maxLength), charset);
+      // if there is remaining data in the underlying stream, throw exception:
+      if (in.read() != -1) {
+        // read remaining data and throw away:
+        while (IOUtils.skip(in, 1024L) > 0);
+        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content exceeds upload limit of " + uploadLimitKB + " KB");
+      }
+      if (data.length() == 0 && totalLength > 0L) {
+        throw getParameterIncompatibilityException();
+      }
+      SolrRequestParsers.parseQueryString(data, charset, map);
+    } finally {
+      IOUtils.closeQuietly(in);
+    }
+    
+    return new MultiMapSolrParams(map);
+  }
+  
+  private SolrException getParameterIncompatibilityException() {
+    return new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+      "Solr requires that request parameters sent using application/x-www-form-urlencoded " +
+      "content-type can be read through the request input stream. Unfortunately, the " +
+      "stream was empty / not available. This may be caused by another servlet filter calling " +
+      "ServletRequest.getParameter*() before SolrDispatchFilter, please remove it."
+    );
+  }
+  
+  public boolean isFormData(HttpServletRequest req) {
+    String contentType = req.getContentType();
+    if (contentType != null) {
+      int idx = contentType.indexOf( ';' );
+      if( idx > 0 ) { // remove the charset definition "; charset=utf-8"
+        contentType = contentType.substring( 0, idx );
+      }
+      contentType = contentType.trim();
+      if( "application/x-www-form-urlencoded".equalsIgnoreCase(contentType)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
+
+/**
  * The default Logic
  */
 class StandardRequestParser implements SolrRequestParser
 {
   MultipartRequestParser multipart;
   RawRequestParser raw;
+  FormDataRequestParser formdata;
   
-  StandardRequestParser( MultipartRequestParser multi, RawRequestParser raw ) 
+  StandardRequestParser(MultipartRequestParser multi, RawRequestParser raw, FormDataRequestParser formdata) 
   {
     this.multipart = multi;
     this.raw = raw;
+    this.formdata = formdata;
   }
   
+  @Override
   public SolrParams parseParamsAndFillStreams( 
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
     String method = req.getMethod().toUpperCase(Locale.ROOT);
-    if( "GET".equals( method ) || "HEAD".equals( method )) {
-      return new ServletSolrParams(req);
+    if ("GET".equals(method) || "HEAD".equals(method)) {
+      return SolrRequestParsers.parseQueryString(req.getQueryString());
     }
-    if( "POST".equals( method ) ) {
-      String contentType = req.getContentType();
-      if( contentType != null ) {
-        int idx = contentType.indexOf( ';' );
-        if( idx > 0 ) { // remove the charset definition "; charset=utf-8"
-          contentType = contentType.substring( 0, idx );
-        }
-        if( "application/x-www-form-urlencoded".equals( contentType.toLowerCase(Locale.ROOT) ) ) {
-          return new ServletSolrParams(req); // just get the params from parameterMap
-        }
-        if( ServletFileUpload.isMultipartContent(req) ) {
-          return multipart.parseParamsAndFillStreams(req, streams);
-        }
+    if ("POST".equals( method ) ) {
+      if (formdata.isFormData(req)) {
+        return formdata.parseParamsAndFillStreams(req, streams);
+      }
+      if (ServletFileUpload.isMultipartContent(req)) {
+        return multipart.parseParamsAndFillStreams(req, streams);
       }
       return raw.parseParamsAndFillStreams(req, streams);
     }

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java Tue Jan  8 03:40:16 2013
@@ -18,21 +18,28 @@
 package org.apache.solr.servlet;
 
 import java.io.IOException;
-import java.io.PrintWriter;
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
 import java.net.URLEncoder;
 import java.util.Date;
 import java.util.List;
 
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.IOUtils;
 import org.apache.noggit.CharArr;
 import org.apache.noggit.JSONWriter;
 import org.apache.solr.cloud.ZkController;
+import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.core.CoreContainer;
+import org.apache.solr.util.FastWriter;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
@@ -46,7 +53,7 @@ import org.slf4j.LoggerFactory;
  */
 public final class ZookeeperInfoServlet extends HttpServlet {
   static final Logger log = LoggerFactory.getLogger(ZookeeperInfoServlet.class);
-
+  
   @Override
   public void init() {
   }
@@ -54,28 +61,42 @@ public final class ZookeeperInfoServlet 
   @Override
   public void doGet(HttpServletRequest request,
                     HttpServletResponse response)
-      throws IOException {
-    response.setCharacterEncoding("UTF-8");
-    response.setContentType("application/json");
-
+      throws ServletException,IOException {
     // This attribute is set by the SolrDispatchFilter
     CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
+    if (cores == null) {
+      throw new ServletException("Missing request attribute org.apache.solr.CoreContainer.");
+    }
+    
+    final SolrParams params;
+    try {
+      params = SolrRequestParsers.DEFAULT.parse(null, request.getServletPath(), request).getParams();
+    } catch (Exception e) {
+      int code=500;
+      if (e instanceof SolrException) {
+        code = Math.min(599, Math.max(100, ((SolrException)e).code()));
+      }
+      response.sendError(code, e.toString());
+      return;
+    }
 
-    String path = request.getParameter("path");
-    String addr = request.getParameter("addr");
+    String path = params.get("path");
+    String addr = params.get("addr");
 
     if (addr != null && addr.length() == 0) {
       addr = null;
     }
 
-    String detailS = request.getParameter("detail");
+    String detailS = params.get("detail");
     boolean detail = detailS != null && detailS.equals("true");
 
-    String dumpS = request.getParameter("dump");
+    String dumpS = params.get("dump");
     boolean dump = dumpS != null && dumpS.equals("true");
 
-    PrintWriter out = response.getWriter();
+    response.setCharacterEncoding("UTF-8");
+    response.setContentType("application/json");
 
+    Writer out = new FastWriter(new OutputStreamWriter(response.getOutputStream(), IOUtils.CHARSET_UTF_8));
 
     ZKPrinter printer = new ZKPrinter(response, out, cores.getZkController(), addr);
     printer.detail = detail;
@@ -86,12 +107,14 @@ public final class ZookeeperInfoServlet 
     } finally {
       printer.close();
     }
+    
+    out.flush();
   }
 
   @Override
   public void doPost(HttpServletRequest request,
                      HttpServletResponse response)
-      throws IOException {
+      throws ServletException,IOException {
     doGet(request, response);
   }
 
@@ -114,13 +137,13 @@ public final class ZookeeperInfoServlet 
     boolean doClose;  // close the client after done if we opened it
 
     final HttpServletResponse response;
-    final PrintWriter out;
+    final Writer out;
     SolrZkClient zkClient;
 
     int level;
     int maxData = 95;
 
-    public ZKPrinter(HttpServletResponse response, PrintWriter out, ZkController controller, String addr) throws IOException {
+    public ZKPrinter(HttpServletResponse response, Writer out, ZkController controller, String addr) throws IOException {
       this.response = response;
       this.out = out;
       this.addr = addr;
@@ -207,10 +230,10 @@ public final class ZookeeperInfoServlet 
       }
       json.endArray();
       json.endObject();
-      out.println(chars.toString());
+      out.write(chars.toString());
     }
 
-    void writeError(int code, String msg) {
+    void writeError(int code, String msg) throws IOException {
       response.setStatus(code);
 
       CharArr chars = new CharArr();
@@ -227,7 +250,7 @@ public final class ZookeeperInfoServlet 
       w.writeString(msg);
       w.endObject();
 
-      out.println(chars.toString());
+      out.write(chars.toString());
     }
 
 
@@ -352,7 +375,7 @@ public final class ZookeeperInfoServlet 
       json.write(v);
     }
 
-    boolean printZnode(JSONWriter json, String path) {
+    boolean printZnode(JSONWriter json, String path) throws IOException {
       try {
         Stat stat = new Stat();
         // Trickily, the call to zkClient.getData fills in the stat variable

Modified: lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/spelling/PossibilityIterator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/spelling/PossibilityIterator.java?rev=1430130&r1=1430129&r2=1430130&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/spelling/PossibilityIterator.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/java/org/apache/solr/spelling/PossibilityIterator.java Tue Jan  8 03:40:16 2013
@@ -346,14 +346,17 @@ public class PossibilityIterator impleme
     return false;
   }
   
+  @Override
   public boolean hasNext() {
     return rankedPossibilityIterator.hasNext();
   }
   
+  @Override
   public PossibilityIterator.RankedSpellPossibility next() {
     return rankedPossibilityIterator.next();
   }
   
+  @Override
   public void remove() {
     throw new UnsupportedOperationException();
   }
@@ -388,6 +391,7 @@ public class PossibilityIterator impleme
       return true;
     }
     
+    @Override
     public String toString() {
       StringBuilder sb = new StringBuilder();
       sb.append("rank=").append(rank).append(" (").append(index).append(")");
@@ -413,6 +417,7 @@ public class PossibilityIterator impleme
   
   private class RankComparator implements Comparator<RankedSpellPossibility> {
     // Rank poorer suggestions ahead of better ones for use with a PriorityQueue
+    @Override
     public int compare(RankedSpellPossibility r1, RankedSpellPossibility r2) {
       int retval = r2.rank - r1.rank;
       if (retval == 0) {