You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by yo...@apache.org on 2007/03/24 22:10:20 UTC

svn commit: r522106 - in /lucene/solr/trunk: CHANGES.txt src/java/org/apache/solr/request/RequiredSolrParams.java src/java/org/apache/solr/request/SolrParams.java src/test/org/apache/solr/util/SolrParamTest.java

Author: yonik
Date: Sat Mar 24 14:10:19 2007
New Revision: 522106

URL: http://svn.apache.org/viewvc?view=rev&rev=522106
Log:
400 errors for numeric parsing exceptions, RequiredSolrParams: SOLR-183

Added:
    lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java   (with props)
    lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java   (with props)
Modified:
    lucene/solr/trunk/CHANGES.txt
    lucene/solr/trunk/src/java/org/apache/solr/request/SolrParams.java

Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?view=diff&rev=522106&r1=522105&r2=522106
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Sat Mar 24 14:10:19 2007
@@ -151,6 +151,11 @@
     a unique id if it is declared in the schema and allowDups=false.
     (ryan via klaas)
 
+17. SOLR-183: Exceptions with error code 400 are raised when
+    numeric argument parsing fails.  RequiredSolrParams class added
+    to facilitate checking for parameters that must be present.
+    (Ryan McKinley, J.J. Larrea via yonik)
+
 Optimizations 
  1. SOLR-114: HashDocSet specific implementations of union() and andNot()
     for a 20x performance improvement for those set operations, and a new

