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/11/27 14:16:22 UTC

svn commit: r1642141 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/cloud/ core/src/java/org/apache/solr/core/ core/src/java/org/apache/solr/handler/ core/src/java/org/apache/solr/util/ core/src/test/org/apache/solr/core/ core/src/test/o...

Author: noble
Date: Thu Nov 27 13:16:22 2014
New Revision: 1642141

URL: http://svn.apache.org/r1642141
Log:
SOLR-6607 Managing requesthandlers through API

Added:
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/ZkController.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.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/SolrConfigHandler.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.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/TestSolrConfigHandlerConcurrent.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1642141&r1=1642140&r2=1642141&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Thu Nov 27 13:16:22 2014
@@ -217,6 +217,8 @@ New Features
 
 * SOLR-6533: Support editing common solrconfig.xml values (Noble Paul)
 
+* SOLR-6607: Managing requesthandlers throuh API (Noble Paul)
+
 Bug Fixes
 ----------------------
 

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/ZkController.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/ZkController.java?rev=1642141&r1=1642140&r2=1642141&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/ZkController.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/ZkController.java Thu Nov 27 13:16:22 2014
@@ -2235,17 +2235,19 @@ public final class ZkController {
               log.info("Watcher on {} is removed ", zkDir);
               return;
             }
-            final Set<Runnable> listeners = confDirectoryListeners.get(zkDir);
+            Set<Runnable> listeners = confDirectoryListeners.get(zkDir);
             if (listeners != null && !listeners.isEmpty()) {
+              final Set<Runnable> listenersCopy = new HashSet<>(listeners);
               new Thread() {
                 //run these in a separate thread because this can be long running
                 public void run() {
-                  for (final Runnable listener : listeners)
+                  for (final Runnable listener : listenersCopy) {
                     try {
                       listener.run();
                     } catch (Exception e) {
                       log.warn("listener throws error", e);
                     }
+                  }
                 }
               }.start();
             }

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=1642141&r1=1642140&r2=1642141&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 Thu Nov 27 13:16:22 2014
@@ -28,17 +28,22 @@ import java.util.Map;
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.request.SolrRequestHandler;
 import org.noggit.CharArr;
 import org.noggit.JSONParser;
 import org.noggit.JSONWriter;
 import org.noggit.ObjectBuilder;
 
+import static org.apache.solr.common.params.CoreAdminParams.NAME;
+
 public class ConfigOverlay implements MapSerializable{
   private final int znodeVersion ;
   private Map<String, Object> data;
   private Map<String,Object> props;
   private Map<String,Object> userProps;
+  private Map<String, Map> reqHandlers;
 
   public ConfigOverlay(Map<String,Object> jsonObj, int znodeVersion){
     if(jsonObj == null) jsonObj= Collections.EMPTY_MAP;
@@ -48,6 +53,8 @@ public class ConfigOverlay implements Ma
     if(props == null) props= Collections.EMPTY_MAP;
     userProps = (Map<String, Object>) data.get("userProps");
     if(userProps == null) userProps= Collections.EMPTY_MAP;
+    reqHandlers = (Map<String, Map>) data.get(SolrRequestHandler.TYPE);
+    if(reqHandlers == null) reqHandlers = new LinkedHashMap<>();
 
   }
   public Object getXPathProperty(String xpath){
@@ -255,4 +262,28 @@ public class ConfigOverlay implements Ma
     result.putAll(data);
     return result;
   }
+
+  public Map<String, Map> getReqHandlers() {
+    return Collections.unmodifiableMap(reqHandlers);
+  }
+
+  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;
+  }
+
+  public ConfigOverlay deleteHandler(String name) {
+    ConfigOverlay copy = copyOverLayWithReqHandler();
+    copy.reqHandlers.remove(name);
+    return copy;
+
+  }
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java?rev=1642141&r1=1642140&r2=1642141&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java Thu Nov 27 13:16:22 2014
@@ -22,8 +22,12 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import java.util.*;
+
+import static java.util.Arrays.asList;
 import static java.util.Collections.unmodifiableList;
 import static java.util.Collections.unmodifiableMap;
