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,39 +29,39 @@ 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 ;
|
||||
public class ConfigOverlay implements MapSerializable {
|
||||
private final int znodeVersion;
|
||||
private final Map<String, Object> data;
|
||||
private Map<String,Object> props;
|
||||
private Map<String,Object> userProps;
|
||||
private Map<String, Object> props;
|
||||
private Map<String, Object> userProps;
|
||||
|
||||
public ConfigOverlay(Map<String,Object> jsonObj, int znodeVersion){
|
||||
if(jsonObj == null) jsonObj= Collections.EMPTY_MAP;
|
||||
public ConfigOverlay(Map<String, Object> jsonObj, int znodeVersion) {
|
||||
if (jsonObj == null) jsonObj = Collections.EMPTY_MAP;
|
||||
this.znodeVersion = znodeVersion;
|
||||
data = Collections.unmodifiableMap(jsonObj);
|
||||
props = (Map<String, Object>) data.get("props");
|
||||
if(props == null) props= Collections.EMPTY_MAP;
|
||||
if (props == null) props = Collections.EMPTY_MAP;
|
||||
userProps = (Map<String, Object>) data.get("userProps");
|
||||
if(userProps == null) userProps= Collections.EMPTY_MAP;
|
||||
if (userProps == null) userProps = Collections.EMPTY_MAP;
|
||||
}
|
||||
public Object getXPathProperty(String xpath){
|
||||
return getXPathProperty(xpath,true);
|
||||
|
||||
public Object getXPathProperty(String xpath) {
|
||||
return getXPathProperty(xpath, true);
|
||||
}
|
||||
|
||||
public Object getXPathProperty(String xpath, boolean onlyPrimitive) {
|
||||
List<String> hierarchy = checkEditable(xpath, true, false);
|
||||
if(hierarchy == null) return null;
|
||||
if (hierarchy == null) return null;
|
||||
return getObjectByPath(props, onlyPrimitive, hierarchy);
|
||||
}
|
||||
|
||||
|
@ -70,10 +69,10 @@ public class ConfigOverlay implements MapSerializable{
|
|||
Map obj = root;
|
||||
for (int i = 0; i < hierarchy.size(); i++) {
|
||||
String s = hierarchy.get(i);
|
||||
if(i < hierarchy.size()-1){
|
||||
if (i < hierarchy.size() - 1) {
|
||||
if (!(obj.get(s) instanceof Map)) return null;
|
||||
obj = (Map) obj.get(s);
|
||||
if(obj == null) return null;
|
||||
if (obj == null) return null;
|
||||
} else {
|
||||
Object val = obj.get(s);
|
||||
if (onlyPrimitive && val instanceof Map) {
|
||||
|
@ -86,15 +85,16 @@ public class ConfigOverlay implements MapSerializable{
|
|||
return false;
|
||||
}
|
||||
|
||||
public ConfigOverlay setUserProperty(String key, Object val){
|
||||
public ConfigOverlay setUserProperty(String key, Object val) {
|
||||
Map copy = new LinkedHashMap(userProps);
|
||||
copy.put(key,val);
|
||||
copy.put(key, val);
|
||||
Map<String, Object> jsonObj = new LinkedHashMap<>(this.data);
|
||||
jsonObj.put("userProps", copy);
|
||||
return new ConfigOverlay(jsonObj, znodeVersion);
|
||||
}
|
||||
public ConfigOverlay unsetUserProperty(String key){
|
||||
if(!userProps.containsKey(key)) return this;
|
||||
|
||||
public ConfigOverlay unsetUserProperty(String key) {
|
||||
if (!userProps.containsKey(key)) return this;
|
||||
Map copy = new LinkedHashMap(userProps);
|
||||
copy.remove(key);
|
||||
Map<String, Object> jsonObj = new LinkedHashMap<>(this.data);
|
||||
|
@ -103,18 +103,18 @@ public class ConfigOverlay implements MapSerializable{
|
|||
}
|
||||
|
||||
public ConfigOverlay setProperty(String name, Object val) {
|
||||
List<String> hierarchy = checkEditable(name,false, true);
|
||||
List<String> hierarchy = checkEditable(name, false, true);
|
||||
Map deepCopy = getDeepCopy(props);
|
||||
Map obj = deepCopy;
|
||||
for (int i = 0; i < hierarchy.size(); i++) {
|
||||
String s = hierarchy.get(i);
|
||||
if (i < hierarchy.size()-1) {
|
||||
if(obj.get(s) == null || (!(obj.get(s) instanceof Map))) {
|
||||
if (i < hierarchy.size() - 1) {
|
||||
if (obj.get(s) == null || (!(obj.get(s) instanceof Map))) {
|
||||
obj.put(s, new LinkedHashMap<>());
|
||||
}
|
||||
obj = (Map) obj.get(s);
|
||||
} else {
|
||||
obj.put(s,val);
|
||||
obj.put(s, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,6 @@ public class ConfigOverlay implements MapSerializable{
|
|||
}
|
||||
|
||||
|
||||
|
||||
private Map getDeepCopy(Map map) {
|
||||
return (Map) ZkStateReader.fromJSON(ZkStateReader.toJSON(map));
|
||||
}
|
||||
|
@ -134,8 +133,9 @@ 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 (!isEditableProp(propName, isXPath, hierarchy)) {
|
||||
if (failOnError)
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, StrUtils.formatString(NOT_EDITABLE, propName));
|
||||
else return null;
|
||||
}
|
||||
return hierarchy;
|
||||
|
@ -143,13 +143,13 @@ public class ConfigOverlay implements MapSerializable{
|
|||
}
|
||||
|
||||
public ConfigOverlay unsetProperty(String name) {
|
||||
List<String> hierarchy = checkEditable(name,false, true);
|
||||
List<String> hierarchy = checkEditable(name, false, true);
|
||||
Map deepCopy = getDeepCopy(props);
|
||||
Map obj = deepCopy;
|
||||
for (int i = 0; i < hierarchy.size(); i++) {
|
||||
String s = hierarchy.get(i);
|
||||
if (i < hierarchy.size()-1) {
|
||||
if(obj.get(s) == null || (!(obj.get(s) instanceof Map))) {
|
||||
if (i < hierarchy.size() - 1) {
|
||||
if (obj.get(s) == null || (!(obj.get(s) instanceof Map))) {
|
||||
return this;
|
||||
}
|
||||
obj = (Map) obj.get(s);
|
||||
|
@ -169,7 +169,7 @@ public class ConfigOverlay implements MapSerializable{
|
|||
}
|
||||
|
||||
|
||||
public int getZnodeVersion(){
|
||||
public int getZnodeVersion() {
|
||||
return znodeVersion;
|
||||
}
|
||||
|
||||
|
@ -187,65 +187,129 @@ 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}" +
|
||||
" }," +
|
||||
" 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}" +
|
||||
"}}";
|
||||
static{
|
||||
private static Map editable_prop_map;
|
||||
//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: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(
|
||||
editable_prop_map = (Map) new ObjectBuilder(new JSONParser(new StringReader(
|
||||
MAPPING))).getObject();
|
||||
} catch (IOException e) {
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "error parsing mapping ", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isEditableProp(String path, boolean isXpath, List<String> hierarchy) {
|
||||
List<String> parts = StrUtils.splitSmart(path, isXpath? '/':'.');
|
||||
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++) {
|
||||
String part = parts.get(i);
|
||||
boolean isAttr = isXpath && part.startsWith("@");
|
||||
if(isAttr){
|
||||
if (isAttr) {
|
||||
part = part.substring(1);
|
||||
}
|
||||
if(hierarchy != null) hierarchy.add(part);
|
||||
if(obj ==null) return false;
|
||||
if(i == parts.size()-1) {
|
||||
if (hierarchy != null) hierarchy.add(part);
|
||||
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,'/'));
|
||||
Object o = getObjectByPath(props, false, StrUtils.splitSmart(xpath, '/'));
|
||||
if (o instanceof Map) {
|
||||
return (Map) o;
|
||||
return (Map) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -258,34 +322,39 @@ public class ConfigOverlay implements MapSerializable{
|
|||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
Map result = new LinkedHashMap();
|
||||
result.put(ZNODEVER,znodeVersion);
|
||||
result.put(ZNODEVER, znodeVersion);
|
||||
result.putAll(data);
|
||||
return result;
|
||||
}
|
||||
public Map<String, Map> getNamedPlugins(String typ){
|
||||
|
||||
public Map<String, Map> getNamedPlugins(String typ) {
|
||||
Map<String, Map> reqHandlers = (Map<String, Map>) data.get(typ);
|
||||
if(reqHandlers == null) return Collections.EMPTY_MAP;
|
||||
if (reqHandlers == null) return Collections.EMPTY_MAP;
|
||||
return Collections.unmodifiableMap(reqHandlers);
|
||||
}
|
||||
|
||||
|
||||
public ConfigOverlay addNamedPlugin(Map<String, Object> info, String typ) {
|
||||
Map dataCopy = RequestParams.getDeepCopy(data, 4);
|
||||
Map dataCopy = RequestParams.getDeepCopy(data, 4);
|
||||
Map reqHandler = (Map) dataCopy.get(typ);
|
||||
if(reqHandler== null) dataCopy.put(typ, reqHandler = new LinkedHashMap());
|
||||
reqHandler.put(info.get(CoreAdminParams.NAME) , info);
|
||||
if (reqHandler == null) dataCopy.put(typ, reqHandler = new LinkedHashMap());
|
||||
reqHandler.put(info.get(CoreAdminParams.NAME), info);
|
||||
return new ConfigOverlay(dataCopy, this.znodeVersion);
|
||||
}
|
||||
|
||||
public ConfigOverlay deleteNamedPlugin(String name, String typ) {
|
||||
Map dataCopy = RequestParams.getDeepCopy(data,4);
|
||||
Map dataCopy = RequestParams.getDeepCopy(data, 4);
|
||||
Map reqHandler = (Map) dataCopy.get(typ);
|
||||
if(reqHandler==null) return this;
|
||||
if (reqHandler == null) return this;
|
||||
reqHandler.remove(name);
|
||||
return new ConfigOverlay(dataCopy,this.znodeVersion);
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -88,22 +90,23 @@ import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME;
|
|||
* configuration data for a a Solr instance -- typically found in
|
||||
* "solrconfig.xml".
|
||||
*/
|
||||
public class SolrConfig extends Config implements MapSerializable{
|
||||
public class SolrConfig extends Config implements MapSerializable {
|
||||
|
||||
public static final Logger log = LoggerFactory.getLogger(SolrConfig.class);
|
||||
|
||||
|
||||
public static final String DEFAULT_CONF_FILE = "solrconfig.xml";
|
||||
private RequestParams requestParams;
|
||||
|
||||
public static enum PluginOpts {
|
||||
MULTI_OK,
|
||||
MULTI_OK,
|
||||
REQUIRE_NAME,
|
||||
REQUIRE_NAME_IN_OVERLAY,
|
||||
REQUIRE_CLASS,
|
||||
LAZY,
|
||||
// EnumSet.of and/or EnumSet.copyOf(Collection) are anoying
|
||||
// because of type determination
|
||||
NOOP
|
||||
}
|
||||
}
|
||||
|
||||
private int multipartUploadLimitKB;
|
||||
|
||||
|
@ -116,49 +119,56 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
private boolean addHttpRequestToContext;
|
||||
|
||||
private final SolrRequestParsers solrRequestParsers;
|
||||
|
||||
/** 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.
|
||||
* A default resource loader will be created (@see SolrResourceLoader)
|
||||
*@param name the configuration name used by the loader
|
||||
|
||||
/**
|
||||
* Creates a default instance from the solrconfig.xml.
|
||||
*/
|
||||
public SolrConfig(String name)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this( (SolrResourceLoader) null, name, null);
|
||||
public SolrConfig()
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this((SolrResourceLoader) null, DEFAULT_CONF_FILE, null);
|
||||
}
|
||||
|
||||
/** Creates a configuration instance from a configuration name and stream.
|
||||
/**
|
||||
* 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)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this((SolrResourceLoader) null, name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param name the configuration name
|
||||
* @param is the configuration stream
|
||||
*/
|
||||
public SolrConfig(String name, InputSource is)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this( (SolrResourceLoader) null, name, is );
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this((SolrResourceLoader) null, name, is);
|
||||
}
|
||||
|
||||
/** 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
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public SolrConfig(String instanceDir, String name, InputSource is)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
this(new SolrResourceLoader(instanceDir), name, is);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -168,16 +178,18 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
throw new SolrException(ErrorCode.SERVER_ERROR, "Error loading solr config from " + resource, e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
*
|
||||
* @param loader the resource loader
|
||||
* @param name the configuration name
|
||||
* @param is the configuration stream
|
||||
*/
|
||||
public SolrConfig(SolrResourceLoader loader, String name, InputSource is)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
super(loader, name, is, "/config/");
|
||||
getOverlay();//just in case it is not initialized
|
||||
getRequestParams();
|
||||
|
@ -188,7 +200,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
// Old indexDefaults and mainIndex sections are deprecated and fails fast for luceneMatchVersion=>LUCENE_4_0_0.
|
||||
// For older solrconfig.xml's we allow the old sections, but never mixed with the new <indexConfig>
|
||||
boolean hasDeprecatedIndexConfig = (getNode("indexDefaults", false) != null) || (getNode("mainIndex", false) != null);
|
||||
if(hasDeprecatedIndexConfig){
|
||||
if (hasDeprecatedIndexConfig) {
|
||||
throw new SolrException(ErrorCode.FORBIDDEN, "<indexDefaults> and <mainIndex> configuration sections are discontinued. Use <indexConfig> instead.");
|
||||
} else {
|
||||
defaultIndexConfig = mainIndexConfig = null;
|
||||
|
@ -207,9 +219,9 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
// Warn about deprecated / discontinued parameters
|
||||
// boolToFilterOptimizer has had no effect since 3.1
|
||||
if(get("query/boolTofilterOptimizer", null) != null)
|
||||
if (get("query/boolTofilterOptimizer", null) != null)
|
||||
log.warn("solrconfig.xml: <boolTofilterOptimizer> is currently not implemented and has no effect.");
|
||||
if(get("query/HashDocSet", null) != null)
|
||||
if (get("query/HashDocSet", null) != null)
|
||||
log.warn("solrconfig.xml: <HashDocSet> is deprecated and no longer recommended used.");
|
||||
|
||||
// TODO: Old code - in case somebody wants to re-enable. Also see SolrIndexSearcher#search()
|
||||
|
@ -228,62 +240,62 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
documentCacheConfig = CacheConfig.getConfig(this, "query/documentCache");
|
||||
CacheConfig conf = CacheConfig.getConfig(this, "query/fieldValueCache");
|
||||
if (conf == null) {
|
||||
Map<String,String> args = new HashMap<>();
|
||||
args.put("name","fieldValueCache");
|
||||
args.put("size","10000");
|
||||
args.put("initialSize","10");
|
||||
args.put("showItems","-1");
|
||||
Map<String, String> args = new HashMap<>();
|
||||
args.put("name", "fieldValueCache");
|
||||
args.put("size", "10000");
|
||||
args.put("initialSize", "10");
|
||||
args.put("showItems", "-1");
|
||||
conf = new CacheConfig(FastLRUCache.class, args, null);
|
||||
}
|
||||
fieldValueCacheConfig = conf;
|
||||
unlockOnStartup = getBool(indexConfigPrefix+"/unlockOnStartup", false);
|
||||
useColdSearcher = getBool("query/useColdSearcher",false);
|
||||
unlockOnStartup = getBool(indexConfigPrefix + "/unlockOnStartup", false);
|
||||
useColdSearcher = getBool("query/useColdSearcher", false);
|
||||
dataDir = get("dataDir", null);
|
||||
if (dataDir != null && dataDir.length()==0) dataDir=null;
|
||||
if (dataDir != null && dataDir.length() == 0) dataDir = null;
|
||||
|
||||
userCacheConfigs = CacheConfig.getMultipleConfigs(this, "query/cache");
|
||||
|
||||
org.apache.solr.search.SolrIndexSearcher.initRegenerators(this);
|
||||
|
||||
hashSetInverseLoadFactor = 1.0f / getFloat("//HashDocSet/@loadFactor",0.75f);
|
||||
hashDocSetMaxSize= getInt("//HashDocSet/@maxSize",3000);
|
||||
hashSetInverseLoadFactor = 1.0f / getFloat("//HashDocSet/@loadFactor", 0.75f);
|
||||
hashDocSetMaxSize = getInt("//HashDocSet/@maxSize", 3000);
|
||||
|
||||
httpCachingConfig = new HttpCachingConfig(this);
|
||||
|
||||
Node jmx = getNode("jmx", false);
|
||||
if (jmx != null) {
|
||||
jmxConfig = new JmxConfiguration(true,
|
||||
get("jmx/@agentId", null),
|
||||
get("jmx/@serviceUrl", null),
|
||||
get("jmx/@rootName", null));
|
||||
get("jmx/@agentId", null),
|
||||
get("jmx/@serviceUrl", null),
|
||||
get("jmx/@rootName", null));
|
||||
|
||||
} else {
|
||||
jmxConfig = new JmxConfiguration(false, null, null, null);
|
||||
}
|
||||
maxWarmingSearchers = getInt("query/maxWarmingSearchers",Integer.MAX_VALUE);
|
||||
maxWarmingSearchers = getInt("query/maxWarmingSearchers", Integer.MAX_VALUE);
|
||||
slowQueryThresholdMillis = getInt("query/slowQueryThresholdMillis", -1);
|
||||
for (SolrPluginInfo plugin : plugins) loadPluginInfo(plugin);
|
||||
updateHandlerInfo = loadUpdatehandlerInfo();
|
||||
|
||||
multipartUploadLimitKB = getInt(
|
||||
"requestDispatcher/requestParsers/@multipartUploadLimitInKB", 2048 );
|
||||
|
||||
formUploadLimitKB = getInt(
|
||||
"requestDispatcher/requestParsers/@formdataUploadLimitInKB", 2048 );
|
||||
|
||||
enableRemoteStreams = getBool(
|
||||
"requestDispatcher/requestParsers/@enableRemoteStreaming", false );
|
||||
|
||||
// Let this filter take care of /select?xxx format
|
||||
handleSelect = getBool(
|
||||
"requestDispatcher/@handleSelect", true );
|
||||
|
||||
addHttpRequestToContext = getBool(
|
||||
"requestDispatcher/requestParsers/@addHttpRequestToContext", false );
|
||||
updateHandlerInfo = loadUpdatehandlerInfo();
|
||||
|
||||
List<PluginInfo> argsInfos = pluginStore.get(InitParams.class.getName()) ;
|
||||
if(argsInfos!=null){
|
||||
Map<String,InitParams> argsMap = new HashMap<>();
|
||||
multipartUploadLimitKB = getInt(
|
||||
"requestDispatcher/requestParsers/@multipartUploadLimitInKB", 2048);
|
||||
|
||||
formUploadLimitKB = getInt(
|
||||
"requestDispatcher/requestParsers/@formdataUploadLimitInKB", 2048);
|
||||
|
||||
enableRemoteStreams = getBool(
|
||||
"requestDispatcher/requestParsers/@enableRemoteStreaming", false);
|
||||
|
||||
// Let this filter take care of /select?xxx format
|
||||
handleSelect = getBool(
|
||||
"requestDispatcher/@handleSelect", true);
|
||||
|
||||
addHttpRequestToContext = getBool(
|
||||
"requestDispatcher/requestParsers/@addHttpRequestToContext", false);
|
||||
|
||||
List<PluginInfo> argsInfos = getPluginInfos(InitParams.class.getName());
|
||||
if (argsInfos != null) {
|
||||
Map<String, InitParams> argsMap = new HashMap<>();
|
||||
for (PluginInfo p : argsInfos) {
|
||||
InitParams args = new InitParams(p);
|
||||
argsMap.put(args.name == null ? String.valueOf(args.hashCode()) : args.name, args);
|
||||
|
@ -296,7 +308,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
Config.log.info("Loaded SolrConfig: " + name);
|
||||
}
|
||||
|
||||
public static final List<SolrPluginInfo> plugins = ImmutableList.<SolrPluginInfo>builder()
|
||||
public static final List<SolrPluginInfo> plugins = ImmutableList.<SolrPluginInfo>builder()
|
||||
.add(new SolrPluginInfo(SolrRequestHandler.class, SolrRequestHandler.TYPE, REQUIRE_NAME, REQUIRE_CLASS, MULTI_OK, LAZY))
|
||||
.add(new SolrPluginInfo(QParserPlugin.class, "queryParser", REQUIRE_NAME, REQUIRE_CLASS, MULTI_OK))
|
||||
.add(new SolrPluginInfo(QueryResponseWriter.class, "queryResponseWriter", REQUIRE_NAME, REQUIRE_CLASS, MULTI_OK, LAZY))
|
||||
|
@ -304,36 +316,38 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
.add(new SolrPluginInfo(TransformerFactory.class, "transformer", REQUIRE_NAME, REQUIRE_CLASS, MULTI_OK))
|
||||
.add(new SolrPluginInfo(SearchComponent.class, "searchComponent", REQUIRE_NAME, REQUIRE_CLASS, MULTI_OK))
|
||||
.add(new SolrPluginInfo(UpdateRequestProcessorFactory.class, "updateProcessor", REQUIRE_NAME, REQUIRE_CLASS, MULTI_OK))
|
||||
// TODO: WTF is up with queryConverter???
|
||||
// it aparently *only* works as a singleton? - SOLR-4304
|
||||
// and even then -- only if there is a single SpellCheckComponent
|
||||
// because of queryConverter.setIndexAnalyzer
|
||||
// TODO: WTF is up with queryConverter???
|
||||
// it aparently *only* works as a singleton? - SOLR-4304
|
||||
// and even then -- only if there is a single SpellCheckComponent
|
||||
// because of queryConverter.setIndexAnalyzer
|
||||
.add(new SolrPluginInfo(QueryConverter.class, "queryConverter", REQUIRE_NAME, REQUIRE_CLASS))
|
||||
.add(new SolrPluginInfo(PluginBag.RuntimeLib.class, "runtimeLib", REQUIRE_NAME, MULTI_OK))
|
||||
// this is hackish, since it picks up all SolrEventListeners,
|
||||
// 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))
|
||||
// this is hackish, since it picks up all SolrEventListeners,
|
||||
// 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(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))
|
||||
.add(new SolrPluginInfo(IndexReaderFactory.class, "indexReaderFactory", REQUIRE_CLASS))
|
||||
.add(new SolrPluginInfo(UpdateRequestProcessorChain.class,"updateRequestProcessorChain", MULTI_OK))
|
||||
.add(new SolrPluginInfo(UpdateLog.class,"updateHandler/updateLog"))
|
||||
.add(new SolrPluginInfo(UpdateRequestProcessorChain.class, "updateRequestProcessorChain", MULTI_OK))
|
||||
.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);
|
||||
classVsSolrPluginInfo = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public static class SolrPluginInfo{
|
||||
public static class SolrPluginInfo {
|
||||
|
||||
public final Class clazz;
|
||||
public final String tag;
|
||||
|
@ -343,17 +357,26 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
private SolrPluginInfo(Class clz, String tag, PluginOpts... opts) {
|
||||
this.clazz = clz;
|
||||
this.tag = tag;
|
||||
this.options= opts == null? Collections.EMPTY_SET : EnumSet.of(NOOP, opts);
|
||||
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) {
|
||||
public static ConfigOverlay getConfigOverlay(SolrResourceLoader loader) {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = loader.openResource(ConfigOverlay.RESOURCE_NAME);
|
||||
} catch (IOException e) {
|
||||
//no problem no overlay.json file
|
||||
return new ConfigOverlay(Collections.EMPTY_MAP,-1);
|
||||
return new ConfigOverlay(Collections.EMPTY_MAP, -1);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -363,27 +386,29 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
log.info("config overlay loaded . version : {} ", version);
|
||||
}
|
||||
Map m = (Map) ObjectBuilder.getVal(new JSONParser(new InputStreamReader(in, StandardCharsets.UTF_8)));
|
||||
return new ConfigOverlay(m,version);
|
||||
return new ConfigOverlay(m, version);
|
||||
} catch (Exception e) {
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR,"Error reading config overlay",e);
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR, "Error reading config overlay", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Map<String,InitParams> initParams = Collections.emptyMap();
|
||||
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),
|
||||
getInt("updateHandler/autoCommit/maxTime",-1),
|
||||
getBool("updateHandler/indexWriter/closeWaitsForMerges",true),
|
||||
getBool("updateHandler/autoCommit/openSearcher",true),
|
||||
getInt("updateHandler/commitIntervalLowerBound",-1),
|
||||
getInt("updateHandler/autoSoftCommit/maxDocs",-1),
|
||||
getInt("updateHandler/autoSoftCommit/maxTime",-1),
|
||||
getBool("updateHandler/commitWithin/softCommit",true));
|
||||
return new UpdateHandlerInfo(get("updateHandler/@class", null),
|
||||
getInt("updateHandler/autoCommit/maxDocs", -1),
|
||||
getInt("updateHandler/autoCommit/maxTime", -1),
|
||||
getBool("updateHandler/indexWriter/closeWaitsForMerges", true),
|
||||
getBool("updateHandler/autoCommit/openSearcher", true),
|
||||
getInt("updateHandler/commitIntervalLowerBound", -1),
|
||||
getInt("updateHandler/autoSoftCommit/maxDocs", -1),
|
||||
getInt("updateHandler/autoSoftCommit/maxTime", -1),
|
||||
getBool("updateHandler/commitWithin/softCommit", true));
|
||||
}
|
||||
|
||||
private void loadPluginInfo(SolrPluginInfo pluginInfo) {
|
||||
|
@ -392,37 +417,37 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
List<PluginInfo> result = readPluginInfos(pluginInfo.tag, requireName, requireClass);
|
||||
|
||||
if (1 < result.size() && ! pluginInfo.options.contains(MULTI_OK)) {
|
||||
throw new SolrException
|
||||
if (1 < result.size() && !pluginInfo.options.contains(MULTI_OK)) {
|
||||
throw new SolrException
|
||||
(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Found " + result.size() + " configuration sections when at most "
|
||||
+ "1 is allowed matching expression: " + pluginInfo.tag);
|
||||
"Found " + result.size() + " configuration sections when at most "
|
||||
+ "1 is allowed matching expression: " + pluginInfo.getCleanTag());
|
||||
}
|
||||
if(!result.isEmpty()) pluginStore.put(pluginInfo.clazz.getName(),result);
|
||||
if (!result.isEmpty()) pluginStore.put(pluginInfo.clazz.getName(), result);
|
||||
}
|
||||
|
||||
public List<PluginInfo> readPluginInfos(String tag, boolean requireName, boolean requireClass) {
|
||||
ArrayList<PluginInfo> result = new ArrayList<>();
|
||||
NodeList nodes = (NodeList) evaluate(tag, XPathConstants.NODESET);
|
||||
for (int i=0; i<nodes.getLength(); i++) {
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
PluginInfo pluginInfo = new PluginInfo(nodes.item(i), "[solrconfig.xml] " + tag, requireName, requireClass);
|
||||
if(pluginInfo.isEnabled()) result.add(pluginInfo);
|
||||
if (pluginInfo.isEnabled()) result.add(pluginInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public SolrRequestParsers getRequestParsers() {
|
||||
return solrRequestParsers;
|
||||
}
|
||||
|
||||
/* The set of materialized parameters: */
|
||||
public final int booleanQueryMaxClauseCount;
|
||||
// SolrIndexSearcher - nutch optimizer -- Disabled since 3.1
|
||||
// SolrIndexSearcher - nutch optimizer -- Disabled since 3.1
|
||||
// public final boolean filtOptEnabled;
|
||||
// public final int filtOptCacheSize;
|
||||
// public final float filtOptThreshold;
|
||||
// SolrIndexSearcher - caches configurations
|
||||
public final CacheConfig filterCacheConfig ;
|
||||
public final CacheConfig filterCacheConfig;
|
||||
public final CacheConfig queryResultCacheConfig;
|
||||
public final CacheConfig documentCacheConfig;
|
||||
public final CacheConfig fieldValueCacheConfig;
|
||||
|
@ -443,7 +468,7 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
// IndexConfig settings
|
||||
public final SolrIndexConfig indexConfig;
|
||||
|
||||
protected UpdateHandlerInfo updateHandlerInfo ;
|
||||
protected UpdateHandlerInfo updateHandlerInfo;
|
||||
|
||||
private Map<String, List<PluginInfo>> pluginStore = new LinkedHashMap<>();
|
||||
|
||||
|
@ -453,23 +478,24 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
public final Version luceneMatchVersion;
|
||||
protected String dataDir;
|
||||
public final int slowQueryThresholdMillis; // threshold above which a query is considered slow
|
||||
|
||||
|
||||
//JMX configuration
|
||||
public final JmxConfiguration jmxConfig;
|
||||
|
||||
|
||||
private final HttpCachingConfig httpCachingConfig;
|
||||
|
||||
public HttpCachingConfig getHttpCachingConfig() {
|
||||
return httpCachingConfig;
|
||||
}
|
||||
|
||||
public static class JmxConfiguration implements MapSerializable{
|
||||
public static class JmxConfiguration implements MapSerializable {
|
||||
public boolean enabled = false;
|
||||
public String agentId;
|
||||
public String serviceUrl;
|
||||
public String rootName;
|
||||
|
||||
public JmxConfiguration(boolean enabled,
|
||||
String agentId,
|
||||
public JmxConfiguration(boolean enabled,
|
||||
String agentId,
|
||||
String serviceUrl,
|
||||
String rootName) {
|
||||
this.enabled = enabled;
|
||||
|
@ -479,180 +505,217 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
|
||||
if (agentId != null && serviceUrl != null) {
|
||||
throw new SolrException
|
||||
(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Incorrect JMX Configuration in solrconfig.xml, "+
|
||||
"both agentId and serviceUrl cannot be specified at the same time");
|
||||
(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Incorrect JMX Configuration in solrconfig.xml, " +
|
||||
"both agentId and serviceUrl cannot be specified at the same time");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
LinkedHashMap map = new LinkedHashMap();
|
||||
map.put("agentId",agentId);
|
||||
map.put("serviceUrl",serviceUrl);
|
||||
map.put("rootName",rootName);
|
||||
map.put("agentId", agentId);
|
||||
map.put("serviceUrl", serviceUrl);
|
||||
map.put("rootName", rootName);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HttpCachingConfig 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 */
|
||||
= "requestDispatcher/httpCaching/";
|
||||
|
||||
/**
|
||||
* For extracting Expires "ttl" from <cacheControl> config
|
||||
*/
|
||||
private final static Pattern MAX_AGE
|
||||
= Pattern.compile("\\bmax-age=(\\d+)");
|
||||
= Pattern.compile("\\bmax-age=(\\d+)");
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return ZkNodeProps.makeMap("never304",never304,
|
||||
"etagSeed",etagSeed,
|
||||
"lastModFrom",lastModFrom.name().toLowerCase(Locale.ROOT),
|
||||
"cacheControl",cacheControlHeader);
|
||||
return ZkNodeProps.makeMap("never304", never304,
|
||||
"etagSeed", etagSeed,
|
||||
"lastModFrom", lastModFrom.name().toLowerCase(Locale.ROOT),
|
||||
"cacheControl", cacheControlHeader);
|
||||
}
|
||||
|
||||
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));
|
||||
} catch (Exception e) {
|
||||
log.warn( "Unrecognized value for lastModFrom: " + s, e);
|
||||
log.warn("Unrecognized value for lastModFrom: " + s, e);
|
||||
return BOGUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final boolean never304;
|
||||
private final String etagSeed;
|
||||
private final String cacheControlHeader;
|
||||
private final Long maxAge;
|
||||
private final LastModFrom lastModFrom;
|
||||
|
||||
|
||||
private HttpCachingConfig(SolrConfig conf) {
|
||||
|
||||
never304 = conf.getBool(CACHE_PRE+"@never304", false);
|
||||
|
||||
etagSeed = conf.get(CACHE_PRE+"@etagSeed", "Solr");
|
||||
|
||||
never304 = conf.getBool(CACHE_PRE + "@never304", false);
|
||||
|
||||
lastModFrom = LastModFrom.parse(conf.get(CACHE_PRE+"@lastModFrom",
|
||||
"openTime"));
|
||||
|
||||
cacheControlHeader = conf.get(CACHE_PRE+"cacheControl",null);
|
||||
etagSeed = conf.get(CACHE_PRE + "@etagSeed", "Solr");
|
||||
|
||||
|
||||
lastModFrom = LastModFrom.parse(conf.get(CACHE_PRE + "@lastModFrom",
|
||||
"openTime"));
|
||||
|
||||
cacheControlHeader = conf.get(CACHE_PRE + "cacheControl", null);
|
||||
|
||||
Long tmp = null; // maxAge
|
||||
if (null != cacheControlHeader) {
|
||||
try {
|
||||
try {
|
||||
final Matcher ttlMatcher = MAX_AGE.matcher(cacheControlHeader);
|
||||
final String ttlStr = ttlMatcher.find() ? ttlMatcher.group(1) : null;
|
||||
tmp = (null != ttlStr && !"".equals(ttlStr))
|
||||
? Long.valueOf(ttlStr)
|
||||
: null;
|
||||
? Long.valueOf(ttlStr)
|
||||
: null;
|
||||
} catch (Exception e) {
|
||||
log.warn( "Ignoring exception while attempting to " +
|
||||
"extract max-age from cacheControl config: " +
|
||||
cacheControlHeader, e);
|
||||
log.warn("Ignoring exception while attempting to " +
|
||||
"extract max-age from cacheControl config: " +
|
||||
cacheControlHeader, e);
|
||||
}
|
||||
}
|
||||
maxAge = tmp;
|
||||
|
||||
}
|
||||
|
||||
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{
|
||||
public static class UpdateHandlerInfo implements MapSerializable {
|
||||
public final String className;
|
||||
public final int autoCommmitMaxDocs,autoCommmitMaxTime,commitIntervalLowerBound,
|
||||
autoSoftCommmitMaxDocs,autoSoftCommmitMaxTime;
|
||||
public final int autoCommmitMaxDocs, autoCommmitMaxTime, commitIntervalLowerBound,
|
||||
autoSoftCommmitMaxDocs, autoSoftCommmitMaxTime;
|
||||
public final boolean indexWriterCloseWaitsForMerges;
|
||||
public final boolean openSearcher; // is opening a new searcher part of hard autocommit?
|
||||
public final boolean commitWithinSoftCommit;
|
||||
|
||||
/**
|
||||
* @param autoCommmitMaxDocs set -1 as default
|
||||
* @param autoCommmitMaxTime set -1 as default
|
||||
* @param autoCommmitMaxDocs set -1 as default
|
||||
* @param autoCommmitMaxTime set -1 as default
|
||||
* @param commitIntervalLowerBound set -1 as default
|
||||
*/
|
||||
public UpdateHandlerInfo(String className, int autoCommmitMaxDocs, int autoCommmitMaxTime, boolean indexWriterCloseWaitsForMerges, boolean openSearcher, int commitIntervalLowerBound,
|
||||
int autoSoftCommmitMaxDocs, int autoSoftCommmitMaxTime, boolean commitWithinSoftCommit) {
|
||||
int autoSoftCommmitMaxDocs, int autoSoftCommmitMaxTime, boolean commitWithinSoftCommit) {
|
||||
this.className = className;
|
||||
this.autoCommmitMaxDocs = autoCommmitMaxDocs;
|
||||
this.autoCommmitMaxTime = autoCommmitMaxTime;
|
||||
this.indexWriterCloseWaitsForMerges = indexWriterCloseWaitsForMerges;
|
||||
this.openSearcher = openSearcher;
|
||||
this.commitIntervalLowerBound = commitIntervalLowerBound;
|
||||
|
||||
|
||||
this.autoSoftCommmitMaxDocs = autoSoftCommmitMaxDocs;
|
||||
this.autoSoftCommmitMaxTime = autoSoftCommmitMaxTime;
|
||||
|
||||
|
||||
this.commitWithinSoftCommit = commitWithinSoftCommit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
LinkedHashMap result = new LinkedHashMap();
|
||||
result.put("class",className);
|
||||
result.put("autoCommmitMaxDocs",autoCommmitMaxDocs);
|
||||
result.put("indexWriterCloseWaitsForMerges",indexWriterCloseWaitsForMerges);
|
||||
result.put("openSearcher",openSearcher);
|
||||
result.put("commitIntervalLowerBound",commitIntervalLowerBound);
|
||||
result.put("commitWithinSoftCommit",commitWithinSoftCommit);
|
||||
result.put("class", className);
|
||||
result.put("autoCommmitMaxDocs", autoCommmitMaxDocs);
|
||||
result.put("indexWriterCloseWaitsForMerges", indexWriterCloseWaitsForMerges);
|
||||
result.put("openSearcher", openSearcher);
|
||||
result.put("commitIntervalLowerBound", commitIntervalLowerBound);
|
||||
result.put("commitWithinSoftCommit", commitWithinSoftCommit);
|
||||
result.put("autoCommit", ZkNodeProps.makeMap(
|
||||
"maxDocs", autoCommmitMaxDocs,
|
||||
"maxTime",autoCommmitMaxTime,
|
||||
"maxTime", autoCommmitMaxTime,
|
||||
"commitIntervalLowerBound", commitIntervalLowerBound
|
||||
));
|
||||
result.put("autoSoftCommit" ,
|
||||
result.put("autoSoftCommit",
|
||||
ZkNodeProps.makeMap("maxDocs", autoSoftCommmitMaxDocs,
|
||||
"maxTime",autoSoftCommmitMaxTime));
|
||||
"maxTime", autoSoftCommmitMaxTime));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
* IndexDeletionPolicy, IndexReaderFactory, {@link TransformerFactory}
|
||||
* SolrRequestHandler,QParserPlugin, QueryResponseWriter,ValueSourceParser,
|
||||
* SearchComponent, QueryConverter, SolrEventListener, DirectoryFactory,
|
||||
* IndexDeletionPolicy, IndexReaderFactory, {@link TransformerFactory}
|
||||
*/
|
||||
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){
|
||||
|
||||
public PluginInfo getPluginInfo(String type) {
|
||||
List<PluginInfo> result = pluginStore.get(type);
|
||||
if (result == null || result.isEmpty()) {
|
||||
return null;
|
||||
|
@ -662,9 +725,9 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
}
|
||||
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Multiple plugins configured for type: " + type);
|
||||
"Multiple plugins configured for type: " + type);
|
||||
}
|
||||
|
||||
|
||||
private void initLibs() {
|
||||
NodeList nodes = (NodeList) evaluate("lib", XPathConstants.NODESET);
|
||||
if (nodes == null || nodes.getLength() == 0) return;
|
||||
|
@ -728,23 +791,36 @@ 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();
|
||||
if(getZnodeVersion() > -1) result.put("znodeVersion",getZnodeVersion());
|
||||
result.put("luceneMatchVersion",luceneMatchVersion);
|
||||
if (getZnodeVersion() > -1) result.put("znodeVersion", getZnodeVersion());
|
||||
result.put("luceneMatchVersion", luceneMatchVersion);
|
||||
result.put("updateHandler", getUpdateHandlerInfo().toMap());
|
||||
Map m = new LinkedHashMap();
|
||||
result.put("query", m);
|
||||
|
@ -753,22 +829,22 @@ 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;
|
||||
tag = tag.replace("/","");
|
||||
if(plugin.options.contains(PluginOpts.REQUIRE_NAME)){
|
||||
if (infos == null || infos.isEmpty()) continue;
|
||||
String tag = plugin.getCleanTag();
|
||||
tag = tag.replace("/", "");
|
||||
if (plugin.options.contains(PluginOpts.REQUIRE_NAME)) {
|
||||
LinkedHashMap items = new LinkedHashMap();
|
||||
for (PluginInfo info : infos) items.put(info.name, info.toMap());
|
||||
for (Map.Entry e : overlay.getNamedPlugins(plugin.tag).entrySet()) items.put(e.getKey(), e.getValue());
|
||||
result.put(tag, items);
|
||||
} else {
|
||||
if(plugin.options.contains(MULTI_OK)){
|
||||
if (plugin.options.contains(MULTI_OK)) {
|
||||
ArrayList<Map> l = new ArrayList<>();
|
||||
for (PluginInfo info : infos) l.add(info.toMap());
|
||||
result.put(tag,l);
|
||||
result.put(tag, l);
|
||||
} else {
|
||||
result.put(tag, infos.get(0).toMap());
|
||||
}
|
||||
|
@ -778,16 +854,16 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
}
|
||||
|
||||
|
||||
addCacheConfig(m,filterCacheConfig,queryResultCacheConfig,documentCacheConfig,fieldValueCacheConfig);
|
||||
if(jmxConfig != null) result.put("jmx",jmxConfig.toMap());
|
||||
addCacheConfig(m, filterCacheConfig, queryResultCacheConfig, documentCacheConfig, fieldValueCacheConfig);
|
||||
if (jmxConfig != null) result.put("jmx", jmxConfig.toMap());
|
||||
m = new LinkedHashMap();
|
||||
result.put("requestDispatcher", m);
|
||||
m.put("handleSelect",handleSelect);
|
||||
if(httpCachingConfig!=null) m.put("httpCaching", httpCachingConfig.toMap());
|
||||
m.put("requestParsers", ZkNodeProps.makeMap("multipartUploadLimitKB",multipartUploadLimitKB,
|
||||
"formUploadLimitKB",formUploadLimitKB,
|
||||
"addHttpRequestToContext",addHttpRequestToContext));
|
||||
if(indexConfig != null) result.put("indexConfig",indexConfig.toMap());
|
||||
m.put("handleSelect", handleSelect);
|
||||
if (httpCachingConfig != null) m.put("httpCaching", httpCachingConfig.toMap());
|
||||
m.put("requestParsers", ZkNodeProps.makeMap("multipartUploadLimitKB", multipartUploadLimitKB,
|
||||
"formUploadLimitKB", formUploadLimitKB,
|
||||
"addHttpRequestToContext", addHttpRequestToContext));
|
||||
if (indexConfig != null) result.put("indexConfig", indexConfig.toMap());
|
||||
|
||||
//TODO there is more to add
|
||||
|
||||
|
@ -795,38 +871,39 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
}
|
||||
|
||||
private void addCacheConfig(Map queryMap, CacheConfig... cache) {
|
||||
if(cache==null)return;
|
||||
for (CacheConfig config : cache) if(config !=null) queryMap.put(config.getNodeName(),config.toMap());
|
||||
if (cache == null) return;
|
||||
for (CacheConfig config : cache) if (config != null) queryMap.put(config.getNodeName(), config.toMap());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties getSubstituteProperties() {
|
||||
Map<String, Object> p = getOverlay().getUserProps();
|
||||
if(p==null || p.isEmpty()) return super.getSubstituteProperties();
|
||||
if (p == null || p.isEmpty()) return super.getSubstituteProperties();
|
||||
Properties result = new Properties(super.getSubstituteProperties());
|
||||
result.putAll(p);
|
||||
return result;
|
||||
}
|
||||
|
||||
private ConfigOverlay overlay;
|
||||
|
||||
public ConfigOverlay getOverlay() {
|
||||
if(overlay ==null) {
|
||||
if (overlay == null) {
|
||||
overlay = getConfigOverlay(getResourceLoader());
|
||||
}
|
||||
return overlay;
|
||||
}
|
||||
|
||||
public RequestParams getRequestParams() {
|
||||
if(requestParams == null){
|
||||
if (requestParams == null) {
|
||||
return refreshRequestParams();
|
||||
}
|
||||
return requestParams;
|
||||
}
|
||||
|
||||
|
||||
public RequestParams refreshRequestParams(){
|
||||
requestParams = RequestParams.getFreshRequestParams(getResourceLoader(),requestParams);
|
||||
public RequestParams refreshRequestParams() {
|
||||
requestParams = RequestParams.getFreshRequestParams(getResourceLoader(), requestParams);
|
||||
log.info("current version of requestparams : {}", requestParams.getZnodeVersion());
|
||||
return requestParams;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ public class SolrConfigHandler extends RequestHandlerBase {
|
|||
|
||||
private boolean verifyClass(CommandOperation op, String clz, Class expected) {
|
||||
if (clz == null) return true;
|
||||
if ( !"true".equals(String.valueOf(op.getStr("runtimeLib", null)))) {
|
||||
if (!"true".equals(String.valueOf(op.getStr("runtimeLib", null)))) {
|
||||
//this is not dynamically loaded so we can verify the class right away
|
||||
try {
|
||||
req.getCore().createInitInstance(new PluginInfo(SolrRequestHandler.TYPE, op.getDataMap()), expected, clz, "");
|
||||
|
@ -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));
|
||||
|
|
|
@ -67,7 +67,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
tmpConfDir = new File(tmpSolrHome, confDir);
|
||||
FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile());
|
||||
|
||||
final SortedMap<ServletHolder,String> extraServlets = new TreeMap<>();
|
||||
final SortedMap<ServletHolder, String> extraServlets = new TreeMap<>();
|
||||
final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class);
|
||||
solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi");
|
||||
extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...'
|
||||
|
@ -93,62 +93,63 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
}
|
||||
|
||||
|
||||
public void testProperty() throws Exception{
|
||||
public void testProperty() throws Exception {
|
||||
RestTestHarness harness = restTestHarness;
|
||||
Map confMap = getRespMap("/config?wt=json" ,harness);
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/luke")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/system")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/mbeans")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/plugins")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/threads")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/properties")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/logging")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/file")));
|
||||
assertNotNull( getObjectByPath(confMap,false,Arrays.asList("config","requestHandler","/admin/ping")));
|
||||
Map confMap = getRespMap("/config?wt=json", harness);
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/luke")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/system")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/mbeans")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/plugins")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/threads")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/properties")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/logging")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/file")));
|
||||
assertNotNull(getObjectByPath(confMap, false, Arrays.asList("config", "requestHandler", "/admin/ping")));
|
||||
|
||||
String payload= "{\n" +
|
||||
" 'set-property' : { 'updateHandler.autoCommit.maxDocs':100, 'updateHandler.autoCommit.maxTime':10 } \n" +
|
||||
String payload = "{\n" +
|
||||
" 'set-property' : { 'updateHandler.autoCommit.maxDocs':100, 'updateHandler.autoCommit.maxTime':10 , 'requestDispatcher.requestParsers.addHttpRequestToContext':true} \n" +
|
||||
" }";
|
||||
runConfigCommand( harness,"/config?wt=json", payload);
|
||||
runConfigCommand(harness, "/config?wt=json", payload);
|
||||
|
||||
Map m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
|
||||
Map m = (Map) getRespMap("/config/overlay?wt=json", harness).get("overlay");
|
||||
Map props = (Map) m.get("props");
|
||||
assertNotNull(props);
|
||||
assertEquals("100", String.valueOf(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxDocs")) ));
|
||||
assertEquals("10", String.valueOf(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxTime")) ));
|
||||
assertEquals("100", String.valueOf(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxDocs"))));
|
||||
assertEquals("10", String.valueOf(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxTime"))));
|
||||
|
||||
m = (Map) getRespMap("/config?wt=json" ,harness).get("config");
|
||||
m = (Map) getRespMap("/config?wt=json", harness).get("config");
|
||||
assertNotNull(m);
|
||||
|
||||
assertEquals( "100",String.valueOf(getObjectByPath(m, true, ImmutableList.of("updateHandler", "autoCommit", "maxDocs"))));
|
||||
assertEquals( "10",String.valueOf(getObjectByPath(m, true, ImmutableList.of("updateHandler", "autoCommit", "maxTime"))));
|
||||
payload= "{\n" +
|
||||
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" +
|
||||
" }";
|
||||
runConfigCommand(harness, "/config?wt=json", payload);
|
||||
|
||||
m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
|
||||
m = (Map) getRespMap("/config/overlay?wt=json", harness).get("overlay");
|
||||
props = (Map) m.get("props");
|
||||
assertNotNull(props);
|
||||
assertNull(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxDocs")));
|
||||
assertEquals("10", String.valueOf(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxTime"))));
|
||||
assertEquals("10", String.valueOf(getObjectByPath(props, true, ImmutableList.of("updateHandler", "autoCommit", "maxTime"))));
|
||||
}
|
||||
|
||||
public void testUserProp() throws Exception{
|
||||
public void testUserProp() throws Exception {
|
||||
RestTestHarness harness = restTestHarness;
|
||||
String payload= "{\n" +
|
||||
String payload = "{\n" +
|
||||
" 'set-user-property' : { 'my.custom.variable.a':'MODIFIEDA'," +
|
||||
" 'my.custom.variable.b':'MODIFIEDB' } \n" +
|
||||
" }";
|
||||
runConfigCommand(harness,"/config?wt=json", payload);
|
||||
runConfigCommand(harness, "/config?wt=json", payload);
|
||||
|
||||
Map m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
|
||||
Map m = (Map) getRespMap("/config/overlay?wt=json", harness).get("overlay");
|
||||
Map props = (Map) m.get("userProps");
|
||||
assertNotNull(props);
|
||||
assertEquals(props.get("my.custom.variable.a"), "MODIFIEDA");
|
||||
assertEquals(props.get("my.custom.variable.b"),"MODIFIEDB");
|
||||
assertEquals(props.get("my.custom.variable.b"), "MODIFIEDB");
|
||||
|
||||
m = (Map) getRespMap("/dump?wt=json&json.nl=map&initArgs=true" ,harness).get("initArgs");
|
||||
m = (Map) getRespMap("/dump?wt=json&json.nl=map&initArgs=true", harness).get("initArgs");
|
||||
|
||||
m = (Map) m.get(PluginInfo.DEFAULTS);
|
||||
assertEquals("MODIFIEDA", m.get("a"));
|
||||
|
@ -157,21 +158,21 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
}
|
||||
|
||||
public void testReqHandlerAPIs() throws Exception {
|
||||
reqhandlertests(restTestHarness, null,null);
|
||||
reqhandlertests(restTestHarness, null, null);
|
||||
}
|
||||
|
||||
public static void runConfigCommand(RestTestHarness harness, String uri, String payload) throws IOException {
|
||||
public static void runConfigCommand(RestTestHarness harness, String uri, String payload) throws IOException {
|
||||
String response = harness.post(uri, SolrTestCaseJ4.json(payload));
|
||||
Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||
assertNull(response, map.get("errors"));
|
||||
assertNull(response, map.get("errors"));
|
||||
}
|
||||
|
||||
|
||||
public static void reqhandlertests(RestTestHarness writeHarness,String testServerBaseUrl, CloudSolrClient cloudSolrServer) throws Exception {
|
||||
public static void reqhandlertests(RestTestHarness writeHarness, String testServerBaseUrl, CloudSolrClient cloudSolrServer) throws Exception {
|
||||
String payload = "{\n" +
|
||||
"'create-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy'}\n" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness,"/config?wt=json", payload);
|
||||
runConfigCommand(writeHarness, "/config?wt=json", payload);
|
||||
|
||||
testForResponseElement(writeHarness,
|
||||
testServerBaseUrl,
|
||||
|
@ -184,7 +185,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
payload = "{\n" +
|
||||
"'update-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy' , 'a':'b' , 'defaults': {'def_a':'def A val'}}\n" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness,"/config?wt=json", payload);
|
||||
runConfigCommand(writeHarness, "/config?wt=json", payload);
|
||||
|
||||
testForResponseElement(writeHarness,
|
||||
testServerBaseUrl,
|
||||
|
@ -205,21 +206,21 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
payload = "{\n" +
|
||||
"'delete-requesthandler' : '/x'" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness,"/config?wt=json", payload);
|
||||
runConfigCommand(writeHarness, "/config?wt=json", payload);
|
||||
boolean success = false;
|
||||
long startTime = System.nanoTime();
|
||||
int maxTimeoutSeconds = 10;
|
||||
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
while (TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
String uri = "/config/overlay?wt=json";
|
||||
Map m = testServerBaseUrl ==null? getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
|
||||
if(null == ConfigOverlay.getObjectByPath(m, true, Arrays.asList("overlay", "requestHandler", "/x","a"))) {
|
||||
Map m = testServerBaseUrl == null ? getRespMap(uri, writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl + uri, cloudSolrServer);
|
||||
if (null == ConfigOverlay.getObjectByPath(m, true, Arrays.asList("overlay", "requestHandler", "/x", "a"))) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
|
||||
}
|
||||
assertTrue( "Could not delete requestHandler ", success);
|
||||
assertTrue("Could not delete requestHandler ", success);
|
||||
|
||||
payload = "{\n" +
|
||||
"'create-queryconverter' : { 'name' : 'qc', 'class': 'org.apache.solr.spelling.SpellingQueryConverter'}\n" +
|
||||
|
@ -290,7 +291,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
Arrays.asList("config", "searchComponent", "tc"),
|
||||
null,
|
||||
10);
|
||||
//<valueSourceParser name="countUsage" class="org.apache.solr.core.CountUsageValueSourceParser"/>
|
||||
//<valueSourceParser name="countUsage" class="org.apache.solr.core.CountUsageValueSourceParser"/>
|
||||
payload = "{\n" +
|
||||
"'create-valuesourceparser' : { 'name' : 'cu', 'class': 'org.apache.solr.core.CountUsageValueSourceParser'}\n" +
|
||||
"}";
|
||||
|
@ -351,7 +352,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
testServerBaseUrl,
|
||||
"/config?wt=json",
|
||||
cloudSolrServer,
|
||||
Arrays.asList("config", "transformer","mytrans","value"),
|
||||
Arrays.asList("config", "transformer", "mytrans", "value"),
|
||||
"6",
|
||||
10);
|
||||
|
||||
|
@ -366,29 +367,44 @@ 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") );
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static Map testForResponseElement(RestTestHarness harness,
|
||||
String testServerBaseUrl,
|
||||
String uri,
|
||||
CloudSolrClient cloudSolrServer,List<String> jsonPath,
|
||||
Object expected,
|
||||
long maxTimeoutSeconds ) throws Exception {
|
||||
String testServerBaseUrl,
|
||||
String uri,
|
||||
CloudSolrClient cloudSolrServer, List<String> jsonPath,
|
||||
Object expected,
|
||||
long maxTimeoutSeconds) throws Exception {
|
||||
|
||||
boolean success = false;
|
||||
long startTime = System.nanoTime();
|
||||
Map m = null;
|
||||
|
||||
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
while (TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
try {
|
||||
m = testServerBaseUrl ==null? getRespMap(uri,harness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl + uri, cloudSolrServer) ;
|
||||
m = testServerBaseUrl == null ? getRespMap(uri, harness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl + uri, cloudSolrServer);
|
||||
} catch (Exception e) {
|
||||
Thread.sleep(100);
|
||||
continue;
|
||||
|
||||
}
|
||||
if(Objects.equals(expected,ConfigOverlay.getObjectByPath(m, false, jsonPath))) {
|
||||
if (Objects.equals(expected, ConfigOverlay.getObjectByPath(m, false, jsonPath))) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
@ -400,7 +416,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
return m;
|
||||
}
|
||||
|
||||
public void testReqParams() throws Exception{
|
||||
public void testReqParams() throws Exception {
|
||||
RestTestHarness harness = restTestHarness;
|
||||
String payload = " {\n" +
|
||||
" 'set' : {'x': {" +
|
||||
|
@ -410,7 +426,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
" }";
|
||||
|
||||
|
||||
TestSolrConfigHandler.runConfigCommand(harness,"/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.runConfigCommand(harness, "/config/params?wt=json", payload);
|
||||
|
||||
TestSolrConfigHandler.testForResponseElement(
|
||||
harness,
|
||||
|
@ -464,7 +480,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
"'create-requesthandler' : { 'name' : '/dump1', 'class': 'org.apache.solr.handler.DumpRequestHandler', 'useParams':'x' }\n" +
|
||||
"}";
|
||||
|
||||
TestSolrConfigHandler.runConfigCommand(harness,"/config?wt=json", payload);
|
||||
TestSolrConfigHandler.runConfigCommand(harness, "/config?wt=json", payload);
|
||||
|
||||
TestSolrConfigHandler.testForResponseElement(harness,
|
||||
null,
|
||||
|
@ -484,7 +500,6 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
5);
|
||||
|
||||
|
||||
|
||||
payload = " {\n" +
|
||||
" 'set' : {'y':{\n" +
|
||||
" 'c':'CY val',\n" +
|
||||
|
@ -494,7 +509,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
" }";
|
||||
|
||||
|
||||
TestSolrConfigHandler.runConfigCommand(harness,"/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.runConfigCommand(harness, "/config/params?wt=json", payload);
|
||||
|
||||
TestSolrConfigHandler.testForResponseElement(
|
||||
harness,
|
||||
|
@ -538,7 +553,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
"/dump1?wt=json&useParams=y",
|
||||
null,
|
||||
Arrays.asList("params", "d"),
|
||||
Arrays.asList("val 1", "val 2") ,
|
||||
Arrays.asList("val 1", "val 2"),
|
||||
5);
|
||||
|
||||
payload = " {\n" +
|
||||
|
@ -551,7 +566,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
" }";
|
||||
|
||||
|
||||
TestSolrConfigHandler.runConfigCommand(harness,"/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.runConfigCommand(harness, "/config/params?wt=json", payload);
|
||||
|
||||
TestSolrConfigHandler.testForResponseElement(
|
||||
harness,
|
||||
|
@ -580,7 +595,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
" }";
|
||||
|
||||
|
||||
TestSolrConfigHandler.runConfigCommand(harness,"/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.runConfigCommand(harness, "/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.testForResponseElement(
|
||||
harness,
|
||||
null,
|
||||
|
@ -599,7 +614,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
null,
|
||||
10);
|
||||
payload = " {'delete' : 'y'}";
|
||||
TestSolrConfigHandler.runConfigCommand(harness,"/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.runConfigCommand(harness, "/config/params?wt=json", payload);
|
||||
TestSolrConfigHandler.testForResponseElement(
|
||||
harness,
|
||||
null,
|
||||
|
|
|
@ -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