diff --git a/CHANGES.txt b/CHANGES.txt
index 1e23d0d6073..373e3337dcb 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -151,6 +151,11 @@ Changes in runtime behavior
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
diff --git a/src/java/org/apache/solr/request/RequiredSolrParams.java b/src/java/org/apache/solr/request/RequiredSolrParams.java
new file mode 100755
index 00000000000..e18d09d40e1
--- /dev/null
+++ b/src/java/org/apache/solr/request/RequiredSolrParams.java
@@ -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 RequiredSolrParams
+ * will return a valid non-null value or throw a 400 exception.
+ * (If you pass in null 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 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);
+ }
+}
diff --git a/src/java/org/apache/solr/request/SolrParams.java b/src/java/org/apache/solr/request/SolrParams.java
index dd2d5e1718f..37eecb3e35b 100644
--- a/src/java/org/apache/solr/request/SolrParams.java
+++ b/src/java/org/apache/solr/request/SolrParams.java
@@ -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 @@ public abstract class SolrParams {
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 @@ public abstract class SolrParams {
/** 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 from a NamedList given no keys are repeated */
@@ -258,8 +298,8 @@ public abstract class SolrParams {
}
/** Convert this to a NamedList */
- public NamedList toNamedList() {
- final SimpleOrderedMap result = new SimpleOrderedMap();
+ public NamedList