+import static org.apache.solr.common.params.CoreAdminParams.NAME;
+import static org.apache.solr.schema.FieldType.CLASS_NAME;
 
 /**
  * An Object which represents a Plugin of any type 
@@ -38,8 +42,8 @@ public class PluginInfo implements MapSe
 
   public PluginInfo(String type, Map<String, String> attrs ,NamedList initArgs, List<PluginInfo> children) {
     this.type = type;
-    this.name = attrs.get("name");
-    this.className = attrs.get("class");
+    this.name = attrs.get(NAME);
+    this.className = attrs.get(CLASS_NAME);
     this.initArgs = initArgs;
     attributes = unmodifiableMap(attrs);
     this.children = children == null ? Collections.<PluginInfo>emptyList(): unmodifiableList(children);
@@ -49,14 +53,27 @@ public class PluginInfo implements MapSe
 
   public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
     type = node.getNodeName();
-    name = DOMUtil.getAttr(node, "name", requireName ? err : null);
-    className = DOMUtil.getAttr(node, "class", requireClass ? err : null);
+    name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
+    className = DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null);
     initArgs = DOMUtil.childNodesToNamedList(node);
     attributes = unmodifiableMap(DOMUtil.toMap(node.getAttributes()));
     children = loadSubPlugins(node);
     isFromSolrConfig = true;
   }
 
+  public PluginInfo(String type, Map<String,Object> map) {
+    LinkedHashMap m = new LinkedHashMap<>(map);
+    NamedList nl = new NamedList();
+    for (String s : asList(DEFAULTS, APPENDS, INVARIANTS)) if (m.get(s) != null) nl.add(s, map.remove(s));
+    this.type = type;
+    this.name = (String) m.get(NAME);
+    this.className = (String) m.get(CLASS_NAME);
+    this.initArgs = nl;
+    attributes = unmodifiableMap(m);
+    this.children =  Collections.<PluginInfo>emptyList();
+    isFromSolrConfig = true;
+  }
+
   private List<PluginInfo> loadSubPlugins(Node node) {
     List<PluginInfo> children = new ArrayList<>();
     //if there is another sub tag with a non namedlist tag that has to be another plugin
@@ -131,11 +148,11 @@ public class PluginInfo implements MapSe
   public static final PluginInfo EMPTY_INFO = new PluginInfo("",Collections.<String,String>emptyMap(), new NamedList(),Collections.<PluginInfo>emptyList());
 
   private static final HashSet<String> NL_TAGS = new HashSet<>
-    (Arrays.asList("lst", "arr",
-                   "bool",
-                   "str",
-                   "int","long",
-                   "float","double"));
+    (asList("lst", "arr",
+        "bool",
+        "str",
+        "int", "long",
+        "float", "double"));
   public static final String DEFAULTS = "defaults";
   public static final String APPENDS = "appends";
   public static final String INVARIANTS = "invariants";

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=1642141&r1=1642140&r2=1642141&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 Thu Nov 27 13:16:22 2014
@@ -143,12 +143,15 @@ public final class RequestHandlers {
     List<PluginInfo> implicits = PluginsRegistry.getHandlers(core);
     // use link map so we iterate in the same order
     Map<PluginInfo,SolrRequestHandler> handlers = new LinkedHashMap<>();
-    Map<String, PluginInfo> implicitInfoMap= new HashMap<>();
+    Map<String, PluginInfo> infoMap= new LinkedHashMap<>();
     //deduping implicit and explicit requesthandlers
-    for (PluginInfo info : implicits) implicitInfoMap.put(info.name,info);
+    for (PluginInfo info : implicits) infoMap.put(info.name,info);
     for (PluginInfo info : config.getPluginInfos(SolrRequestHandler.class.getName()))
-      if(implicitInfoMap.containsKey(info.name)) implicitInfoMap.remove(info.name);
-    ArrayList<PluginInfo> infos = new ArrayList<>(implicitInfoMap.values());
+      if(infoMap.containsKey(info.name)) infoMap.remove(info.name);
+    for (Map.Entry e : core.getSolrConfig().getOverlay().getReqHandlers().entrySet())
+      infoMap.put((String)e.getKey(), new PluginInfo(SolrRequestHandler.TYPE, (Map)e.getValue()));
+
+    ArrayList<PluginInfo> infos = new ArrayList<>(infoMap.values());
     infos.addAll(config.getPluginInfos(SolrRequestHandler.class.getName()));
     for (PluginInfo info : infos) {
       try {

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=1642141&r1=1642140&r2=1642141&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 Thu Nov 27 13:16:22 2014
@@ -334,13 +334,14 @@ public class SolrConfig extends Config i
       in = loader.openResource(ConfigOverlay.RESOURCE_NAME);
     } catch (IOException e) {
       //no problem no overlay.json file
-      return new ConfigOverlay(Collections.EMPTY_MAP,0);
+      return new ConfigOverlay(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("config overlay loaded . version : {} ", version);
       }
       Map m = (Map) ObjectBuilder.getVal(new JSONParser(new InputStreamReader(in, StandardCharsets.UTF_8)));
       return new ConfigOverlay(m,version);

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=1642141&r1=1642140&r2=1642141&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 Thu Nov 27 13:16:22 2014
@@ -51,6 +51,7 @@ import org.apache.solr.request.LocalSolr
 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.SchemaManager;
 import org.apache.solr.util.CommandOperation;
 import org.apache.solr.util.plugin.SolrCoreAware;
@@ -63,8 +64,10 @@ import static java.text.MessageFormat.fo
 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{
   public static final Logger log = LoggerFactory.getLogger(SolrConfigHandler.class);
@@ -106,7 +109,7 @@ public class SolrConfigHandler extends R
     return new Runnable() {
           @Override
           public void run() {
-            log.info("config update_listener called");
+            log.info("config update listener called for core {}", coreName);
             SolrZkClient zkClient = cc.getZkController().getZkClient();
             int solrConfigversion,overlayVersion;
             try (SolrCore core = cc.getCore(coreName))  {
@@ -117,7 +120,7 @@ public class SolrConfigHandler extends R
 
             if (checkStale(zkClient, overlayPath, solrConfigversion) ||
                 checkStale(zkClient, solrConfigPath, overlayVersion)) {
-              log.info("core reload");
+              log.info("core reload {}",coreName);
               cc.reload(coreName);
             }
           }
@@ -128,7 +131,7 @@ public class SolrConfigHandler extends R
     try {
       Stat stat = zkClient.exists(zkPath, null, true);
       if(stat == null){
-        if(currentVersion>0) return true;
+        if(currentVersion > -1) return true;
         return false;
       }
       if (stat.getVersion() >  currentVersion) {
@@ -198,7 +201,7 @@ public class SolrConfigHandler extends R
           for (CommandOperation op : ops) opsCopy.add(op.getCopy());
           try {
             handleCommands(opsCopy, overlay);
-            break;
+            break;//succeeded . so no need to go over the loop again
           } catch (ZkController.ResourceModifiedInZkException e) {
             //retry
             log.info("Race condition, the node is modified in ZK by someone else " +e.getMessage());
@@ -226,6 +229,13 @@ public class SolrConfigHandler extends R
         case UNSET_USER_PROPERTY:
           overlay = applyUnsetUserProp(op, overlay);
           break;
+        case UPDATE_REQHANDLER:
+        case CREATE_REQHANDLER:
+          overlay = applyRequestHandler(op, overlay);
+          break;
+        case DELETE_REQHANDLER:
+          overlay = applyDeleteHandler(op,overlay);
+          break;
       }
     }
     List errs = CommandOperation.captureErrors(ops);
@@ -246,6 +256,50 @@ public class SolrConfigHandler extends R
 
   }
 
+    private ConfigOverlay applyDeleteHandler(CommandOperation op, ConfigOverlay overlay) {
+      String name = op.getStr(CommandOperation.ROOT_OBJ);
+      if(op.hasError()) return overlay;
+      if(overlay.getReqHandlers().containsKey(name)){
+        return overlay.deleteHandler(name);
+      } else {
+        op.addError(MessageFormat.format("NO such requestHandler ''{0}'' ",name));
+        return overlay;
+      }
+
+    }
+
+    private ConfigOverlay applyRequestHandler(CommandOperation op, ConfigOverlay overlay) {
+      String name=op.getStr(NAME);
+      op.getStr(CLASS_NAME);
+      op.getMap(PluginInfo.DEFAULTS, null);
+      op.getMap(PluginInfo.INVARIANTS,null);
+      op.getMap(PluginInfo.APPENDS,null);
+      if(op.hasError()) return overlay;
+
+
+      if(CREATE_REQHANDLER.equals(op.name)) {
+        if (overlay.getReqHandlers().containsKey(name)) {
+          op.addError(MessageFormat.format(" ''{0}'' already exists . Do an ''{1}'' , if you want to change it ", name, UPDATE_REQHANDLER));
+          return overlay;
+        } else {
+          return overlay.addReqHandler(op.getDataMap());
+        }
+      } else if(UPDATE_REQHANDLER.equals(op.name)){
+        if (!overlay.getReqHandlers().containsKey(name)) {
+          op.addError(MessageFormat.format(" ''{0}'' does not exist . Do an ''{1}'' , if you want to create it ", name, CREATE_REQHANDLER));
+          return overlay;
+        } else {
+          return overlay.addReqHandler(op.getDataMap());
+
+        }
+      }
+
+      return overlay;
+
+
+
+    }
+
     private ConfigOverlay applySetUserProp(CommandOperation op, ConfigOverlay overlay) {
       Map<String, Object> m = op.getDataMap();
       if(op.hasError()) return overlay;
@@ -351,7 +405,8 @@ public class SolrConfigHandler extends R
   public static final String UNSET_PROPERTY = "unset-property";
   public static final String SET_USER_PROPERTY = "set-user-property";
   public static final String UNSET_USER_PROPERTY = "unset-user-property";
-
-
+  public static final String CREATE_REQHANDLER = "create-requesthandler";
+  public static final String DELETE_REQHANDLER = "delete-requesthandler";
+  public static final String UPDATE_REQHANDLER = "update-requesthandler";
 
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java?rev=1642141&r1=1642140&r2=1642141&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java Thu Nov 27 13:16:22 2014
@@ -214,4 +214,15 @@ public  class CommandOperation {
     return new CommandOperation(name,commandData);
   }
 
+  public Map getMap(String key, Map def) {
+    Object o =getMapVal(key);
+    if(o==null) return def;
+    if ( !(o instanceof Map)) {
+      addError(MessageFormat.format("''{0}'' must be a map", key));
+      return def;
+    } else {
+      return (Map) o;
+
+    }
+  }
 }

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=1642141&r1=1642140&r2=1642141&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 Thu Nov 27 13:16:22 2014
@@ -19,15 +19,25 @@ package org.apache.solr.core;
 
 
 import java.io.File;
+import java.io.IOException;
 import java.io.StringReader;
-import java.util.List;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 
 import com.google.common.collect.ImmutableList;
 import org.apache.commons.io.FileUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.util.EntityUtils;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.impl.CloudSolrServer;
+import org.apache.solr.client.solrj.impl.HttpSolrServer;
+import org.apache.solr.handler.TestSolrConfigHandlerConcurrent;
 import org.apache.solr.util.RestTestBase;
 import org.apache.solr.util.RestTestHarness;
 import org.eclipse.jetty.servlet.ServletHolder;
@@ -77,13 +87,11 @@ public class TestSolrConfigHandler exten
 
 
   public void testProperty() throws Exception{
+    RestTestHarness harness = restTestHarness;
     String payload= "{\n" +
         " 'set-property' : { 'updateHandler.autoCommit.maxDocs':100, 'updateHandler.autoCommit.maxTime':10 } \n" +
         " }";
-    RestTestHarness harness = restTestHarness;
-    String response = harness.post("/config?wt=json", SolrTestCaseJ4.json(payload));
-    Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
-    assertNull(response,  map.get("errors"));
+    runConfigCommand( harness,"/config?wt=json", payload);
 
     Map m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
     Map props = (Map) m.get("props");
@@ -99,9 +107,7 @@ public class TestSolrConfigHandler exten
     payload= "{\n" +
         " 'unset-property' :  'updateHandler.autoCommit.maxDocs'} \n" +
         " }";
-    response = harness.post("/config?wt=json", SolrTestCaseJ4.json(payload));
-    map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
-    assertNull(response,  map.get("errors"));
+    runConfigCommand(harness, "/config?wt=json", payload);
 
     m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
     props = (Map) m.get("props");
@@ -111,14 +117,12 @@ public class TestSolrConfigHandler exten
   }
 
   public void testUserProp() throws Exception{
+    RestTestHarness harness = restTestHarness;
     String payload= "{\n" +
         " 'set-user-property' : { 'my.custom.variable.a':'MODIFIEDA'," +
         " 'my.custom.variable.b':'MODIFIEDB' } \n" +
         " }";
-    RestTestHarness harness = restTestHarness;
-    String response = harness.post("/config?wt=json", SolrTestCaseJ4.json(payload));
-    Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
-    assertNull(response,  map.get("errors"));
+    runConfigCommand(harness,"/config?wt=json", payload);
 
     Map m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
     Map props = (Map) m.get("userProps");
@@ -132,14 +136,93 @@ public class TestSolrConfigHandler exten
     assertEquals("MODIFIEDA", m.get("a"));
     assertEquals("MODIFIEDB", m.get("b"));
 
+  }
 
+  public void testReqHandlerAPIs() throws Exception {
+    reqhandlertests(restTestHarness, null,null);
+  }
 
+  private static void runConfigCommand(RestTestHarness harness, String uri,  String payload) throws IOException {
+    String response = harness.post(uri, SolrTestCaseJ4.json(payload));
+    Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
+    assertNull(response,  map.get("errors"));
   }
 
 
+  public static void reqhandlertests(RestTestHarness writeHarness,String testServerBaseUrl, CloudSolrServer cloudSolrServer) throws Exception {
+    String payload = "{\n" +
+        "'create-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy'}\n" +
+        "}";
+    runConfigCommand(writeHarness,"/config?wt=json", payload);
+
+    boolean success = false;
+    long startTime = System.nanoTime();
+    long maxTimeoutSeconds = 10;
+    while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
+      String uri = "/config/overlay?wt=json";
+      Map m = testServerBaseUrl ==null?  getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
+      if("lazy".equals( ConfigOverlay.getObjectByPath(m,  true, Arrays.asList("overlay", "requestHandler", "/x","startup")))) {
+        Map map = getRespMap("/x?wt=json",writeHarness);
+        if(map.containsKey("params")) {
+          success = true;
+          break;
+        }
+      }
+      Thread.sleep(100);
+
+    }
+
+    assertTrue( "Could not register requestHandler  ", success);
+
+    payload = "{\n" +
+        "'update-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy' , 'a':'b'}\n" +
+        "}";
+    runConfigCommand(writeHarness,"/config?wt=json", payload);
+
+    success = false;
+    startTime = System.nanoTime();
+    maxTimeoutSeconds = 10;
+    while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
+      String uri = "/config/overlay?wt=json";
+      Map m = testServerBaseUrl ==null?  getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
+      if("b".equals( ConfigOverlay.getObjectByPath(m,  true, Arrays.asList("overlay", "requestHandler", "/x","a")))) {
+          success = true;
+          break;
+      }
+      Thread.sleep(100);
+
+    }
+
+    assertTrue( "Could not update requestHandler  ", success);
+
+    payload = "{\n" +
+        "'delete-requesthandler' : '/x'" +
+        "}";
+    runConfigCommand(writeHarness,"/config?wt=json", payload);
+    success = false;
+    startTime = System.nanoTime();
+    maxTimeoutSeconds = 10;
+    while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
+      String uri = "/config/overlay?wt=json";
+      Map m = testServerBaseUrl ==null?  getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
+      if(null == ConfigOverlay.getObjectByPath(m,  true, Arrays.asList("overlay", "requestHandler", "/x","a"))) {
+        success = true;
+        break;
+      }
+      Thread.sleep(100);
+
+    }
+    assertTrue( "Could not delete requestHandler  ", success);
+
+  }
+
 
   public static Map getRespMap(String path, RestTestHarness restHarness) throws Exception {
     String response = restHarness.query(path);
-    return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
+    try {
+      return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
+    } catch (JSONParser.ParseException e) {
+      return Collections.emptyMap();
+    }
   }
 }

Added: 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=1642141&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java Thu Nov 27 13:16:22 2014
@@ -0,0 +1,72 @@
+package org.apache.solr.handler;
+
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.impl.HttpSolrServer;
+import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
+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.TestSolrConfigHandler;
+import org.apache.solr.util.RESTfulServerProvider;
+import org.apache.solr.util.RestTestHarness;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestSolrConfigHandlerCloud extends AbstractFullDistribZkTestBase {
+  static final Logger log =  LoggerFactory.getLogger(TestSolrConfigHandlerCloud.class);
+  private List<RestTestHarness> restTestHarnesses = new ArrayList<>();
+
+  private void setupHarnesses() {
+    for (final SolrServer client : clients) {
+      RestTestHarness harness = new RestTestHarness(new RESTfulServerProvider() {
+        @Override
+        public String getBaseURL() {
+          return ((HttpSolrServer)client).getBaseURL();
+        }
+      });
+      restTestHarnesses.add(harness);
+    }
+  }
+
+  @Override
+  public void doTest() throws Exception {
+    setupHarnesses();
+    testReqHandlerAPIs();
+
+  }
+
+  private void testReqHandlerAPIs() 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 testServerBaseUrl = urls.get(random().nextInt(urls.size()));
+    TestSolrConfigHandler.reqhandlertests(writeHarness, testServerBaseUrl , cloudClient);
+  }
+}

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=1642141&r1=1642140&r2=1642141&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 Thu Nov 27 13:16:22 2014
@@ -33,6 +33,7 @@ import org.apache.http.client.methods.Ht
 import org.apache.http.util.EntityUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.impl.CloudSolrServer;
 import org.apache.solr.client.solrj.impl.HttpSolrServer;
 import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
 import org.apache.solr.common.cloud.DocCollection;
@@ -164,7 +165,7 @@ public class TestSolrConfigHandlerConcur
       while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
         Thread.sleep(100);
         errmessages.clear();
-        Map respMap = getAsMap(url+"/config/overlay?wt=json");
+        Map respMap = getAsMap(url+"/config/overlay?wt=json", cloudClient);
         Map m = (Map) respMap.get("overlay");
         if(m!= null) m = (Map) m.get("props");
         if(m == null) {
@@ -191,7 +192,7 @@ public class TestSolrConfigHandlerConcur
 
   }
 
-  private  Map getAsMap(String uri) throws Exception {
+  public static Map getAsMap(String uri, CloudSolrServer cloudClient) throws Exception {
     HttpGet get = new HttpGet(uri) ;
     HttpEntity entity = null;
     try {



Re: svn commit: r1642141 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/cloud/ core/src/java/org/apache/solr/core/ core/src/java/org/apache/solr/handler/ core/src/java/org/apache/solr/util/ core/src/test/org/apache/solr/core/ core/src/test/o...

Posted by Mark Miller <ma...@gmail.com>.
> On Nov 27, 2014, at 8:16 AM, noble@apache.org wrote:
> 
> SOLR-6607 Managing requesthandlers through API

You do see that you are the only one that doesn’t use a colon after the issue id right? As you were the only one that was just using the issue name only for a while?

Would you mind at least trying to be consistent with the rest of us?

- Mark
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org