You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2014/12/24 09:51:09 UTC

svn commit: r1647748 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/core/ core/src/java/org/apache/solr/handler/ core/src/java/org/apache/solr/response/ core/src/java/org/apache/solr/util/ core/src/test/org/apache/solr/core/ core/src/tes...

Author: noble
Date: Wed Dec 24 08:51:08 2014
New Revision: 1647748

URL: http://svn.apache.org/r1647748
Log:
SOLR-6770 Add/edit param sets and use them in requests

Added:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestParams.java
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestInitParams.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Wed Dec 24 08:51:08 2014
@@ -252,6 +252,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
 ----------------------

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java Wed Dec 24 08:51:08 2014
@@ -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 Ma
   @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 Ma
   }
 
   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";
+
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java Wed Dec 24 08:51:08 2014
@@ -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 ) {

Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestParams.java?rev=1647748&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestParams.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestParams.java Wed Dec 24 08:51:08 2014
@@ -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");
+    }
+  }
+}

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java Wed Dec 24 08:51:08 2014
@@ -45,6 +45,8 @@ import org.apache.solr.update.processor.
 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 i
   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 i
     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;
+  }
 
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java Wed Dec 24 08:51:08 2014
@@ -23,6 +23,7 @@ import org.apache.solr.common.util.Named
 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
     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
   }
 
   public void setPluginInfo(PluginInfo pluginInfo){
-    if(pluginInfo==null) this.pluginInfo = pluginInfo;
+    if(this.pluginInfo==null) this.pluginInfo = pluginInfo;
   }
 
   public PluginInfo getPluginInfo(){

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java Wed Dec 24 08:51:08 2014
@@ -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.ZkSolrResou
 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 R
             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 R
     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 R
       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 R
 
     }
 
+
+
+    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 R
 
   }
 
+  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 R
   @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 R
   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";
 
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java Wed Dec 24 08:51:08 2014
@@ -66,6 +66,7 @@ import org.apache.solr.search.SolrReturn
  * @since solr 0.9
  */
 public class SolrQueryResponse {
+  public static final String NAME = "response";
 
   /**
    * Container for user defined values

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java Wed Dec 24 08:51:08 2014
@@ -44,11 +44,13 @@ import org.apache.solr.common.SolrDocume
 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);
           }
         }
       }

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestInitParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestInitParams.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestInitParams.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestInitParams.java Wed Dec 24 08:51:08 2014
@@ -76,7 +76,7 @@ public class TestInitParams extends Solr
 
   }
 
-  @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 Solr
       assertEquals("B", def.get("b"));
       assertEquals("C", def.get("c"));
     }
-  }
+  }*/
   @Test
   public void testComponentWithConflictingInitParams(){
     SolrRequestHandler handler = h.getCore().getRequestHandler("/dump2");

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java Wed Dec 24 08:51:08 2014
@@ -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.Immutab
 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 exten
 
     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 exten
     try {
       return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
     } catch (JSONParser.ParseException e) {
+      log.error(response);
       return Collections.emptyMap();
     }
   }

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java Wed Dec 24 08:51:08 2014
@@ -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.DocC
 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
   public void doTest() throws Exception {
     setupHarnesses();
     testReqHandlerAPIs();
+    testReqParams();
 
   }
 
@@ -69,4 +74,211 @@ public class TestSolrConfigHandlerCloud
     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);
+
+
+  }
+
 }

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java?rev=1647748&r1=1647747&r2=1647748&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java Wed Dec 24 08:51:08 2014
@@ -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 TestSolrConfigHandlerConcur
     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();