SOLR-5264 - move config argument retrieval/removal from Update Processor code to NamedList

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1528680 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Shawn Heisey 2013-10-02 23:45:25 +00:00
parent 2cb0a5c0da
commit 86a0b893fe
8 changed files with 197 additions and 30 deletions

View File

@ -217,7 +217,7 @@ public class AddSchemaFieldsUpdateProcessorFactory extends UpdateRequestProcesso
String fieldType = fieldTypeObj.toString();
Collection<String> valueClasses
= FieldMutatingUpdateProcessorFactory.oneOrMany(typeMappingNamedList, VALUE_CLASS_PARAM);
= typeMappingNamedList.removeConfigArgs(VALUE_CLASS_PARAM);
if (valueClasses.isEmpty()) {
throw new SolrException(SERVER_ERROR,
"Each '" + TYPE_MAPPING_PARAM + "' <lst/> must contain at least one '" + VALUE_CLASS_PARAM + "' <str>");

View File

@ -176,7 +176,7 @@ public class CloneFieldUpdateProcessorFactory
} else {
// source better be one or more strings
srcInclusions.fieldName = new HashSet<String>
(FieldMutatingUpdateProcessorFactory.oneOrMany(args, "source"));
(args.removeConfigArgs("source"));
}

View File

@ -17,8 +17,8 @@
package org.apache.solr.update.processor;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -27,10 +27,9 @@ import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.solr.core.SolrCore;
import org.apache.solr.common.SolrException;
import static org.apache.solr.common.SolrException.ErrorCode.*;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.util.plugin.SolrCoreAware;
@ -133,18 +132,18 @@ public abstract class FieldMutatingUpdateProcessorFactory
protected final FieldMutatingUpdateProcessor.FieldNameSelector getSelector() {
if (null != selector) return selector;
throw new SolrException(SERVER_ERROR, "selector was never initialized, "+
" inform(SolrCore) never called???");
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"selector was never initialized, inform(SolrCore) never called???");
}
public static SelectorParams parseSelectorParams(NamedList args) {
SelectorParams params = new SelectorParams();
params.fieldName = new HashSet<String>(oneOrMany(args, "fieldName"));
params.typeName = new HashSet<String>(oneOrMany(args, "typeName"));
params.fieldName = new HashSet<String>(args.removeConfigArgs("fieldName"));
params.typeName = new HashSet<String>(args.removeConfigArgs("typeName"));
// we can compile the patterns now
Collection<String> patterns = oneOrMany(args, "fieldRegex");
Collection<String> patterns = args.removeConfigArgs("fieldRegex");
if (! patterns.isEmpty()) {
params.fieldRegex = new ArrayList<Pattern>(patterns.size());
for (String s : patterns) {
@ -152,13 +151,14 @@ public abstract class FieldMutatingUpdateProcessorFactory
params.fieldRegex.add(Pattern.compile(s));
} catch (PatternSyntaxException e) {
throw new SolrException
(SERVER_ERROR, "Invalid 'fieldRegex' pattern: " + s, e);
(SolrException.ErrorCode.SERVER_ERROR,
"Invalid 'fieldRegex' pattern: " + s, e);
}
}
}
// resolve this into actual Class objects later
params.typeClass = oneOrMany(args, "typeClass");
params.typeClass = args.removeConfigArgs("typeClass");
// getBooleanArg() returns null if the arg is not specified
params.fieldNameMatchesSchemaField = getBooleanArg(args, "fieldNameMatchesSchemaField");
@ -171,17 +171,17 @@ public abstract class FieldMutatingUpdateProcessorFactory
List<Object> excList = args.getAll("exclude");
for (Object excObj : excList) {
if (null == excObj) {
throw new SolrException
(SERVER_ERROR, "'exclude' init param can not be null");
throw new SolrException (SolrException.ErrorCode.SERVER_ERROR,
"'exclude' init param can not be null");
}
if (! (excObj instanceof NamedList) ) {
throw new SolrException
(SERVER_ERROR, "'exclude' init param must be <lst/>");
throw new SolrException (SolrException.ErrorCode.SERVER_ERROR,
"'exclude' init param must be <lst/>");
}
NamedList exc = (NamedList) excObj;
exclusions.add(parseSelectorParams(exc));
if (0 < exc.size()) {
throw new SolrException(SERVER_ERROR,
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Unexpected 'exclude' init sub-param(s): '" +
args.getName(0) + "'");
}
@ -207,9 +207,8 @@ public abstract class FieldMutatingUpdateProcessorFactory
exclusions = parseSelectorExclusionParams(args);
if (0 < args.size()) {
throw new SolrException(SERVER_ERROR,
"Unexpected init param(s): '" +
args.getName(0) + "'");
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Unexpected init param(s): '" + args.getName(0) + "'");
}
}
@ -249,7 +248,10 @@ public abstract class FieldMutatingUpdateProcessorFactory
* Strings that key referred to. Throws an error if the key didn't refer
* to one or more strings (or arrays of strings)
* @exception SolrException invalid arr/str structure.
* @deprecated Replaced by {@link NamedList#removeConfigArgs(String)}. Will be
* removed in version 5.0.
*/
@Deprecated
public static Collection<String> oneOrMany(final NamedList args, final String key) {
List<String> result = new ArrayList<String>(args.size() / 2);
final String err = "init arg '" + key + "' must be a string "
@ -268,7 +270,7 @@ public abstract class FieldMutatingUpdateProcessorFactory
if (o instanceof Collection) {
for (Object item : (Collection)o) {
if (! (item instanceof String)) {
throw new SolrException(SERVER_ERROR, err + item.getClass());
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + item.getClass());
}
result.add((String)item);
}
@ -276,7 +278,7 @@ public abstract class FieldMutatingUpdateProcessorFactory
}
// who knows what the hell we have
throw new SolrException(SERVER_ERROR, err + o.getClass());
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + o.getClass());
}
return result;
@ -294,7 +296,8 @@ public abstract class FieldMutatingUpdateProcessorFactory
return null;
}
if (values.size() > 1) {
throw new SolrException(SERVER_ERROR, "Only one '" + key + "' is allowed");
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Only one '" + key + "' is allowed");
}
Object o = args.remove(key);
if (o instanceof Boolean) {
@ -302,7 +305,8 @@ public abstract class FieldMutatingUpdateProcessorFactory
} else if (o instanceof CharSequence) {
bool = Boolean.parseBoolean(o.toString());
} else {
throw new SolrException(SERVER_ERROR, "'" + key + "' must have type 'bool' or 'str'; found " + o.getClass());
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"'" + key + "' must have type 'bool' or 'str'; found " + o.getClass());
}
return bool;
}

