mirror of https://github.com/apache/lucene.git
SOLR-7226: Make /query/* jmx/* , requestDispatcher/*, <listener> <initParams> properties in solrconfig.xml editable
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1669368 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f2874dd9d3
commit
ad913e4013
|
@ -221,6 +221,11 @@ New Features
|
|||
Example: q=price:[ ${low:0} TO ${high} ]&low=100&high=200
|
||||
(yonik)
|
||||
|
||||
* SOLR-7226: Make /query/* jmx/* , requestDispatcher/*, <listener> <initParams>
|
||||
properties in solrconfig.xml editable (Noble Paul)
|
||||
|
||||
|
||||
|
||||
|
||||
Bug Fixes
|
||||
----------------------
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.apache.solr.core;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
|
@ -30,16 +29,15 @@ import org.apache.solr.common.SolrException;
|
|||
import org.apache.solr.common.cloud.ZkStateReader;
|
||||
import org.apache.solr.common.params.CoreAdminParams;
|
||||
import org.apache.solr.common.util.StrUtils;
|
||||
import org.apache.solr.request.SolrRequestHandler;
|
||||
import org.noggit.CharArr;
|
||||
import org.noggit.JSONParser;
|
||||
import org.noggit.JSONWriter;
|
||||
import org.noggit.ObjectBuilder;
|
||||
|
||||
/**This class encapsulates the config overlay json file. It is immutable
|
||||
/**
|
||||
* This class encapsulates the config overlay json file. It is immutable
|
||||
* and any edit operations performed on tbhis gives a new copy of the object
|
||||
* with the changed value
|
||||
*
|
||||
*/
|
||||
public class ConfigOverlay implements MapSerializable {
|
||||
private final int znodeVersion;
|
||||
|
@ -56,6 +54,7 @@ public class ConfigOverlay implements MapSerializable{
|
|||
userProps = (Map<String, Object>) data.get("userProps");
|
||||
if (userProps == null) userProps = Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
public Object getXPathProperty(String xpath) {
|
||||
return getXPathProperty(xpath, true);
|
||||
}
|
||||
|
@ -93,6 +92,7 @@ public class ConfigOverlay implements MapSerializable{
|
|||
jsonObj.put("userProps", copy);
|
||||
return new ConfigOverlay(jsonObj, znodeVersion);
|
||||
}
|
||||
|
||||
public ConfigOverlay unsetUserProperty(String key) {
|
||||
if (!userProps.containsKey(key)) return this;
|
||||
Map copy = new LinkedHashMap(userProps);
|
||||
|
@ -125,7 +125,6 @@ public class ConfigOverlay implements MapSerializable{
|
|||
}
|
||||
|
||||
|
||||
|
||||
private Map getDeepCopy(Map map) {
|
||||
return (Map) ZkStateReader.fromJSON(ZkStateReader.toJSON(map));
|
||||
}
|
||||
|
@ -135,7 +134,8 @@ public class ConfigOverlay implements MapSerializable{
|
|||
private List<String> checkEditable(String propName, boolean isXPath, boolean failOnError) {
|
||||
LinkedList<String> hierarchy = new LinkedList<>();
|
||||
if (!isEditableProp(propName, isXPath, hierarchy)) {
|
||||
if(failOnError) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, StrUtils.formatString( NOT_EDITABLE,propName));
|
||||
if (failOnError)
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, StrUtils.formatString(NOT_EDITABLE, propName));
|
||||
else return null;
|
||||
}
|
||||
return hierarchy;
|
||||
|
@ -187,23 +187,73 @@ public class ConfigOverlay implements MapSerializable{
|
|||
|
||||
public static final String RESOURCE_NAME = "configoverlay.json";
|
||||
|
||||
private static final Long XML_ATTR = 0L;
|
||||
private static final Long XML_NODE = 1L;
|
||||
private static final Long STR_ATTR = 0L;
|
||||
private static final Long STR_NODE = 1L;
|
||||
private static final Long BOOL_ATTR = 10L;
|
||||
private static final Long BOOL_NODE = 11L;
|
||||
private static final Long INT_ATTR = 20L;
|
||||
private static final Long INT_NODE = 21L;
|
||||
private static final Long FLOAT_ATTR = 30L;
|
||||
private static final Long FLOAT_NODE = 31L;
|
||||
|
||||
private static Map editable_prop_map;
|
||||
public static final String MAPPING = "{ updateHandler : {" +
|
||||
" autoCommit : { maxDocs:1, maxTime:1, openSearcher:1 }," +
|
||||
" autoSoftCommit : { maxDocs:1, maxTime :1}," +
|
||||
" commitWithin : {softCommit:1}," +
|
||||
" commitIntervalLowerBound:1," +
|
||||
" indexWriter : {closeWaitsForMerges:1}" +
|
||||
" }," +
|
||||
//The path maps to the xml xpath and value of 1 means it is a tag with a string value and value
|
||||
// of 0 means it is an attribute with string value
|
||||
public static final String MAPPING = "{" +
|
||||
" updateHandler:{" +
|
||||
" autoCommit:{" +
|
||||
" maxDocs:20," +
|
||||
" maxTime:20," +
|
||||
" openSearcher:11}," +
|
||||
" autoSoftCommit:{" +
|
||||
" maxDocs:20," +
|
||||
" maxTime:20}," +
|
||||
" commitWithin:{softCommit:11}," +
|
||||
" commitIntervalLowerBound:21," +
|
||||
" indexWriter:{closeWaitsForMerges:11}}," +
|
||||
" query:{" +
|
||||
" filterCache : {class:0, size:0, initialSize:0 , autowarmCount:0 , regenerator:0}," +
|
||||
" queryResultCache :{class:0, size:0, initialSize:0,autowarmCount:0,regenerator:0}," +
|
||||
" documentCache :{class:0, size:0, initialSize:0 ,autowarmCount:0,regenerator:0}," +
|
||||
" fieldValueCache :{class:0, size:0, initialSize:0 ,autowarmCount:0,regenerator:0}" +
|
||||
"}}";
|
||||
" filterCache:{" +
|
||||
" class:0," +
|
||||
" size:0," +
|
||||
" initialSize:20," +
|
||||
" autowarmCount:20," +
|
||||
" regenerator:0}," +
|
||||
" queryResultCache:{" +
|
||||
" class:0," +
|
||||
" size:20," +
|
||||
" initialSize:20," +
|
||||
" autowarmCount:20," +
|
||||
" regenerator:0}," +
|
||||
" documentCache:{" +
|
||||
" class:0," +
|
||||
" size:20," +
|
||||
" initialSize:20," +
|
||||
" autowarmCount:20," +
|
||||
" regenerator:0}," +
|
||||
" fieldValueCache:{" +
|
||||
" class:0," +
|
||||
" size:20," +
|
||||
" initialSize:20," +
|
||||
" autowarmCount:20," +
|
||||
" regenerator:0}," +
|
||||
" useFilterForSortedQuery:1," +
|
||||
" queryResultWindowSize:1," +
|
||||
" queryResultMaxDocsCached:1," +
|
||||
" enableLazyFieldLoading:1," +
|
||||
" boolTofilterOptimizer:1," +
|
||||
" maxBooleanClauses:1}," +
|
||||
" jmx:{" +
|
||||
" agentId:0," +
|
||||
" serviceUrl:0," +
|
||||
" rootName:0}," +
|
||||
" requestDispatcher:{" +
|
||||
" handleSelect:0," +
|
||||
" requestParsers:{" +
|
||||
" multipartUploadLimitInKB:0," +
|
||||
" formdataUploadLimitInKB:0," +
|
||||
" enableRemoteStreaming:0," +
|
||||
" addHttpRequestToContext:0}}}";
|
||||
|
||||
static {
|
||||
try {
|
||||
editable_prop_map = (Map) new ObjectBuilder(new JSONParser(new StringReader(
|
||||
|
@ -213,8 +263,12 @@ public class ConfigOverlay implements MapSerializable{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isEditableProp(String path, boolean isXpath, List<String> hierarchy) {
|
||||
return !(checkEditable(path, isXpath, hierarchy) == null);
|
||||
}
|
||||
|
||||
|
||||
public static Class checkEditable(String path, boolean isXpath, List<String> hierarchy) {
|
||||
List<String> parts = StrUtils.splitSmart(path, isXpath ? '/' : '.');
|
||||
Object obj = editable_prop_map;
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
|
@ -224,23 +278,33 @@ public class ConfigOverlay implements MapSerializable{
|
|||
part = part.substring(1);
|
||||
}
|
||||
if (hierarchy != null) hierarchy.add(part);
|
||||
if(obj ==null) return false;
|
||||
if (obj == null) return null;
|
||||
if (i == parts.size() - 1) {
|
||||
if (obj instanceof Map) {
|
||||
Map map = (Map) obj;
|
||||
if(isXpath && isAttr){
|
||||
return XML_ATTR.equals(map.get(part));
|
||||
} else {
|
||||
return XML_ATTR.equals( map.get(part)) || XML_NODE.equals(map.get(part));
|
||||
Object o = map.get(part);
|
||||
return checkType(o, isXpath, isAttr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
obj = ((Map) obj).get(part);
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
static Class[] types = new Class[]{String.class, Boolean.class, Integer.class, Float.class};
|
||||
|
||||
private static Class checkType(Object o, boolean isXpath, boolean isAttr) {
|
||||
if (o instanceof Long) {
|
||||
Long aLong = (Long) o;
|
||||
int ten = aLong.intValue() / 10;
|
||||
int one = aLong.intValue() % 10;
|
||||
if (isXpath && isAttr && one != 0) return null;
|
||||
return types[ten];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getEditableSubProperties(String xpath) {
|
||||
Object o = getObjectByPath(props, false, StrUtils.splitSmart(xpath, '/'));
|
||||
|
@ -262,6 +326,7 @@ public class ConfigOverlay implements MapSerializable{
|
|||
result.putAll(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Map> getNamedPlugins(String typ) {
|
||||
Map<String, Map> reqHandlers = (Map<String, Map>) data.get(typ);
|
||||
if (reqHandlers == null) return Collections.EMPTY_MAP;
|
||||
|
@ -285,7 +350,11 @@ public class ConfigOverlay implements MapSerializable{
|
|||
return new ConfigOverlay(dataCopy, this.znodeVersion);
|
||||
|
||||
}
|
||||
|
||||
public static final String ZNODEVER = "znodeVersion";
|
||||
public static final String NAME = "overlay";
|
||||
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.apache.solr.core;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -57,7 +56,9 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
private SolrCore core;
|
||||
private final SolrConfig.SolrPluginInfo meta;
|
||||
|
||||
/** Pass needThreadSafety=true if plugins can be added and removed concurrently with lookups. */
|
||||
/**
|
||||
* Pass needThreadSafety=true if plugins can be added and removed concurrently with lookups.
|
||||
*/
|
||||
public PluginBag(Class<T> klass, SolrCore core, boolean needThreadSafety) {
|
||||
this.core = core;
|
||||
this.klass = klass;
|
||||
|
@ -72,12 +73,14 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
/** Constructs a non-threadsafe plugin registry */
|
||||
/**
|
||||
* Constructs a non-threadsafe plugin registry
|
||||
*/
|
||||
public PluginBag(Class<T> klass, SolrCore core) {
|
||||
this(klass, core, false);
|
||||
}
|
||||
|
||||
static void initInstance(Object inst, PluginInfo info, SolrCore core) {
|
||||
static void initInstance(Object inst, PluginInfo info) {
|
||||
if (inst instanceof PluginInfoInitialized) {
|
||||
((PluginInfoInitialized) inst).init(info);
|
||||
} else if (inst instanceof NamedListInitializedPlugin) {
|
||||
|
@ -94,16 +97,16 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
|
||||
}
|
||||
|
||||
PluginHolder<T> createPlugin(PluginInfo info, SolrCore core) {
|
||||
PluginHolder<T> createPlugin(PluginInfo info) {
|
||||
if ("true".equals(String.valueOf(info.attributes.get("runtimeLib")))) {
|
||||
log.info(" {} : '{}' created with runtimeLib=true ", meta.tag, info.name);
|
||||
log.info(" {} : '{}' created with runtimeLib=true ", meta.getCleanTag(), info.name);
|
||||
return new LazyPluginHolder<>(meta, info, core, core.getMemClassLoader());
|
||||
} else if ("lazy".equals(info.attributes.get("startup")) && meta.options.contains(SolrConfig.PluginOpts.LAZY)) {
|
||||
log.info("{} : '{}' created with startup=lazy ", meta.tag, info.name);
|
||||
log.info("{} : '{}' created with startup=lazy ", meta.getCleanTag(), info.name);
|
||||
return new LazyPluginHolder<T>(meta, info, core, core.getResourceLoader());
|
||||
} else {
|
||||
T inst = core.createInstance(info.className, (Class<T>) meta.clazz, meta.tag, null, core.getResourceLoader());
|
||||
initInstance(inst, info, core);
|
||||
T inst = core.createInstance(info.className, (Class<T>) meta.clazz, meta.getCleanTag(), null, core.getResourceLoader());
|
||||
initInstance(inst, info);
|
||||
return new PluginHolder<>(info, inst);
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +167,7 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
|
||||
void setDefault(String def) {
|
||||
if (!registry.containsKey(def)) return;
|
||||
if (this.def != null) log.warn("Multiple defaults for : " + meta.tag);
|
||||
if (this.def != null) log.warn("Multiple defaults for : " + meta.getCleanTag());
|
||||
this.def = def;
|
||||
}
|
||||
|
||||
|
@ -197,11 +200,11 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
void init(Map<String, T> defaults, SolrCore solrCore, List<PluginInfo> infos) {
|
||||
core = solrCore;
|
||||
for (PluginInfo info : infos) {
|
||||
PluginHolder<T> o = createPlugin(info, solrCore);
|
||||
PluginHolder<T> o = createPlugin(info);
|
||||
String name = info.name;
|
||||
if (meta.clazz.equals(SolrRequestHandler.class)) name = RequestHandlers.normalize(info.name);
|
||||
PluginHolder<T> old = put(name, o);
|
||||
if (old != null) log.warn("Multiple entries of {} with name {}", meta.tag, name);
|
||||
if (old != null) log.warn("Multiple entries of {} with name {}", meta.getCleanTag(), name);
|
||||
}
|
||||
for (Map.Entry<String, T> e : defaults.entrySet()) {
|
||||
if (!contains(e.getKey())) {
|
||||
|
@ -238,7 +241,7 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
try {
|
||||
e.getValue().close();
|
||||
} catch (Exception exp) {
|
||||
log.error("Error closing plugin " + e.getKey() + " of type : " + meta.tag, exp);
|
||||
log.error("Error closing plugin " + e.getKey() + " of type : " + meta.getCleanTag(), exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,14 +334,14 @@ public class PluginBag<T> implements AutoCloseable {
|
|||
|
||||
private synchronized boolean createInst() {
|
||||
if (lazyInst != null) return false;
|
||||
log.info("Going to create a new {} with {} ", pluginMeta.tag, pluginInfo.toString());
|
||||
log.info("Going to create a new {} with {} ", pluginMeta.getCleanTag(), pluginInfo.toString());
|
||||
if (resourceLoader instanceof MemClassLoader) {
|
||||
MemClassLoader loader = (MemClassLoader) resourceLoader;
|
||||
loader.loadJars();
|
||||
}
|
||||
Class<T> clazz = (Class<T>) pluginMeta.clazz;
|
||||
T localInst = core.createInstance(pluginInfo.className, clazz, pluginMeta.tag, null, resourceLoader);
|
||||
initInstance(localInst, pluginInfo, core);
|
||||
T localInst = core.createInstance(pluginInfo.className, clazz, pluginMeta.getCleanTag(), null, resourceLoader);
|
||||
initInstance(localInst, pluginInfo);
|
||||
if (localInst instanceof SolrCoreAware) {
|
||||
SolrResourceLoader.assertAwareCompatibility(SolrCoreAware.class, localInst);
|
||||
((SolrCoreAware) localInst).inform(core);
|
||||
|
|
|
@ -73,6 +73,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -81,6 +82,7 @@ import static org.apache.solr.core.SolrConfig.PluginOpts.MULTI_OK;
|
|||
import static org.apache.solr.core.SolrConfig.PluginOpts.NOOP;
|
||||
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_CLASS;
|
||||
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME;
|
||||
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME_IN_OVERLAY;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -98,6 +100,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
public static enum PluginOpts {
|
||||
MULTI_OK,
|
||||
REQUIRE_NAME,
|
||||
REQUIRE_NAME_IN_OVERLAY,
|
||||
REQUIRE_CLASS,
|
||||
LAZY,
|
||||
// EnumSet.of and/or EnumSet.copyOf(Collection) are anoying
|
||||
|
@ -117,14 +120,18 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
private final SolrRequestParsers solrRequestParsers;
|
||||
|
||||
/** Creates a default instance from the solrconfig.xml. */
|
||||
/**
|
||||
* Creates a default instance from the solrconfig.xml.
|
||||
*/
|
||||
public SolrConfig()
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this((SolrResourceLoader) null, DEFAULT_CONF_FILE, null);
|
||||
}
|
||||
|
||||
/** Creates a configuration instance from a configuration name.
|
||||
/**
|
||||
* Creates a configuration instance from a configuration name.
|
||||
* A default resource loader will be created (@see SolrResourceLoader)
|
||||
*
|
||||
* @param name the configuration name used by the loader
|
||||
*/
|
||||
public SolrConfig(String name)
|
||||
|
@ -132,10 +139,12 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
this((SolrResourceLoader) null, name, null);
|
||||
}
|
||||
|
||||
/** Creates a configuration instance from a configuration name and stream.
|
||||
/**
|
||||
* Creates a configuration instance from a configuration name and stream.
|
||||
* A default resource loader will be created (@see SolrResourceLoader).
|
||||
* If the stream is null, the resource loader will open the configuration stream.
|
||||
* If the stream is not null, no attempt to load the resource will occur (the name is not used).
|
||||
*
|
||||
* @param name the configuration name
|
||||
* @param is the configuration stream
|
||||
*/
|
||||
|
@ -144,7 +153,9 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
this((SolrResourceLoader) null, name, is);
|
||||
}
|
||||
|
||||
/** Creates a configuration instance from an instance directory, configuration name and stream.
|
||||
/**
|
||||
* Creates a configuration instance from an instance directory, configuration name and stream.
|
||||
*
|
||||
* @param instanceDir the directory used to create the resource loader
|
||||
* @param name the configuration name used by the loader if the stream is null
|
||||
* @param is the configuration stream
|
||||
|
@ -157,8 +168,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
public static SolrConfig readFromResourceLoader(SolrResourceLoader loader, String name) {
|
||||
try {
|
||||
return new SolrConfig(loader, name, null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
String resource;
|
||||
if (loader instanceof ZkSolrResourceLoader) {
|
||||
resource = name;
|
||||
|
@ -169,9 +179,11 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
}
|
||||
}
|
||||
|
||||
/** Creates a configuration instance from a resource loader, a configuration name and a stream.
|
||||
/**
|
||||
* Creates a configuration instance from a resource loader, a configuration name and a stream.
|
||||
* If the stream is null, the resource loader will open the configuration stream.
|
||||
* If the stream is not null, no attempt to load the resource will occur (the name is not used).
|
||||
*
|
||||
* @param loader the resource loader
|
||||
* @param name the configuration name
|
||||
* @param is the configuration stream
|
||||
|
@ -281,7 +293,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
addHttpRequestToContext = getBool(
|
||||
"requestDispatcher/requestParsers/@addHttpRequestToContext", false);
|
||||
|
||||
List<PluginInfo> argsInfos = pluginStore.get(InitParams.class.getName()) ;
|
||||
List<PluginInfo> argsInfos = getPluginInfos(InitParams.class.getName());
|
||||
if (argsInfos != null) {
|
||||
Map<String, InitParams> argsMap = new HashMap<>();
|
||||
for (PluginInfo p : argsInfos) {
|
||||
|
@ -314,7 +326,9 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
// regardless of when/how/why they are used (or even if they are
|
||||
// declared outside of the appropriate context) but there's no nice
|
||||
// way around that in the PluginInfo framework
|
||||
.add(new SolrPluginInfo(SolrEventListener.class, "//listener", REQUIRE_CLASS, MULTI_OK))
|
||||
.add(new SolrPluginInfo(InitParams.class, InitParams.TYPE, MULTI_OK, REQUIRE_NAME_IN_OVERLAY))
|
||||
.add(new SolrPluginInfo(SolrEventListener.class, "//listener", REQUIRE_CLASS, MULTI_OK, REQUIRE_NAME_IN_OVERLAY))
|
||||
|
||||
.add(new SolrPluginInfo(DirectoryFactory.class, "directoryFactory", REQUIRE_CLASS))
|
||||
.add(new SolrPluginInfo(IndexDeletionPolicy.class, "indexConfig/deletionPolicy", REQUIRE_CLASS))
|
||||
.add(new SolrPluginInfo(CodecFactory.class, "codecFactory", REQUIRE_CLASS))
|
||||
|
@ -323,10 +337,10 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
.add(new SolrPluginInfo(UpdateLog.class, "updateHandler/updateLog"))
|
||||
.add(new SolrPluginInfo(IndexSchemaFactory.class, "schemaFactory", REQUIRE_CLASS))
|
||||
.add(new SolrPluginInfo(RestManager.class, "restManager"))
|
||||
.add(new SolrPluginInfo(InitParams.class, InitParams.TYPE, MULTI_OK))
|
||||
.add(new SolrPluginInfo(StatsCache.class, "statsCache", REQUIRE_CLASS))
|
||||
.build();
|
||||
public static final Map<String, SolrPluginInfo> classVsSolrPluginInfo;
|
||||
|
||||
static {
|
||||
Map<String, SolrPluginInfo> map = new HashMap<>();
|
||||
for (SolrPluginInfo plugin : plugins) map.put(plugin.clazz.getName(), plugin);
|
||||
|
@ -345,6 +359,15 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
this.tag = tag;
|
||||
this.options = opts == null ? Collections.EMPTY_SET : EnumSet.of(NOOP, opts);
|
||||
}
|
||||
|
||||
public String getCleanTag() {
|
||||
return tag.replaceAll("/", "");
|
||||
}
|
||||
|
||||
public String getTagCleanLower() {
|
||||
return getCleanTag().toLowerCase(Locale.ROOT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static ConfigOverlay getConfigOverlay(SolrResourceLoader loader) {
|
||||
|
@ -371,9 +394,11 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
}
|
||||
|
||||
private Map<String, InitParams> initParams = Collections.emptyMap();
|
||||
|
||||
public Map<String, InitParams> getInitParams() {
|
||||
return initParams;
|
||||
}
|
||||
|
||||
protected UpdateHandlerInfo loadUpdatehandlerInfo() {
|
||||
return new UpdateHandlerInfo(get("updateHandler/@class", null),
|
||||
getInt("updateHandler/autoCommit/maxDocs", -1),
|
||||
|
@ -396,7 +421,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
throw new SolrException
|
||||
(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Found " + result.size() + " configuration sections when at most "
|
||||
+ "1 is allowed matching expression: " + pluginInfo.tag);
|
||||
+ "1 is allowed matching expression: " + pluginInfo.getCleanTag());
|
||||
}
|
||||
if (!result.isEmpty()) pluginStore.put(pluginInfo.clazz.getName(), result);
|
||||
}
|
||||
|
@ -458,6 +483,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
public final JmxConfiguration jmxConfig;
|
||||
|
||||
private final HttpCachingConfig httpCachingConfig;
|
||||
|
||||
public HttpCachingConfig getHttpCachingConfig() {
|
||||
return httpCachingConfig;
|
||||
}
|
||||
|
@ -498,11 +524,15 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
public static class HttpCachingConfig implements MapSerializable {
|
||||
|
||||
/** config xpath prefix for getting HTTP Caching options */
|
||||
/**
|
||||
* config xpath prefix for getting HTTP Caching options
|
||||
*/
|
||||
private final static String CACHE_PRE
|
||||
= "requestDispatcher/httpCaching/";
|
||||
|
||||
/** For extracting Expires "ttl" from <cacheControl> config */
|
||||
/**
|
||||
* For extracting Expires "ttl" from <cacheControl> config
|
||||
*/
|
||||
private final static Pattern MAX_AGE
|
||||
= Pattern.compile("\\bmax-age=(\\d+)");
|
||||
|
||||
|
@ -517,7 +547,9 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
public static enum LastModFrom {
|
||||
OPENTIME, DIRLASTMOD, BOGUS;
|
||||
|
||||
/** Input must not be null */
|
||||
/**
|
||||
* Input must not be null
|
||||
*/
|
||||
public static LastModFrom parse(final String s) {
|
||||
try {
|
||||
return valueOf(s.toUpperCase(Locale.ROOT));
|
||||
|
@ -564,13 +596,31 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
}
|
||||
|
||||
public boolean isNever304() { return never304; }
|
||||
public String getEtagSeed() { return etagSeed; }
|
||||
/** null if no Cache-Control header */
|
||||
public String getCacheControlHeader() { return cacheControlHeader; }
|
||||
/** null if no max age limitation */
|
||||
public Long getMaxAge() { return maxAge; }
|
||||
public LastModFrom getLastModFrom() { return lastModFrom; }
|
||||
public boolean isNever304() {
|
||||
return never304;
|
||||
}
|
||||
|
||||
public String getEtagSeed() {
|
||||
return etagSeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* null if no Cache-Control header
|
||||
*/
|
||||
public String getCacheControlHeader() {
|
||||
return cacheControlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* null if no max age limitation
|
||||
*/
|
||||
public Long getMaxAge() {
|
||||
return maxAge;
|
||||
}
|
||||
|
||||
public LastModFrom getLastModFrom() {
|
||||
return lastModFrom;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateHandlerInfo implements MapSerializable {
|
||||
|
@ -602,7 +652,6 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
LinkedHashMap result = new LinkedHashMap();
|
||||
|
@ -626,11 +675,17 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
// public Map<String, List<PluginInfo>> getUpdateProcessorChainInfo() { return updateProcessorChainInfo; }
|
||||
|
||||
public UpdateHandlerInfo getUpdateHandlerInfo() { return updateHandlerInfo; }
|
||||
public UpdateHandlerInfo getUpdateHandlerInfo() {
|
||||
return updateHandlerInfo;
|
||||
}
|
||||
|
||||
public String getDataDir() { return dataDir; }
|
||||
public String getDataDir() {
|
||||
return dataDir;
|
||||
}
|
||||
|
||||
/**SolrConfig keeps a repository of plugins by the type. The known interfaces are the types.
|
||||
/**
|
||||
* SolrConfig keeps a repository of plugins by the type. The known interfaces are the types.
|
||||
*
|
||||
* @param type The key is FQN of the plugin class there are a few known types : SolrFormatter, SolrFragmenter
|
||||
* SolrRequestHandler,QParserPlugin, QueryResponseWriter,ValueSourceParser,
|
||||
* SearchComponent, QueryConverter, SolrEventListener, DirectoryFactory,
|
||||
|
@ -639,19 +694,27 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
public List<PluginInfo> getPluginInfos(String type) {
|
||||
List<PluginInfo> result = pluginStore.get(type);
|
||||
SolrPluginInfo info = classVsSolrPluginInfo.get(type);
|
||||
if (info != null && info.options.contains(REQUIRE_NAME)) {
|
||||
Map<String, Map> infos = overlay.getNamedPlugins(info.tag);
|
||||
if (info != null &&
|
||||
(info.options.contains(REQUIRE_NAME) || info.options.contains(REQUIRE_NAME_IN_OVERLAY))) {
|
||||
Map<String, Map> infos = overlay.getNamedPlugins(info.getCleanTag());
|
||||
if (!infos.isEmpty()) {
|
||||
LinkedHashMap<String, PluginInfo> map = new LinkedHashMap<>();
|
||||
if (result != null) for (PluginInfo pluginInfo : result) map.put(pluginInfo.name, pluginInfo);
|
||||
if (result != null) for (PluginInfo pluginInfo : result) {
|
||||
//just create a UUID for the time being so that map key is not null
|
||||
String name = pluginInfo.name == null ?
|
||||
UUID.randomUUID().toString().toLowerCase(Locale.ROOT) :
|
||||
pluginInfo.name;
|
||||
map.put(name, pluginInfo);
|
||||
}
|
||||
for (Map.Entry<String, Map> e : infos.entrySet()) {
|
||||
map.put(e.getKey(), new PluginInfo(info.tag, e.getValue()));
|
||||
map.put(e.getKey(), new PluginInfo(info.getCleanTag(), e.getValue()));
|
||||
}
|
||||
result = new ArrayList<>(map.values());
|
||||
}
|
||||
}
|
||||
return result == null ? Collections.<PluginInfo>emptyList() : result;
|
||||
}
|
||||
|
||||
public PluginInfo getPluginInfo(String type) {
|
||||
List<PluginInfo> result = pluginStore.get(type);
|
||||
if (result == null || result.isEmpty()) {
|
||||
|
@ -728,18 +791,31 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
@Override
|
||||
public int getInt(String path, int def) {
|
||||
Object v = overlay.getXPathProperty(path);
|
||||
|
||||
Object val = overlay.getXPathProperty(path);
|
||||
if (val != null) return Integer.parseInt(val.toString());
|
||||
return super.getInt(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBool(String path, boolean def) {
|
||||
Object val = overlay.getXPathProperty(path);
|
||||
if (val != null) return Boolean.parseBoolean(val.toString());
|
||||
return super.getBool(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String path) {
|
||||
Object val = overlay.getXPathProperty(path, true);
|
||||
return val != null ? val.toString() : super.get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String path, String def) {
|
||||
Object val = overlay.getXPathProperty(path, true);
|
||||
return val != null ? val.toString() : super.get(path, def);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
LinkedHashMap result = new LinkedHashMap();
|
||||
|
@ -753,11 +829,11 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
m.put("queryResultMaxDocsCached", queryResultMaxDocsCached);
|
||||
m.put("enableLazyFieldLoading", enableLazyFieldLoading);
|
||||
m.put("maxBooleanClauses", booleanQueryMaxClauseCount);
|
||||
|
||||
if (jmxConfig != null) result.put("jmx", jmxConfig.toMap());
|
||||
for (SolrPluginInfo plugin : plugins) {
|
||||
List<PluginInfo> infos = getPluginInfos(plugin.clazz.getName());
|
||||
if (infos == null || infos.isEmpty()) continue;
|
||||
String tag = plugin.tag;
|
||||
String tag = plugin.getCleanTag();
|
||||
tag = tag.replace("/", "");
|
||||
if (plugin.options.contains(PluginOpts.REQUIRE_NAME)) {
|
||||
LinkedHashMap items = new LinkedHashMap();
|
||||
|
@ -808,6 +884,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
result.putAll(p);
|
||||
return result;
|
||||
}
|
||||
|
||||
private ConfigOverlay overlay;
|
||||
|
||||
public ConfigOverlay getOverlay() {
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.apache.solr.handler;
|
|||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -57,9 +56,11 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.apache.solr.common.params.CoreAdminParams.NAME;
|
||||
import static org.apache.solr.common.util.StrUtils.formatString;
|
||||
import static org.apache.solr.core.ConfigOverlay.NOT_EDITABLE;
|
||||
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_CLASS;
|
||||
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME;
|
||||
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME_IN_OVERLAY;
|
||||
import static org.apache.solr.schema.FieldType.CLASS_NAME;
|
||||
|
||||
public class SolrConfigHandler extends RequestHandlerBase {
|
||||
|
@ -70,9 +71,8 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
static {
|
||||
Map<String, SolrConfig.SolrPluginInfo> map = new HashMap<>();
|
||||
for (SolrConfig.SolrPluginInfo plugin : SolrConfig.plugins) {
|
||||
if (plugin.options.contains(REQUIRE_NAME)) {
|
||||
map.put(plugin.tag.toLowerCase(Locale.ROOT), plugin);
|
||||
|
||||
if (plugin.options.contains(REQUIRE_NAME) || plugin.options.contains(REQUIRE_NAME_IN_OVERLAY)) {
|
||||
map.put(plugin.getCleanTag().toLowerCase(Locale.ROOT), plugin);
|
||||
}
|
||||
}
|
||||
namedPlugins = Collections.unmodifiableMap(map);
|
||||
|
@ -252,7 +252,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
if (op.hasError()) break;
|
||||
for (String s : name) {
|
||||
if (params.getParams(s) == null) {
|
||||
op.addError(StrUtils.formatString("can't delete . No such params ''{0}'' exist", s));
|
||||
op.addError(formatString("can't delete . No such params ''{0}'' exist", s));
|
||||
}
|
||||
params = params.setParams(s, null);
|
||||
}
|
||||
|
@ -302,19 +302,19 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
default: {
|
||||
List<String> pcs = StrUtils.splitSmart(op.name.toLowerCase(Locale.ROOT), '-');
|
||||
if (pcs.size() != 2) {
|
||||
op.addError(StrUtils.formatString("Unknown operation ''{0}'' ", op.name));
|
||||
op.addError(formatString("Unknown operation ''{0}'' ", op.name));
|
||||
} else {
|
||||
String prefix = pcs.get(0);
|
||||
String name = pcs.get(1);
|
||||
if (cmdPrefixes.contains(prefix) && namedPlugins.containsKey(name)) {
|
||||
SolrConfig.SolrPluginInfo info = namedPlugins.get(name);
|
||||
if ("delete".equals(prefix)) {
|
||||
overlay = deleteNamedComponent(op, overlay, info.tag);
|
||||
overlay = deleteNamedComponent(op, overlay, info.getCleanTag());
|
||||
} else {
|
||||
overlay = updateNamedPlugin(info, op, overlay, prefix.equals("create") || prefix.equals("add"));
|
||||
}
|
||||
} else {
|
||||
op.addError(StrUtils.formatString("Unknown operation ''{0}'' ", op.name));
|
||||
op.addError(formatString("Unknown operation ''{0}'' ", op.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
if (overlay.getNamedPlugins(typ).containsKey(name)) {
|
||||
return overlay.deleteNamedPlugin(name, typ);
|
||||
} else {
|
||||
op.addError(StrUtils.formatString("NO such {0} ''{1}'' ", typ, name));
|
||||
op.addError(formatString("NO such {0} ''{1}'' ", typ, name));
|
||||
return overlay;
|
||||
}
|
||||
}
|
||||
|
@ -360,18 +360,18 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
op.getMap(PluginInfo.APPENDS, null);
|
||||
if (op.hasError()) return overlay;
|
||||
if (!verifyClass(op, clz, info.clazz)) return overlay;
|
||||
if (overlay.getNamedPlugins(info.tag).containsKey(name)) {
|
||||
if (overlay.getNamedPlugins(info.getCleanTag()).containsKey(name)) {
|
||||
if (isCeate) {
|
||||
op.addError(StrUtils.formatString(" ''{0}'' already exists . Do an ''{1}'' , if you want to change it ", name, "update-" + info.tag.toLowerCase(Locale.ROOT)));
|
||||
op.addError(formatString(" ''{0}'' already exists . Do an ''{1}'' , if you want to change it ", name, "update-" + info.getTagCleanLower()));
|
||||
return overlay;
|
||||
} else {
|
||||
return overlay.addNamedPlugin(op.getDataMap(), info.tag);
|
||||
return overlay.addNamedPlugin(op.getDataMap(), info.getCleanTag());
|
||||
}
|
||||
} else {
|
||||
if (isCeate) {
|
||||
return overlay.addNamedPlugin(op.getDataMap(), info.tag);
|
||||
return overlay.addNamedPlugin(op.getDataMap(), info.getCleanTag());
|
||||
} else {
|
||||
op.addError(StrUtils.formatString(" ''{0}'' does not exist . Do an ''{1}'' , if you want to create it ", name, "create-" + info.tag.toLowerCase(Locale.ROOT)));
|
||||
op.addError(formatString(" ''{0}'' does not exist . Do an ''{1}'' , if you want to create it ", name, "create-" + info.getTagCleanLower()));
|
||||
return overlay;
|
||||
}
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
if (op.hasError()) return overlay;
|
||||
for (String o : name) {
|
||||
if (!overlay.getUserProps().containsKey(o)) {
|
||||
op.addError(StrUtils.formatString("No such property ''{0}''", name));
|
||||
op.addError(formatString("No such property ''{0}''", name));
|
||||
} else {
|
||||
overlay = overlay.unsetUserProperty(o);
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
|
||||
for (String o : name) {
|
||||
if (!ConfigOverlay.isEditableProp(o, false, null)) {
|
||||
op.addError(StrUtils.formatString(NOT_EDITABLE, name));
|
||||
op.addError(formatString(NOT_EDITABLE, name));
|
||||
} else {
|
||||
overlay = overlay.unsetProperty(o);
|
||||
}
|
||||
|
@ -437,10 +437,42 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
for (Map.Entry<String, Object> e : m.entrySet()) {
|
||||
String name = e.getKey();
|
||||
Object val = e.getValue();
|
||||
if (!ConfigOverlay.isEditableProp(name, false, null)) {
|
||||
op.addError(StrUtils.formatString(NOT_EDITABLE, name));
|
||||
Class typ = ConfigOverlay.checkEditable(name, false, null);
|
||||
if (typ == null) {
|
||||
op.addError(formatString(NOT_EDITABLE, name));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val != null) {
|
||||
if (typ == String.class) val = val.toString();
|
||||
String typeErr = "Property {0} must be of {1} type ";
|
||||
if (typ == Boolean.class) {
|
||||
try {
|
||||
val = Boolean.parseBoolean(val.toString());
|
||||
} catch (Exception exp) {
|
||||
op.addError(formatString(typeErr, name, typ.getSimpleName()));
|
||||
continue;
|
||||
}
|
||||
} else if (typ == Integer.class) {
|
||||
try {
|
||||
val = Integer.parseInt(val.toString());
|
||||
} catch (Exception exp) {
|
||||
op.addError(formatString(typeErr, typ.getSimpleName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (typ == Float.class) {
|
||||
try {
|
||||
val = Float.parseFloat(val.toString());
|
||||
} catch (Exception exp) {
|
||||
op.addError(formatString(typeErr, typ.getSimpleName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
overlay = overlay.setProperty(name, val);
|
||||
}
|
||||
return overlay;
|
||||
|
@ -459,7 +491,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
c == '.'
|
||||
) continue;
|
||||
else {
|
||||
return StrUtils.formatString("''{0}'' name should only have chars [a-zA-Z_-.0-9] ", s);
|
||||
return formatString("''{0}'' name should only have chars [a-zA-Z_-.0-9] ", s);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -487,7 +519,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
|
||||
static {
|
||||
for (SolrConfig.SolrPluginInfo solrPluginInfo : SolrConfig.plugins)
|
||||
subPaths.add("/" + solrPluginInfo.tag.replaceAll("/", ""));
|
||||
subPaths.add("/" + solrPluginInfo.getCleanTag());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,21 @@ public class TestConfigOverlay extends LuceneTestCase {
|
|||
assertTrue(isEditableProp("updateHandler.autoCommit.maxTime", false, null));
|
||||
assertTrue(isEditableProp("updateHandler.commitWithin.softCommit", false, null));
|
||||
assertTrue(isEditableProp("updateHandler.indexWriter.closeWaitsForMerges", false, null));
|
||||
assertTrue(isEditableProp("query.useFilterForSortedQuery", false, null));
|
||||
assertTrue(isEditableProp("query.queryResultWindowSize", false, null));
|
||||
assertTrue(isEditableProp("query.queryResultMaxDocsCached", false, null));
|
||||
assertTrue(isEditableProp("query.enableLazyFieldLoading", false, null));
|
||||
assertTrue(isEditableProp("query.boolTofilterOptimizer", false, null));
|
||||
assertTrue(isEditableProp("jmx.agentId", false, null));
|
||||
assertTrue(isEditableProp("jmx.serviceUrl", false, null));
|
||||
assertTrue(isEditableProp("jmx.rootName", false, null));
|
||||
|
||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.multipartUploadLimitInKB", false, null));
|
||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.formdataUploadLimitInKB", false, null));
|
||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.enableRemoteStreaming", false, null));
|
||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.addHttpRequestToContext", false, null));
|
||||
|
||||
assertTrue(isEditableProp("requestDispatcher.handleSelect", false, null));
|
||||
|
||||
assertTrue(isEditableProp("updateHandler/commitIntervalLowerBound", true, null));
|
||||
assertFalse(isEditableProp("updateHandler/commitIntervalLowerBound1", true, null));
|
||||
|
|
|
@ -107,7 +107,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/ping")));
|
||||
|
||||
String payload = "{\n" +
|
||||
" 'set-property' : { 'updateHandler.autoCommit.maxDocs':100, 'updateHandler.autoCommit.maxTime':10 } \n" +
|
||||
" 'set-property' : { 'updateHandler.autoCommit.maxDocs':100, 'updateHandler.autoCommit.maxTime':10 , 'requestDispatcher.requestParsers.addHttpRequestToContext':true} \n" +
|
||||
" }";
|
||||
runConfigCommand(harness, "/config?wt=json", payload);
|
||||
|
||||
|
@ -122,6 +122,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
|
||||
assertEquals("100", String.valueOf(getObjectByPath(m, true, ImmutableList.of("updateHandler", "autoCommit", "maxDocs"))));
|
||||
assertEquals("10", String.valueOf(getObjectByPath(m, true, ImmutableList.of("updateHandler", "autoCommit", "maxTime"))));
|
||||
assertEquals("true", String.valueOf(getObjectByPath(m, true, ImmutableList.of("requestDispatcher", "requestParsers", "addHttpRequestToContext"))));
|
||||
payload = "{\n" +
|
||||
" 'unset-property' : 'updateHandler.autoCommit.maxDocs'} \n" +
|
||||
" }";
|
||||
|
@ -366,6 +367,21 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
Arrays.asList("config", "transformer", "mytrans"),
|
||||
null,
|
||||
10);
|
||||
payload = "{\n" +
|
||||
"'create-initparams' : { 'name' : 'hello', 'key':'val'}\n" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness, "/config?wt=json", payload);
|
||||
Map map = testForResponseElement(writeHarness,
|
||||
testServerBaseUrl,
|
||||
"/config?wt=json",
|
||||
cloudSolrServer,
|
||||
Arrays.asList("config", "transformer", "mytrans"),
|
||||
null,
|
||||
10);
|
||||
List l = (List) ConfigOverlay.getObjectByPath(map,false, Arrays.asList("config", "initParams"));
|
||||
assertEquals( 1, l.size());
|
||||
assertEquals( "val", ((Map)l.get(0)).get("key") );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -484,7 +500,6 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
5);
|
||||
|
||||
|
||||
|
||||
payload = " {\n" +
|
||||
" 'set' : {'y':{\n" +
|
||||
" 'c':'CY val',\n" +
|
||||
|
|
|
@ -306,6 +306,8 @@ public class StrUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**Format using MesssageFormat but with the ROOT locale
|
||||
*/
|
||||
public static String formatString(String pattern, Object... args) {
|
||||
return new MessageFormat(pattern, Locale.ROOT).format(args);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue