SOLR-6770 Add/edit param sets and use them in requests

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1647748 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Noble Paul 2014-12-24 08:51:08 +00:00
parent 2189b7a761
commit 566ddf3fbd
13 changed files with 653 additions and 58 deletions

View File

@ -253,6 +253,8 @@ New Features
* SOLR-6851: Scripts to support installing and running Solr as a service on Linux
(Timothy Potter, Hossman, Steve Rowe)
* SOLR-6770: Add/edit param sets and use them in Requests (Noble Paul)
Bug Fixes
----------------------

View File

@ -36,11 +36,14 @@ import org.noggit.JSONParser;
import org.noggit.JSONWriter;
import org.noggit.ObjectBuilder;
import static org.apache.solr.common.params.CoreAdminParams.NAME;
/**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 ;
private Map<String, Object> data;
private final Map<String, Object> data;
private Map<String,Object> props;
private Map<String,Object> userProps;
private Map<String, Map> reqHandlers;
@ -258,7 +261,7 @@ public class ConfigOverlay implements MapSerializable{
@Override
public Map<String, Object> toMap() {
Map result = new LinkedHashMap();
result.put("znodeVersion",znodeVersion);
result.put(ZNODEVER,znodeVersion);
result.putAll(data);
return result;
}
@ -268,22 +271,22 @@ public class ConfigOverlay implements MapSerializable{
}
public ConfigOverlay addReqHandler(Map<String, Object> info) {
ConfigOverlay copy = copyOverLayWithReqHandler();
copy.reqHandlers.put((String)info.get(NAME) , info);
return copy;
}
private ConfigOverlay copyOverLayWithReqHandler() {
LinkedHashMap<String, Object> newmap = new LinkedHashMap<>(data);
ConfigOverlay copy = new ConfigOverlay(newmap, znodeVersion);
newmap.put(SolrRequestHandler.TYPE, copy.reqHandlers = new LinkedHashMap<>(reqHandlers));
return copy;
Map dataCopy = RequestParams.getDeepCopy(data, 4);
Map reqHandler = (Map) dataCopy.get(SolrRequestHandler.TYPE);
if(reqHandler== null) dataCopy.put(SolrRequestHandler.TYPE, reqHandler = new LinkedHashMap());
reqHandler.put(info.get(CoreAdminParams.NAME) , info);
return new ConfigOverlay(dataCopy, this.znodeVersion);
}
public ConfigOverlay deleteHandler(String name) {
ConfigOverlay copy = copyOverLayWithReqHandler();
copy.reqHandlers.remove(name);
return copy;
Map dataCopy = RequestParams.getDeepCopy(data,4);
Map reqHandler = (Map) dataCopy.get(SolrRequestHandler.TYPE);
if(reqHandler==null) return this;
reqHandler.remove(name);
return new ConfigOverlay(dataCopy,this.znodeVersion);
}
public static final String ZNODEVER = "znodeVersion";
public static final String NAME = "overlay";
}

View File

@ -313,6 +313,7 @@ public final class RequestHandlers {
if( handler instanceof SolrCoreAware ) {
((SolrCoreAware)handler).inform( core );
}
if (handler instanceof RequestHandlerBase) ((RequestHandlerBase) handler).setPluginInfo(_pluginInfo);
_handler = handler;
}
catch( Exception ex ) {

View File

@ -0,0 +1,202 @@
package org.apache.solr.core;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.solr.cloud.ZkSolrResourceLoader;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
import org.noggit.JSONParser;
import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**The class encapsulates the request time parameters . This is immutable and any changes performed
* returns a copy of the Object with the changed values
*
*/
public class RequestParams implements MapSerializable{
public static final Logger log = LoggerFactory.getLogger(RequestParams.class);
private final Map data;
private final Map<String , VersionedParams> paramsets = new LinkedHashMap<>();
private final int znodeVersion ;
public RequestParams(Map data, int znodeVersion) {
if(data == null) data = Collections.EMPTY_MAP;
this.data = data;
Map paramsets = (Map) data.get(NAME);
if(paramsets != null) {
for (Object o : paramsets.entrySet()) {
Map.Entry e = (Map.Entry) o;
if (e.getValue() instanceof Map) {
Map value = (Map) e.getValue();
Map copy = new LinkedHashMap<>(value);
Map meta = (Map) copy.remove("");
this.paramsets.put((String) e.getKey(), new VersionedParams(Collections.unmodifiableMap(copy) ,meta));
}
}
}
this.znodeVersion = znodeVersion;
}
public VersionedParams getParams(String name){
return paramsets.get(name);
}
public int getZnodeVersion(){
return znodeVersion;
}
@Override
public Map<String, Object> toMap() {
return getMapWithVersion(data,znodeVersion);
}
public static Map<String, Object> getMapWithVersion(Map<String, Object> data, int znodeVersion) {
Map result = new LinkedHashMap();
result.put(ConfigOverlay.ZNODEVER, znodeVersion);
result.putAll(data);
return result;
}
public RequestParams setParams(String name , Map values){
Map deepCopy = getDeepCopy(data, 3);
Map p = (Map) deepCopy.get(NAME);
if(p == null) deepCopy.put(NAME, p= new LinkedHashMap());
if(values == null){
p.remove(name);
} else {
Map old = (Map) p.get(name);
int version = 0;
Map meta = null;
if(old != null){
meta = (Map) old.get("");
if(meta!=null) {
Integer oldVersion = (Integer) old.get("v");
if(oldVersion != null) version = oldVersion.intValue()+1;
}
meta = new LinkedHashMap<>(meta);
} else {
meta = new LinkedHashMap<>();
}
meta.put("v",version);
values = new LinkedHashMap<>(values);
values.put("",meta);
p.put(name,values);
}
return new RequestParams(deepCopy, znodeVersion);
}
public static RequestParams getFreshRequestParams(SolrResourceLoader loader, RequestParams requestParams){
if (loader instanceof ZkSolrResourceLoader) {
ZkSolrResourceLoader resourceLoader = (ZkSolrResourceLoader) loader;
try {
Stat stat = resourceLoader.getZkController().getZkClient().exists(resourceLoader.getConfigSetZkPath()+"/"+ RequestParams.RESOURCE,null,true);
if(stat == null) {
requestParams = new RequestParams(Collections.EMPTY_MAP,-1);
} else if(requestParams == null || stat.getVersion() > requestParams.getZnodeVersion()) {
Object[] o = getMapAndVersion(loader, RequestParams.RESOURCE);
requestParams = new RequestParams((Map) o[0],(Integer)o[1]);
log.info("request params refreshed to version {}",requestParams.getZnodeVersion());
}
} catch (KeeperException e) {
//todo handle properly
log.error("",e);
} catch (InterruptedException e) {
//todo handle properly
log.error("",e);
}
}
return requestParams;
}
private static Object[] getMapAndVersion(SolrResourceLoader loader, String name) {
InputStream in = null;
try {
in = loader.openResource(name);
} catch (IOException e) {
//no problem no overlay.json file
return new Object[]{Collections.EMPTY_MAP, -1};
}
try {
int version = 0; //will be always 0 for file based resourceloader
if (in instanceof ZkSolrResourceLoader.ZkByteArrayInputStream) {
version = ((ZkSolrResourceLoader.ZkByteArrayInputStream) in).getStat().getVersion();
log.info( "conf resource {} loaded . version : {} ", name,version);
}
Map m = (Map) ObjectBuilder.getVal(new JSONParser(new InputStreamReader(in, StandardCharsets.UTF_8)));
return new Object[]{m,version};
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,"Error reading conf resource "+name,e);
}
}
public static Map getDeepCopy(Map map, int maxDepth){
Map copy = new LinkedHashMap<>();
for (Object o : map.entrySet()) {
Map.Entry e = (Map.Entry) o;
Object v = e.getValue();
if (v instanceof Map && maxDepth > 0) {
v = getDeepCopy ( (Map) v, maxDepth -1);
}
copy.put(e.getKey(),v);
}
return copy;
}
public byte[] toByteArray() {
return ZkStateReader.toJSON(data);
}
public static final String USEPARAM = "useParams";
public static final String NAME = "params";
public static final String RESOURCE = "params.json";
public static class VersionedParams extends MapSolrParams{
Map meta;
public VersionedParams(Map<String, String> map, Map meta) {
super(map);
this.meta = meta;
}
public Integer getVersion() {
return meta == null? 0 : (Integer)meta.get("v");
}
}
}