View File

@ -112,7 +112,7 @@ public class ParseBooleanFieldUpdateProcessorFactory extends FieldMutatingUpdate
}
}
Collection<String> trueValuesParam = oneOrMany(args, TRUE_VALUES_PARAM);
Collection<String> trueValuesParam = args.removeConfigArgs(TRUE_VALUES_PARAM);
if ( ! trueValuesParam.isEmpty()) {
trueValues.clear();
for (String trueVal : trueValuesParam) {
@ -120,7 +120,7 @@ public class ParseBooleanFieldUpdateProcessorFactory extends FieldMutatingUpdate
}
}
Collection<String> falseValuesParam = oneOrMany(args, FALSE_VALUES_PARAM);
Collection<String> falseValuesParam = args.removeConfigArgs(FALSE_VALUES_PARAM);
if ( ! falseValuesParam.isEmpty()) {
falseValues.clear();
for (String val : falseValuesParam) {

View File

@ -150,7 +150,7 @@ public class ParseDateFieldUpdateProcessorFactory extends FieldMutatingUpdatePro
defaultTimeZone = DateTimeZone.forID(defaultTimeZoneParam.toString());
}
Collection<String> formatsParam = oneOrMany(args, FORMATS_PARAM);
Collection<String> formatsParam = args.removeConfigArgs(FORMATS_PARAM);
if (null != formatsParam) {
for (String value : formatsParam) {
formats.put(value, DateTimeFormat.forPattern(value).withZone(defaultTimeZone).withLocale(locale));

View File

@ -173,7 +173,7 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
@Override
public void init(NamedList args) {
Collection<String> scripts =
FieldMutatingUpdateProcessorFactory.oneOrMany(args, SCRIPT_ARG);
args.removeConfigArgs(SCRIPT_ARG);
if (scripts.isEmpty()) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"StatelessScriptUpdateProcessorFactory must be " +

View File

@ -19,10 +19,14 @@ package org.apache.solr.common.util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.solr.common.SolrException;
/**
* A simple container class for modeling an ordered list of name/value pairs.
*
@ -257,7 +261,23 @@ public class NamedList<T> implements Cloneable, Serializable, Iterable<Map.Entry
}
return result;
}
/**
* Removes all values matching the specified name
*
* @param name Name
*/
private void killAll(String name) {
int sz = size();
// Go through the list backwards, removing matches as found.
for (int i = sz - 1; i >= 0; i--) {
String n = getName(i);
if (name==n || (name!=null && name.equals(n))) {
remove(i);
}
}
}
/**
* Recursively parses the NamedList structure to arrive at a specific element.
* As you descend the NamedList tree, the last element can be any type,
@ -470,6 +490,83 @@ public class NamedList<T> implements Cloneable, Serializable, Iterable<Map.Entry
return null;
}
/**
* Removes and returns all values for the specified name. Returns null if
* no matches found. This method will return all matching objects,
* regardless of data type. If you are parsing Solr config options, the
* {@link #removeConfigArgs(String)} method will probably work better.
*
* @param name Name
* @return List of values
*/
public List<T> removeAll(String name) {
List<T> result = new ArrayList<T>();
result = getAll(name);
if (result.size() > 0 ) {
killAll(name);
return result;
}
return null;
}
/**
* Used for getting one or many arguments from NamedList objects that hold
* configuration parameters. Finds all entries in the NamedList that match
* the given name. If they are all strings or arrays of strings, remove them
* from the NamedList and return the individual elements as a {@link Collection}.
* Parameter order will be preserved if the returned collection is handled as
* an {@link ArrayList}. Throws SolrException if any of the values associated
* with the name are not strings or arrays of strings. If exception is
* thrown, the NamedList is not modified. Returns an empty collection if no
* matches found. If you need to remove and retrieve all matching items from
* the NamedList regardless of data type, use {@link #removeAll(String)} instead.
*
* @param name
* The key to look up in the NamedList.
* @return A collection of the values found.
* @throws SolrException
* If values are found for the input key that are not strings or
* arrays of strings.
*/
@SuppressWarnings("rawtypes")
public Collection<String> removeConfigArgs(final String name)
throws SolrException {
List<T> objects = getAll(name);
List<String> collection = new ArrayList<String>(size() / 2);
final String err = "init arg '" + name + "' must be a string "
+ "(ie: 'str'), or an array (ie: 'arr') containing strings; found: ";
for (Object o : objects) {
if (o instanceof String) {
collection.add((String) o);
continue;
}
// If it's an array, convert to List (which is a Collection).
if (o instanceof Object[]) {
o = Arrays.asList((Object[]) o);
}
// If it's a Collection, collect each value.
if (o instanceof Collection) {
for (Object item : (Collection) o) {
if (!(item instanceof String)) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + item.getClass());
}
collection.add((String) item);
}
continue;
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + o.getClass());
}
if (collection.size() > 0) {
killAll(name);
}
return collection;
}
public void clear() {
nvPairs.clear();
}

View File

@ -17,7 +17,11 @@
package org.apache.solr.common.util;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.common.SolrException;
public class NamedListTest extends LuceneTestCase {
public void testRemove() {
@ -25,9 +29,71 @@ public class NamedListTest extends LuceneTestCase {
nl.add("key1", "value1");
nl.add("key2", "value2");
assertEquals(2, nl.size());
String value = nl.remove(0);
String value = null;
value = nl.remove(0);
assertEquals("value1", value);
assertEquals(1, nl.size());
value = nl.remove("key2");
assertEquals("value2", value);
assertEquals(0, nl.size());
}
public void testRemoveAll() {
NamedList<String> nl = new NamedList<String>();
nl.add("key1", "value1-1");
nl.add("key2", "value2-1");
nl.add("key1", "value1-2");
nl.add("key2", "value2-2");
nl.add("key1", "value1-3");
nl.add("key2", "value2-3");
nl.add("key1", "value1-4");
nl.add("key2", "value2-4");
nl.add("key1", "value1-5");
nl.add("key2", "value2-5");
nl.add("key1", "value1-6");
assertEquals(11, nl.size());
List<String> values = null;
values = nl.removeAll("key1");
assertEquals("value1-1", values.get(0));
assertEquals("value1-3", values.get(2));
assertEquals(6, values.size());
assertEquals(5, nl.size());
values = nl.removeAll("key2");
assertEquals(5, values.size());
assertEquals(0, nl.size());
}
public void testRemoveArgs() {
NamedList<Object> nl = new NamedList<Object>();
nl.add("key1", "value1-1");
nl.add("key2", "value2-1");
nl.add("key1", "value1-2");
nl.add("key2", "value2-2");
nl.add("key1", "value1-3");
nl.add("key2", "value2-3");
nl.add("key1", "value1-4");
nl.add("key2", "value2-4");
nl.add("key1", "value1-5");
nl.add("key2", "value2-5");
nl.add("key1", "value1-6");
nl.add("key2", 0);
nl.add("key2", "value2-7");
assertEquals(13, nl.size());
List<String> values = (ArrayList<String>) nl.removeConfigArgs("key1");
assertEquals("value1-1", values.get(0));
assertEquals("value1-3", values.get(2));
assertEquals(6, values.size());
assertEquals(7, nl.size());
try {
values = (ArrayList<String>) nl.removeConfigArgs("key2");
fail();
}
catch(SolrException e) {
// Expected exception.
assertTrue(true);
}
// nl should be unmodified when removeArgs throws an exception.
assertEquals(7, nl.size());
}
public void testRecursive() {