Added: lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java?view=auto&rev=522106
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java Sat Mar 24 14:10:19 2007
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.request;
+
+import org.apache.solr.core.SolrException;
+
+import java.util.Iterator;
+
+/**
+ * This is a simple wrapper to SolrParams that will throw a 400
+ * exception if you ask for a parameter that does not exist.  Fields
+ * specified with
+ * 
+ * In short, any value you for from a <code>RequiredSolrParams</code> 
+ * will return a valid non-null value or throw a 400 exception.  
+ * (If you pass in <code>null</code> as the default value, you can 
+ * get a null return value)
+ * 
+ * @author jjl
+ * @version $Id$
+ * @since solr 1.2
+ */
+public class RequiredSolrParams extends SolrParams {
+  protected final SolrParams params;
+  
+  public RequiredSolrParams(SolrParams params) {
+    this.params = params;
+  }
+
+  /** get the param from params, fail if not found **/
+  @Override
+  public String get(String param) {
+    String val = params.get(param);
+    if( val == null )  {
+      throw new SolrException( 400, "Missing required parameter: "+param );
+    }
+    return val;
+  }
+
+  @Override
+  public String[] getParams(String param) {
+    String[] vals = params.getParams(param);
+    if( vals == null || vals.length == 0 ) {
+      throw new SolrException( 400, "Missing required parameter: "+param );
+    }
+    return vals;
+  }
+  
+  /** returns an Iterator over the parameter names */
+  @Override
+  public Iterator<String> getParameterNamesIterator() {
+    return params.getParameterNamesIterator();
+  }
+
+  @Override
+  public String toString() {
+    return "{required("+params+")}";  
+  }    
+
+  //----------------------------------------------------------
+  // Functions with a default value - pass directly to the
+  // wrapped SolrParams (they won't return null - unless its the default)
+  //----------------------------------------------------------
+
+  @Override
+  public String get(String param, String def) {
+    return params.get(param, def);
+  }
+
+  @Override
+  public int getInt(String param, int def) {
+    return params.getInt(param, def);
+  }
+
+  @Override
+  public float getFloat(String param, float def) {
+    return params.getFloat(param, def);
+  }
+  
+  @Override
+  public boolean getBool(String param, boolean def) {
+    return params.getBool(param, def);
+  }
+
+  @Override
+  public int getFieldInt(String field, String param, int def) {
+    return params.getFieldInt(field, param, def);
+  }
+  
+  @Override
+  public boolean getFieldBool(String field, String param, boolean def) {
+    return params.getFieldBool(field, param, def);
+  }
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: lucene/solr/trunk/src/java/org/apache/solr/request/RequiredSolrParams.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/solr/trunk/src/java/org/apache/solr/request/SolrParams.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/request/SolrParams.java?view=diff&rev=522106&r1=522105&r2=522106
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/request/SolrParams.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/request/SolrParams.java Sat Mar 24 14:10:19 2007
@@ -17,18 +17,13 @@
 
 package org.apache.solr.request;
 
-import org.apache.solr.util.NamedList;
-import org.apache.solr.util.StrUtils;
-import org.apache.solr.util.SimpleOrderedMap;
-
-import javax.servlet.ServletRequest;
-
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
-import java.io.IOException;
+
+import org.apache.solr.core.SolrException;
+import org.apache.solr.util.NamedList;
+import org.apache.solr.util.SimpleOrderedMap;
 
 /**  SolrParams hold request parameters.
  *
@@ -142,6 +137,13 @@
     return val==null ? def : val;
   }
   
+  /** returns a RequiredSolrParams wrapping this */
+  public RequiredSolrParams required()
+  {
+    // TODO? should we want to stash a reference?
+    return new RequiredSolrParams(this);
+  }
+  
   protected String fpname(String field, String param) {
     return "f."+field+'.'+param;
   }
@@ -183,47 +185,85 @@
   /** Returns the Integer value of the param, or null if not set */
   public Integer getInt(String param) {
     String val = get(param);
-    return val==null ? null : Integer.parseInt(val);
+    try {
+      return val==null ? null : Integer.valueOf(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( 400, ex.getMessage(), ex );
+    }
   }
 
   /** Returns the int value of the param, or def if not set */
   public int getInt(String param, int def) {
     String val = get(param);
-    return val==null ? def : Integer.parseInt(val);
+    try {
+      return val==null ? def : Integer.parseInt(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( 400, ex.getMessage(), ex );
+    }
   }
-
+  
   /** Returns the int value of the field param,
   or the value for param, or def if neither is set. */
   public Integer getFieldInt(String field, String param) {
     String val = getFieldParam(field, param);
-    return val==null ? null : Integer.parseInt(val);
+    try {
+      return val==null ? null : Integer.valueOf(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( 400, ex.getMessage(), ex );
+    }
   }
   
   /** Returns the int value of the field param, 
   or the value for param, or def if neither is set. */
   public int getFieldInt(String field, String param, int def) {
     String val = getFieldParam(field, param);
-    return val==null ? def : Integer.parseInt(val);
+    try {
+      return val==null ? def : Integer.parseInt(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( 400, ex.getMessage(), ex );
+    }
   }
 
 
   /** Returns the Float value of the param, or null if not set */
   public Float getFloat(String param) {
     String val = get(param);
-    return val==null ? null : Float.parseFloat(val);
+    try {
+      return val==null ? null : Float.valueOf(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( 400, ex.getMessage(), ex );
+    }
   }
 
   /** Returns the float value of the param, or def if not set */
   public float getFloat(String param, float def) {
     String val = get(param);
-    return val==null ? def : Float.parseFloat(val);
+    try {
+      return val==null ? def : Float.parseFloat(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( 400, ex.getMessage(), ex );
+    }
   }
 
   /** how to transform a String into a boolean... more flexible than
    * Boolean.parseBoolean() to enable easier integration with html forms.
    */
   protected boolean parseBool(String s) {
-    return s.startsWith("true") || s.startsWith("on") || s.startsWith("yes");
+    if( s != null ) {
+      if( s.startsWith("true") || s.startsWith("on") || s.startsWith("yes") ) {
+        return true;
+      }
+      if( s.startsWith("false") || s.startsWith("off") || s.equals("no") ) {
+        return false;
+      }
+    }
+    throw new SolrException( 400, "invalid boolean value: "+s );
   }
 
   /** Create a Map<String,String> from a NamedList given no keys are repeated */
@@ -258,8 +298,8 @@
   }
   
   /** Convert this to a NamedList */
-  public NamedList toNamedList() {
-    final SimpleOrderedMap result = new SimpleOrderedMap();
+  public NamedList<Object> toNamedList() {
+    final SimpleOrderedMap<Object> result = new SimpleOrderedMap<Object>();
     
     for(Iterator<String> it=getParameterNamesIterator(); it.hasNext(); ) {
       final String name = it.next();

Added: lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java?view=auto&rev=522106
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java (added)
+++ lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java Sat Mar 24 14:10:19 2007
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.core.SolrException;
+import org.apache.solr.request.SolrParams;
+import org.apache.solr.request.MapSolrParams;
+import org.apache.solr.request.DefaultSolrParams;
+
+/**
+ * @author ryan
+ */
+public class SolrParamTest extends TestCase 
+{  
+  public void testGetParams() {
+    Map<String,String> pmap = new HashMap<String, String>();
+    pmap.put( "str"        , "string"   );
+    pmap.put( "bool"       , "true"     );
+    pmap.put( "true-0"     , "true"     );
+    pmap.put( "true-1"     , "yes"      );
+    pmap.put( "true-2"     , "on"       );
+    pmap.put( "false-0"    , "false"    );
+    pmap.put( "false-1"    , "off"      );
+    pmap.put( "false-2"    , "no"       );
+    pmap.put( "int"        , "100"      );
+    pmap.put( "float"      , "10.6"     );
+    pmap.put( "f.fl.str"   , "string"   );
+    pmap.put( "f.fl.bool"  , "true"     );
+    pmap.put( "f.fl.int"   , "100"      );
+    pmap.put( "f.fl.float" , "10.6"     );
+    pmap.put( "f.bad.bool" , "notbool"  );
+    pmap.put( "f.bad.int"  , "notint"   );
+    pmap.put( "f.bad.float", "notfloat" );
+    final SolrParams params = new MapSolrParams( pmap );
+    
+    // Test the string values we put in directly
+    assertEquals(  "string"   , params.get( "str"       ) );
+    assertEquals(  "true"     , params.get( "bool"      ) );
+    assertEquals(  "100"      , params.get( "int"       ) );
+    assertEquals(  "10.6"     , params.get( "float"     ) );
+    assertEquals(  "string"   , params.get( "f.fl.str"    ) );
+    assertEquals(  "true"     , params.get( "f.fl.bool"   ) );
+    assertEquals(  "100"      , params.get( "f.fl.int"    ) );
+    assertEquals(  "10.6"     , params.get( "f.fl.float"  ) );
+    assertEquals(  "notbool"  , params.get( "f.bad.bool"  ) );
+    assertEquals(  "notint"   , params.get( "f.bad.int"   ) );
+    assertEquals(  "notfloat" , params.get( "f.bad.float" ) );
+    
+    final String  pstr = "string";
+    final Boolean pbool = Boolean.TRUE;
+    final Integer pint = new Integer( 100 );
+    final Float   pfloat = new Float( 10.6f );
+    
+    // Make sure they parse ok
+    assertEquals( pstr   , params.get(      "str"      ) );
+    assertEquals( pbool  , params.getBool(  "bool"     ) );
+    assertEquals( pint   , params.getInt(   "int"      ) );
+    assertEquals( pfloat , params.getFloat( "float"    ) );
+    assertEquals( pbool  , params.getBool(  "f.fl.bool"  ) );
+    assertEquals( pint   , params.getInt(   "f.fl.int"   ) );
+    assertEquals( pfloat , params.getFloat( "f.fl.float" ) );
+    assertEquals( pstr   , params.getFieldParam( "fl", "str"  ) );
+    assertEquals( pbool  , params.getFieldBool(  "fl", "bool" ) );
+    assertEquals( pint   , params.getFieldInt(   "fl", "int"  ) );
+
+    // Test field defaulting (fall through to non-field-specific value)
+    assertEquals( pint   , params.getFieldInt( "fff",  "int"      ) );
+    
+    // test boolean parsing
+    for( int i=0; i<3; i++ ) {
+      // Must use Boolean rather than boolean reference value to prevent
+      // auto-unboxing ambiguity
+      assertEquals( Boolean.TRUE,  params.getBool( "true-"+i  ) );
+      assertEquals( Boolean.FALSE, params.getBool( "false-"+i ) );
+    }
+    
+    // Malformed params: These should throw a 400
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { params.getInt(   "f.bad.int" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { params.getBool(  "f.bad.bool" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { params.getFloat( "f.bad.float" ); } } ) );
+    
+    // Ask for params that arent there
+    assertNull( params.get( "asagdsaga" ) );
+    assertNull( params.getBool( "asagdsaga" ) );
+    assertNull( params.getInt( "asagdsaga" ) );
+    assertNull( params.getFloat( "asagdsaga" ) );
+    
+    // Get things with defaults
+    assertEquals( pstr                  , params.get(          "xxx", pstr   ) );
+    assertEquals( pbool.booleanValue()  , params.getBool(      "xxx", pbool   ) );
+    assertEquals( pint.intValue()       , params.getInt(       "xxx", pint   ) );
+    assertEquals( pfloat.floatValue()   , params.getFloat(     "xxx", pfloat  ) );
+    assertEquals( pbool.booleanValue()  , params.getFieldBool( "xxx", "bool", pbool ) );
+    assertEquals( pint.intValue()       , params.getFieldInt(  "xxx", "int", pint  ) );
+
+    // Required params testing uses decorator
+    final SolrParams required = params.required();
+    
+    // Required params which are present should test same as above
+    assertEquals( pstr   , required.get(      "str"      ) );
+    assertEquals( pbool  , required.getBool(  "bool"     ) );
+    assertEquals( pint   , required.getInt(   "int"      ) );
+    assertEquals( pfloat , required.getFloat( "float"    ) );
+    
+    // field value present
+    assertEquals( pbool  , required.getFieldBool(  "fl", "bool" ) );
+    // field defaulting (fall through to non-field-specific value)
+    //assertEquals( pint   , required.getFieldInt( "fff",  "int"      ) );
+    
+    // Required params which are missing: These should throw a 400
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.get( "aaaa" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.getInt(   "f.bad.int" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.getBool(  "f.bad.bool" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.getFloat( "f.bad.float" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.getInt(   "aaa" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.getBool(  "aaa" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { required.getFloat( "aaa" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { params.getFieldBool(  "bad", "bool" ); } } ) );
+    assertEquals( 400, getReturnCode( new Runnable() { public void run() { params.getFieldInt(   "bad", "int"  ); } } ) );
+
+    // Fields with default use their parent value:
+    assertEquals(
+        params.get(   "aaaa", "str" ), 
+        required.get( "aaaa", "str" ) );
+    assertEquals(
+        params.getInt(   "f.bad.nnnn", pint ), 
+        required.getInt( "f.bad.nnnn", pint ) );
+    
+    // Check default SolrParams
+    Map<String,String> dmap = new HashMap<String, String>();
+    // these are not defined in params
+    dmap.put( "dstr"               , "default"   );
+    dmap.put( "dint"               , "123"       );
+    // these are defined in params
+    dmap.put( "int"                , "456"       );
+    SolrParams defaults = new DefaultSolrParams( params, new MapSolrParams( dmap ) );
+  
+    // in params, not in default
+    assertEquals( pstr                  , defaults.get( "str"      ) );
+    // in default, not in params
+    assertEquals( "default"             , defaults.get( "dstr"      ) );
+    assertEquals( new Integer(123)      , defaults.getInt(  "dint"     ) );
+    // in params, overriding defaults
+    assertEquals( pint                  , defaults.getInt(   "int"      ) );
+    // in neither params nor defaults
+    assertNull( defaults.get( "asagdsaga" ) );
+  }
+  
+  public static int getReturnCode( Runnable runnable )
+  {
+    try {
+      runnable.run();
+    }
+    catch( SolrException sx ) {
+      return sx.code();
+    }
+    catch( Exception ex ) {
+      ex.printStackTrace();
+      return 500;
+    }
+    return 200;
+  }
+}

Propchange: lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: lucene/solr/trunk/src/test/org/apache/solr/util/SolrParamTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL