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();