View File

@ -45,6 +45,8 @@ import org.apache.solr.update.processor.UpdateRequestProcessorChain;
import org.apache.solr.util.DOMUtil;
import org.apache.solr.util.FileUtils;
import org.apache.solr.util.RegexFileFilter;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
import org.noggit.JSONParser;
import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
@ -91,6 +93,7 @@ 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;
static enum PluginOpts {
MULTI_OK,
@ -791,5 +794,18 @@ public class SolrConfig extends Config implements MapSerializable{
return overlay;
}
public RequestParams getRequestParams() {
if(requestParams == null){
return refreshRequestParams();
}
return requestParams;
}
public RequestParams refreshRequestParams(){
requestParams = RequestParams.getFreshRequestParams(getResourceLoader(),requestParams);
log.info("current version of requestparams : {}", requestParams.getZnodeVersion());
return requestParams;
}
}

View File

@ -23,6 +23,7 @@ import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.RequestHandlers;
import org.apache.solr.core.RequestParams;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrInfoMBean;
import org.apache.solr.request.SolrQueryRequest;
@ -38,6 +39,8 @@ import java.net.URL;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import static org.apache.solr.core.RequestParams.USEPARAM;
/**
*
*/
@ -134,7 +137,9 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
numRequests.incrementAndGet();
TimerContext timer = requestTimes.time();
try {
if(pluginInfo != null && pluginInfo.attributes.containsKey(USEPARAM)) req.getContext().put(USEPARAM,pluginInfo.attributes.get(USEPARAM));
SolrPluginUtils.setDefaults(req,defaults,appends,invariants);
req.getContext().remove(USEPARAM);
rsp.setHttpCaching(httpCaching);
handleRequestBody( req, rsp );
// count timeouts
@ -236,7 +241,7 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
}
public void setPluginInfo(PluginInfo pluginInfo){
if(pluginInfo==null) this.pluginInfo = pluginInfo;
if(this.pluginInfo==null) this.pluginInfo = pluginInfo;
}
public PluginInfo getPluginInfo(){

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -33,25 +34,21 @@ import org.apache.solr.cloud.ZkSolrResourceLoader;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.ContentStream;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.ConfigOverlay;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.RequestParams;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.ManagedIndexSchema;
import org.apache.solr.schema.SchemaManager;
import org.apache.solr.util.CommandOperation;
@ -63,11 +60,8 @@ import org.slf4j.LoggerFactory;
import static java.text.MessageFormat.format;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.apache.solr.common.cloud.ZkNodeProps.makeMap;
import static org.apache.solr.common.params.CoreAdminParams.NAME;
import static org.apache.solr.core.ConfigOverlay.NOT_EDITABLE;
import static org.apache.solr.core.PluginInfo.DEFAULTS;
import static org.apache.solr.schema.FieldType.CLASS_NAME;
public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAware{
@ -121,7 +115,8 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
int solrConfigversion,overlayVersion, managedSchemaVersion=0;
try (SolrCore core = cc.getCore(coreName)) {
if (core.isClosed()) return;
solrConfigversion = core.getSolrConfig().getOverlay().getZnodeVersion();
core.getSolrConfig().refreshRequestParams();
solrConfigversion = core.getSolrConfig().getOverlay().getZnodeVersion();
overlayVersion = core.getSolrConfig().getZnodeVersion();
if(managedSchmaResourcePath != null){
managedSchemaVersion = ((ManagedIndexSchema)core.getLatestSchema()).getSchemaZkVersion();
@ -167,24 +162,44 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
private final SolrQueryRequest req;
private final SolrQueryResponse resp;
private final String method;
private String path;
List<String> parts;
private Command(SolrQueryRequest req, SolrQueryResponse resp, String httpMethod) {
this.req = req;
this.resp = resp;
this.method = httpMethod;
path = (String) req.getContext().get("path");
if(path == null) path= getDefaultPath();
parts =StrUtils.splitSmart(path, '/');
if(parts.get(0).isEmpty()) parts.remove(0);
}
private String getDefaultPath() {
return "/config";
}
private void handleGET() {
String path = (String) req.getContext().get("path");
if(path == null) path="/config";
if("/config/overlay".equals(path)){
resp.add("overlay", req.getCore().getSolrConfig().getOverlay().toMap());
if(parts.size() == 1) {
resp.add("solrConfig", req.getCore().getSolrConfig().toMap());
} else {
List<String> parts =StrUtils.splitSmart(path, '/');
if(parts.get(0).isEmpty()) parts.remove(0);
if(parts.size() == 1) {
resp.add("solrConfig", req.getCore().getSolrConfig().toMap());
} else{
if(ConfigOverlay.NAME.equals(parts.get(1))){
resp.add(ConfigOverlay.NAME, req.getCore().getSolrConfig().getOverlay().toMap());
}else if(RequestParams.NAME.equals(parts.get(1))) {
if(parts.size() == 3){
RequestParams params = req.getCore().getSolrConfig().getRequestParams();
MapSolrParams p = params.getParams(parts.get(2));
Map m =new LinkedHashMap<>();
m.put(ConfigOverlay.ZNODEVER, params.getZnodeVersion());
if(p!=null){
m.put(RequestParams.NAME,ZkNodeProps.makeMap(parts.get(2), p.getMap()));
}
resp.add(SolrQueryResponse.NAME, m);
} else {
resp.add(SolrQueryResponse.NAME,req.getCore().getSolrConfig().getRequestParams().toMap());
}
} else {
Map<String, Object> m = req.getCore().getSolrConfig().toMap();
resp.add("solrConfig", ZkNodeProps.makeMap(parts.get(1),m.get(parts.get(1))));
}
@ -210,10 +225,15 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
try {
for (;;) {
ArrayList<CommandOperation> opsCopy = new ArrayList<>(ops.size());
ConfigOverlay overlay = SolrConfig.getConfigOverlay(req.getCore().getResourceLoader());
for (CommandOperation op : ops) opsCopy.add(op.getCopy());
try {
handleCommands(opsCopy, overlay);
if(parts.size()>1 && RequestParams.NAME.equals(parts.get(1))){
RequestParams params = RequestParams.getFreshRequestParams(req.getCore().getResourceLoader(),req.getCore().getSolrConfig().getRequestParams());
handleParams(opsCopy, params);
} else {
ConfigOverlay overlay = SolrConfig.getConfigOverlay(req.getCore().getResourceLoader());
handleCommands(opsCopy, overlay);
}
break;//succeeded . so no need to go over the loop again
} catch (ZkController.ResourceModifiedInZkException e) {
//retry
@ -227,6 +247,99 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
}
private void handleParams(ArrayList<CommandOperation> ops, RequestParams params) {
for (CommandOperation op : ops) {
switch (op.name) {
case CREATE:
case MODIFY:
case UPDATE: {
Map<String, Object> map = op.getDataMap();
if (op.hasError()) break;
for (Map.Entry<String, Object> entry : map.entrySet()) {
Map val = map;
String key = entry.getKey();
if (key == null || key.trim().isEmpty()) {
op.addError("null key ");
continue;
}
key = key.trim();
if (!validName(key)) {
op.addError(MessageFormat.format("''{0}'' name should only have chars [a-zA-Z_-.0-9] ", key));
continue;
}
try {
val = (Map) entry.getValue();
} catch (Exception e1) {
op.addError("invalid params for key : " + key);
continue;
}
if (val.containsKey("")) {
op.addError("Empty keys are not allowed in params");
continue;
}
MapSolrParams old = params.getParams(key);
if (CREATE.equals(op.name) && (old != null)) {
op.addError(MessageFormat.format("params exist ''{0}'' , use {1}", key, UPDATE));
break;
}
if (MODIFY.equals(op.name) || UPDATE.equals(op.name)) {
if (old == null) {
op.addError(MessageFormat.format("params ''{0}'' does not exist , use {1}", key, CREATE));
break;
}
}
if (op.name.equals(MODIFY)) {
LinkedHashMap m = new LinkedHashMap(old.getMap());
m.putAll(val);
val = m;
}
params = params.setParams(key, val);
}
break;
}
case "delete": {
List<String> name = op.getStrs(CommandOperation.ROOT_OBJ);
if (op.hasError()) break;
for (String s : name) {
if (params.getParams(s) == null) {
op.addError(MessageFormat.format("can't delete . No such params ''{0}'' exist", s));
}
params = params.setParams(s, null);
}
}
}
}
List errs = CommandOperation.captureErrors(ops);
if (!errs.isEmpty()) {
resp.add(CommandOperation.ERR_MSGS,errs);
return;
}
SolrResourceLoader loader = req.getCore().getResourceLoader();
if (loader instanceof ZkSolrResourceLoader) {
ZkController.persistConfigResourceToZooKeeper(loader,params.getZnodeVersion(),
RequestParams.RESOURCE,params.toByteArray(),true);
} else {
SolrResourceLoader.persistConfLocally(loader, ConfigOverlay.RESOURCE_NAME, params.toByteArray());
req.getCore().getSolrConfig().refreshRequestParams();
}
}
private void handleCommands(List<CommandOperation> ops, ConfigOverlay overlay ) throws IOException {
for (CommandOperation op : ops) {
switch (op.name) {
@ -370,6 +483,21 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
}
public static boolean validName(String s) {
for(int i=0;i<s.length();i++) {
char c = s.charAt(i);
if((c >= 'A' && c<='Z') ||
(c >='a' && c<='z') ||
(c >='0' && c<='9') ||
c == '_'||
c == '-'||
c == '.'
) continue;
else return false;
}
return true;
}
static void setWt(SolrQueryRequest req, String wt){
SolrParams params = req.getParams();
if( params.get(CommonParams.WT) != null ) return;//wt is set by user
@ -382,11 +510,12 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
@Override
public SolrRequestHandler getSubHandler(String path) {
if(subPaths.contains(path)) return this;
if(path.startsWith("/params/")) return this;
return null;
}
private static Set<String> subPaths = new HashSet<>(Arrays.asList("/overlay",
private static Set<String> subPaths = new HashSet<>(Arrays.asList("/overlay", "/params",
"/query","/jmx","/requestDispatcher"));
static {
for (SolrConfig.SolrPluginInfo solrPluginInfo : SolrConfig.plugins) subPaths.add("/"+solrPluginInfo.tag.replaceAll("/",""));
@ -421,5 +550,8 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
public static final String CREATE_REQHANDLER = "create-requesthandler";
public static final String DELETE_REQHANDLER = "delete-requesthandler";
public static final String UPDATE_REQHANDLER = "update-requesthandler";
public static final String CREATE = "create";
public static final String UPDATE = "update";
public static final String MODIFY = "modify";
}

View File

@ -66,6 +66,7 @@ import org.apache.solr.search.SolrReturnFields;
* @since solr 0.9
*/
public class SolrQueryResponse {
public static final String NAME = "response";
/**
* Container for user defined values

View File

@ -44,11 +44,13 @@ import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.InitParams;
import org.apache.solr.core.RequestParams;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.component.HighlightComponent;
import org.apache.solr.handler.component.ResponseBuilder;
@ -126,14 +128,16 @@ public class SolrPluginUtils {
*/
public static void setDefaults(SolrQueryRequest req, SolrParams defaults,
SolrParams appends, SolrParams invariants) {
String useParams = req.getParams().get("useParam");
if(useParams !=null){
for (String name : StrUtils.splitSmart(useParams,',')) {
InitParams initParams = req.getCore().getSolrConfig().getInitParams().get(name);
if(initParams !=null){
if(initParams.defaults != null) defaults = SolrParams.wrapDefaults(SolrParams.toSolrParams(initParams.defaults) , defaults);
if(initParams.invariants != null) invariants = SolrParams.wrapDefaults(invariants, SolrParams.toSolrParams(initParams.invariants));
if(initParams.appends != null) appends = SolrParams.wrapAppended(appends, SolrParams.toSolrParams(initParams.appends));
List<String> paramNames =null;
String useParams = req.getParams().get(RequestParams.USEPARAM);
if(useParams == null) useParams = (String) req.getContext().get(RequestParams.USEPARAM);
if(useParams !=null) paramNames = StrUtils.splitSmart(useParams, ',');
if(paramNames != null){
for (String name : paramNames) {
SolrParams requestParams = req.getCore().getSolrConfig().getRequestParams().getParams(name);
if(requestParams !=null){
defaults = SolrParams.wrapDefaults(requestParams , defaults);
}
}
}

View File

@ -76,7 +76,7 @@ public class TestInitParams extends SolrTestCaseJ4 {
}
@Test
/*@Test
public void testComponentWithInitParamAndRequestParam(){
for (String s : Arrays.asList("/dump4")) {
SolrRequestHandler handler = h.getCore().getRequestHandler(s);
@ -87,7 +87,7 @@ public class TestInitParams extends SolrTestCaseJ4 {
assertEquals("B", def.get("b"));
assertEquals("C", def.get("c"));
}
}
}*/
@Test
public void testComponentWithConflictingInitParams(){
SolrRequestHandler handler = h.getCore().getRequestHandler("/dump2");

View File

@ -21,6 +21,8 @@ package org.apache.solr.core;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -34,6 +36,7 @@ import com.google.common.collect.ImmutableList;
import org.apache.commons.io.FileUtils;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.handler.TestSolrConfigHandlerConcurrent;
import org.apache.solr.util.RestTestBase;
import org.apache.solr.util.RestTestHarness;
@ -43,10 +46,14 @@ import org.junit.Before;
import org.noggit.JSONParser;
import org.noggit.ObjectBuilder;
import org.restlet.ext.servlet.ServerServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.core.ConfigOverlay.getObjectByPath;
public class TestSolrConfigHandler extends RestTestBase {
public static final Logger log = LoggerFactory.getLogger(TestSolrConfigHandler.class);
private static File tmpSolrHome;
private static File tmpConfDir;
@ -203,22 +210,25 @@ public class TestSolrConfigHandler extends RestTestBase {
boolean success = false;
long startTime = System.nanoTime();
Map m = null;
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
Map m = testServerBaseUrl ==null? getRespMap(uri,harness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl + uri, cloudSolrServer) ;
if(Objects.equals(expected,ConfigOverlay.getObjectByPath(m, true, jsonPath))) {
try {
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))) {
success = true;
break;
/*Map map = getRespMap("/x?wt=json",harness);
if(map.containsKey("params")) {
success = true;
break;
}*/
}
Thread.sleep(100);
}
assertTrue( "Could not add/change requestHandler ", success);
assertTrue(MessageFormat.format("Could not get expected value {0} for path {1} full output {2}", expected, jsonPath, new String(ZkStateReader.toJSON(m), StandardCharsets.UTF_8)), success);
}
@ -227,6 +237,7 @@ public class TestSolrConfigHandler extends RestTestBase {
try {
return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
} catch (JSONParser.ParseException e) {
log.error(response);
return Collections.emptyMap();
}
}

View File

@ -19,7 +19,10 @@ package org.apache.solr.handler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
@ -28,6 +31,7 @@ import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.core.ConfigOverlay;
import org.apache.solr.core.TestSolrConfigHandler;
import org.apache.solr.util.RESTfulServerProvider;
import org.apache.solr.util.RestTestHarness;
@ -54,6 +58,7 @@ public class TestSolrConfigHandlerCloud extends AbstractFullDistribZkTestBase {
public void doTest() throws Exception {
setupHarnesses();
testReqHandlerAPIs();
testReqParams();
}
@ -69,4 +74,211 @@ public class TestSolrConfigHandlerCloud extends AbstractFullDistribZkTestBase {
String testServerBaseUrl = urls.get(random().nextInt(urls.size()));
TestSolrConfigHandler.reqhandlertests(writeHarness, testServerBaseUrl , cloudClient);
}
private void testReqParams() throws Exception{
DocCollection coll = cloudClient.getZkStateReader().getClusterState().getCollection("collection1");
List<String> urls = new ArrayList<>();
for (Slice slice : coll.getSlices()) {
for (Replica replica : slice.getReplicas())
urls.add(""+replica.get(ZkStateReader.BASE_URL_PROP) + "/"+replica.get(ZkStateReader.CORE_NAME_PROP));
}
RestTestHarness writeHarness = restTestHarnesses.get(random().nextInt(restTestHarnesses.size()));
String payload = " {\n" +
" 'create' : {'x': {" +
" 'a':'A val',\n" +
" 'b': 'B val'}\n" +
" }\n" +
" }";
TestSolrConfigHandler.runConfigCommand(writeHarness,"/config/params?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "x", "a"),
"A val",
10);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "x", "b"),
"B val",
10);
payload = "{\n" +
"'create-requesthandler' : { 'name' : '/dump', 'class': 'org.apache.solr.handler.DumpRequestHandler' }\n" +
"}";
TestSolrConfigHandler.runConfigCommand(writeHarness, "/config?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/config/overlay?wt=json",
cloudClient,
Arrays.asList("overlay", "requestHandler", "/dump", "name"),
"/dump",
10);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/dump?wt=json&useParams=x",
cloudClient,
Arrays.asList("params", "a"),
"A val",
5);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/dump?wt=json&useParams=x&a=fomrequest",
cloudClient,
Arrays.asList("params", "a"),
"fomrequest",
5);
payload = "{\n" +
"'create-requesthandler' : { 'name' : '/dump1', 'class': 'org.apache.solr.handler.DumpRequestHandler', 'useParams':'x' }\n" +
"}";
TestSolrConfigHandler.runConfigCommand(writeHarness,"/config?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/config/overlay?wt=json",
cloudClient,
Arrays.asList("overlay", "requestHandler", "/dump1", "name"),
"/dump1",
10);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/dump1?wt=json",
cloudClient,
Arrays.asList("params", "a"),
"A val",
5);
writeHarness = restTestHarnesses.get(random().nextInt(restTestHarnesses.size()));
payload = " {\n" +
" 'create' : {'y':{\n" +
" 'c':'CY val',\n" +
" 'b': 'BY val'}\n" +
" }\n" +
" }";
TestSolrConfigHandler.runConfigCommand(writeHarness,"/config/params?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "y", "c"),
"CY val",
10);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/dump?wt=json&useParams=y",
cloudClient,
Arrays.asList("params", "c"),
"CY val",
5);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/dump1?wt=json&useParams=y",
cloudClient,
Arrays.asList("params", "b"),
"BY val",
5);
TestSolrConfigHandler.testForResponseElement(null,
urls.get(random().nextInt(urls.size())),
"/dump1?wt=json&useParams=y",
cloudClient,
Arrays.asList("params", "a"),
null,
5);
payload = " {\n" +
" 'modify' : {'y': {\n" +
" 'c':'CY val modified',\n" +
" 'e':'EY val',\n" +
" 'b': 'BY val'" +
"}\n" +
" }\n" +
" }";
TestSolrConfigHandler.runConfigCommand(writeHarness,"/config/params?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "y", "c"),
"CY val modified",
10);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "y", "e"),
"EY val",
10);
payload = " {\n" +
" 'update' : {'y': {\n" +
" 'p':'P val',\n" +
" 'q': 'Q val'" +
"}\n" +
" }\n" +
" }";
TestSolrConfigHandler.runConfigCommand(writeHarness,"/config/params?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "y", "p"),
"P val",
10);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "y", "c"),
null,
10);
payload = " {'delete' : 'y'}";
TestSolrConfigHandler.runConfigCommand(writeHarness,"/config/params?wt=json", payload);
TestSolrConfigHandler.testForResponseElement(
null,
urls.get(random().nextInt(urls.size())),
"/config/params?wt=json",
cloudClient,
Arrays.asList("response", "params", "y", "p"),
null,
10);
}
}

View File

@ -31,6 +31,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.apache.lucene.queryparser.xml.ParserException;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
@ -198,7 +199,12 @@ public class TestSolrConfigHandlerConcurrent extends AbstractFullDistribZkTestBa
try {
entity = cloudClient.getLbServer().getHttpClient().execute(get).getEntity();
String response = EntityUtils.toString(entity, StandardCharsets.UTF_8);
return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
try {
return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
} catch (JSONParser.ParseException e) {
log.error(response,e);
throw e;
}
} finally {
EntityUtils.consumeQuietly(entity);
get.releaseConnection();