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 2021/04/20 05:41:05 UTC

[lucene-solr] branch jira/solr15337 updated: solr15337 more tests pass

This is an automated email from the ASF dual-hosted git repository.

noble pushed a commit to branch jira/solr15337
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/jira/solr15337 by this push:
     new 1466034  solr15337 more tests pass
1466034 is described below

commit 1466034219f056c0bcd5588010ab92aed9e621f5
Author: Noble Paul <no...@gmail.com>
AuthorDate: Tue Apr 20 15:40:33 2021 +1000

    solr15337 more tests pass
---
 .../java/org/apache/solr/core/ConfigOverlay.java   |  17 +-
 .../src/java/org/apache/solr/core/SolrConfig.java  | 318 +++++++++++++--------
 .../apache/solr/handler/DumpRequestHandler.java    |   1 +
 .../java/org/apache/solr/schema/IndexSchema.java   |   2 +-
 .../java/org/apache/solr/util/DOMConfigNode.java   |   2 +-
 .../java/org/apache/solr/util/DataConfigNode.java  |  23 +-
 .../resources/EditableSolrConfigAttributes.json    |   4 -
 .../src/test/org/apache/solr/core/TestConfig.java  |   6 +-
 .../org/apache/solr/cluster/api/SimpleMap.java     |   9 +-
 .../java/org/apache/solr/common/ConfigNode.java    |  26 +-
 .../java/org/apache/solr/common/util/DOMUtil.java  |   4 +-
 .../solr/common/util/LinkedSimpleHashMap.java      |   6 +
 .../apache/solr/common/util/WrappedSimpleMap.java  |   6 +
 13 files changed, 265 insertions(+), 159 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java b/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
index 62cab00..0fa2bd7 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
@@ -22,8 +22,6 @@ import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.solr.common.MapSerializable;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.CoreAdminParams;
@@ -196,7 +194,12 @@ public class ConfigOverlay implements MapSerializable {
     Object obj = editable_prop_map;
     for (int i = 0; i < parts.size(); i++) {
       String part = parts.get(i);
-      boolean isAttr = isXpath && part.startsWith("@");
+      boolean isAttr = false;
+      try {
+        isAttr = isXpath && part.startsWith("@");
+      } catch (RuntimeException e) {
+        throw e;
+      }
       if (isAttr) {
         part = part.substring(1);
       }
@@ -259,6 +262,10 @@ public class ConfigOverlay implements MapSerializable {
     return Collections.unmodifiableMap(reqHandlers);
   }
 
+  boolean hasKey(String key) {
+    return props.containsKey(key);
+  }
+
 
   @SuppressWarnings({"unchecked", "rawtypes"})
   public ConfigOverlay addNamedPlugin(Map<String, Object> info, String typ) {
@@ -282,8 +289,4 @@ public class ConfigOverlay implements MapSerializable {
   public static final String ZNODEVER = "znodeVersion";
   public static final String NAME = "overlay";
 
-  public static void main(String[] args) {
-    System.out.println(Utils.toJSONString(editable_prop_map));
-  }
-
 }
diff --git a/solr/core/src/java/org/apache/solr/core/SolrConfig.java b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
index 6f1d84e..5937f9e 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
@@ -18,7 +18,6 @@ package org.apache.solr.core;
 
 
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathConstants;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -37,11 +36,13 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -54,6 +55,7 @@ import org.apache.lucene.util.Version;
 import org.apache.solr.client.solrj.io.stream.expr.Expressible;
 import org.apache.solr.cloud.RecoveryStrategy;
 import org.apache.solr.cloud.ZkSolrResourceLoader;
+import org.apache.solr.cluster.api.SimpleMap;
 import org.apache.solr.common.ConfigNode;
 import org.apache.solr.common.MapSerializable;
 import org.apache.solr.common.SolrException;
@@ -82,7 +84,6 @@ import org.apache.solr.update.processor.UpdateRequestProcessorChain;
 import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
 import org.apache.solr.util.DOMConfigNode;
 import org.apache.solr.util.DataConfigNode;
-import org.apache.solr.common.util.DOMUtil;
 import org.apache.solr.util.circuitbreaker.CircuitBreakerManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -190,158 +191,169 @@ public class SolrConfig implements MapSerializable {
       @SuppressWarnings("unchecked")
       Map<String, IndexSchemaFactory.VersionedConfig> configCache = (Map<String, IndexSchemaFactory.VersionedConfig>) loader.getCoreContainer().getZkController().getSolrCloudManager().getObjectCache()
           .computeIfAbsent(ConfigSetService.ConfigResource.class.getName(), s -> new ConcurrentHashMap<>());
-      if(overlay.getZnodeVersion()  == -1) {
+
         //currently not optimized for this
         IndexSchemaFactory.VersionedConfig cfg = configCache.get(name);
-        if(cfg != null){
+        if(cfg != null) {
           InputStream in = loader.openResource(name);
           if (in instanceof ZkSolrResourceLoader.ZkByteArrayInputStream) {
             int zkVersion = ((ZkSolrResourceLoader.ZkByteArrayInputStream) in).getStat().getVersion();
-            if(cfg.version == zkVersion) {
+            int overlayVersion = overlay.getZnodeVersion();
+            int hashcode = Objects.hash(zkVersion, overlayVersion);
+            if(cfg.version == hashcode) {
               root = cfg.data;
             } else {
               configCache.remove(name);
               readXml(loader, name);
-              configCache.put(name, new IndexSchemaFactory.VersionedConfig(this.znodeVersion, root));
+              configCache.put(name, new IndexSchemaFactory.VersionedConfig(hashcode, root));
             }
           }
         }
-
-      }
     }
     if(root == null) {
       readXml(loader, name);
     }
-
+    ConfigNode.SUBSTITUTES.set(key -> {
+      if(substitutableProperties== null || !substitutableProperties.containsKey(key)) {
+        Object o = overlay.getUserProps().get(key);
+        return o ==null? null: o.toString();
+      } else {
+        return substitutableProperties.getProperty(key);
+      }
+    });
+    try {
 //    xml = new XmlConfigFile(loader, name, null, "/config/", substitutableProperties == null ? new Properties() : substitutableProperties );
 //    root = new DataConfigNode(new DOMConfigNode(xml.getDocument().getDocumentElement()));
 //    super(loader, name, null, "/config/", substitutableProperties == null ? new Properties() : substitutableProperties);
-    getRequestParams();
-    initLibs(loader, isConfigsetTrusted);
-    String val =  root.child(IndexSchema.LUCENE_MATCH_VERSION_PARAM,
-        () -> new RuntimeException("Missing: "+ IndexSchema.LUCENE_MATCH_VERSION_PARAM)) .textValue() ;
-
-    luceneMatchVersion = SolrConfig.parseLuceneVersionString(val);
-    log.info("Using Lucene MatchVersion: {}", luceneMatchVersion);
-
-    String indexConfigPrefix;
-
-    // Old indexDefaults and mainIndex sections are deprecated and fails fast for luceneMatchVersion=>LUCENE_4_0_0.
-    // For older solrconfig.xml's we allow the old sections, but never mixed with the new <indexConfig>
-    boolean hasDeprecatedIndexConfig = __("indexDefaults").exists() || __("mainIndex").exists();
-    if (hasDeprecatedIndexConfig) {
-      throw new SolrException(ErrorCode.FORBIDDEN, "<indexDefaults> and <mainIndex> configuration sections are discontinued. Use <indexConfig> instead.");
-    } else {
-      indexConfigPrefix = "indexConfig";
-    }
-    assertWarnOrFail("The <nrtMode> config has been discontinued and NRT mode is always used by Solr." +
-            " This config will be removed in future versions.", !__("indexDefaults").__("nrtMode").exists(),
-        true
-    );
-    assertWarnOrFail("Solr no longer supports forceful unlocking via the 'unlockOnStartup' option.  "+
-                     "This is no longer necessary for the default lockType except in situations where "+
-                     "it would be dangerous and should not be done.  For other lockTypes and/or "+
-                     "directoryFactory options it may also be dangerous and users must resolve "+
-                     "problematic locks manually.",
-                     !__(indexConfigPrefix).__( "unlockOnStartup").exists(),
-                     true // 'fail' in trunk
-                     );
-                     
-    // Parse indexConfig section, using mainIndex as backup in case old config is used
-    indexConfig = new SolrIndexConfig (__("indexConfig"), null);
-
-    booleanQueryMaxClauseCount = __("query").__("maxBooleanClauses")._int(BooleanQuery.getMaxClauseCount());
-    if (BooleanQuery.getMaxClauseCount() < booleanQueryMaxClauseCount) {
-      log.warn("solrconfig.xml: <maxBooleanClauses> of {} is greater than global limit of {} and will have no effect {}"
-          , booleanQueryMaxClauseCount, BooleanQuery.getMaxClauseCount()
-          , "set 'maxBooleanClauses' in solr.xml to increase global limit");
-    }
-    
-    // Warn about deprecated / discontinued parameters
-    // boolToFilterOptimizer has had no effect since 3.1
-    if (__("query").__("boolTofilterOptimizer").exists())
-      log.warn("solrconfig.xml: <boolTofilterOptimizer> is currently not implemented and has no effect.");
-    if (__("query").__("HashDocSet").exists())
-      log.warn("solrconfig.xml: <HashDocSet> is deprecated and no longer used.");
+      getRequestParams();
+      initLibs(loader, isConfigsetTrusted);
+      String val = root.child(IndexSchema.LUCENE_MATCH_VERSION_PARAM,
+          () -> new RuntimeException("Missing: " + IndexSchema.LUCENE_MATCH_VERSION_PARAM)).txt();
+
+      luceneMatchVersion = SolrConfig.parseLuceneVersionString(val);
+      log.info("Using Lucene MatchVersion: {}", luceneMatchVersion);
+
+      String indexConfigPrefix;
+
+      // Old indexDefaults and mainIndex sections are deprecated and fails fast for luceneMatchVersion=>LUCENE_4_0_0.
+      // For older solrconfig.xml's we allow the old sections, but never mixed with the new <indexConfig>
+      boolean hasDeprecatedIndexConfig = __("indexDefaults").exists() || __("mainIndex").exists();
+      if (hasDeprecatedIndexConfig) {
+        throw new SolrException(ErrorCode.FORBIDDEN, "<indexDefaults> and <mainIndex> configuration sections are discontinued. Use <indexConfig> instead.");
+      } else {
+        indexConfigPrefix = "indexConfig";
+      }
+      assertWarnOrFail("The <nrtMode> config has been discontinued and NRT mode is always used by Solr." +
+              " This config will be removed in future versions.", !__("indexDefaults").__("nrtMode").exists(),
+          true
+      );
+      assertWarnOrFail("Solr no longer supports forceful unlocking via the 'unlockOnStartup' option.  " +
+              "This is no longer necessary for the default lockType except in situations where " +
+              "it would be dangerous and should not be done.  For other lockTypes and/or " +
+              "directoryFactory options it may also be dangerous and users must resolve " +
+              "problematic locks manually.",
+          !__(indexConfigPrefix).__("unlockOnStartup").exists(),
+          true // 'fail' in trunk
+      );
+
+      // Parse indexConfig section, using mainIndex as backup in case old config is used
+      indexConfig = new SolrIndexConfig(__("indexConfig"), null);
+
+      booleanQueryMaxClauseCount = __("query").__("maxBooleanClauses")._int(BooleanQuery.getMaxClauseCount());
+      if (BooleanQuery.getMaxClauseCount() < booleanQueryMaxClauseCount) {
+        log.warn("solrconfig.xml: <maxBooleanClauses> of {} is greater than global limit of {} and will have no effect {}"
+            , booleanQueryMaxClauseCount, BooleanQuery.getMaxClauseCount()
+            , "set 'maxBooleanClauses' in solr.xml to increase global limit");
+      }
+
+      // Warn about deprecated / discontinued parameters
+      // boolToFilterOptimizer has had no effect since 3.1
+      if (__("query").__("boolTofilterOptimizer").exists())
+        log.warn("solrconfig.xml: <boolTofilterOptimizer> is currently not implemented and has no effect.");
+      if (__("query").__("HashDocSet").exists())
+        log.warn("solrconfig.xml: <HashDocSet> is deprecated and no longer used.");
 
 // TODO: Old code - in case somebody wants to re-enable. Also see SolrIndexSearcher#search()
 //    filtOptEnabled = getBool("query/boolTofilterOptimizer/@enabled", false);
 //    filtOptCacheSize = getInt("query/boolTofilterOptimizer/@cacheSize",32);
 //    filtOptThreshold = getFloat("query/boolTofilterOptimizer/@threshold",.05f);
 
-    useFilterForSortedQuery = __("query").__("useFilterForSortedQuery")._bool(false);
-    queryResultWindowSize = Math.max(1, __("query").__("queryResultWindowSize")._int(1));
-    queryResultMaxDocsCached = __("query").__("queryResultMaxDocsCached")._int(Integer.MAX_VALUE);
-    enableLazyFieldLoading = __("query").__("enableLazyFieldLoading")._bool(false);
-    
-    filterCacheConfig = CacheConfig.getConfig(this, __("query").__("filterCache"), "query/filterCache");
-    queryResultCacheConfig = CacheConfig.getConfig(this, __("query").__("queryResultCache"), "query/queryResultCache");
-    documentCacheConfig = CacheConfig.getConfig(this, __("query").__("documentCache"), "query/documentCache");
-    CacheConfig conf = CacheConfig.getConfig(this, __("query").__("fieldValueCache"), "query/fieldValueCache");
-    if (conf == null) {
-      Map<String, String> args = new HashMap<>();
-      args.put(NAME, "fieldValueCache");
-      args.put("size", "10000");
-      args.put("initialSize", "10");
-      args.put("showItems", "-1");
-      conf = new CacheConfig(FastLRUCache.class, args, null);
-    }
-    fieldValueCacheConfig = conf;
-    useColdSearcher = __("query").__("useColdSearcher")._bool(false);
-    dataDir = __("dataDir").txt();
-    if (dataDir != null && dataDir.length() == 0) dataDir = null;
+      useFilterForSortedQuery = __("query").__("useFilterForSortedQuery")._bool(false);
+      queryResultWindowSize = Math.max(1, __("query").__("queryResultWindowSize")._int(1));
+      queryResultMaxDocsCached = __("query").__("queryResultMaxDocsCached")._int(Integer.MAX_VALUE);
+      enableLazyFieldLoading = __("query").__("enableLazyFieldLoading")._bool(false);
+
+      filterCacheConfig = CacheConfig.getConfig(this, __("query").__("filterCache"), "query/filterCache");
+      queryResultCacheConfig = CacheConfig.getConfig(this, __("query").__("queryResultCache"), "query/queryResultCache");
+      documentCacheConfig = CacheConfig.getConfig(this, __("query").__("documentCache"), "query/documentCache");
+      CacheConfig conf = CacheConfig.getConfig(this, __("query").__("fieldValueCache"), "query/fieldValueCache");
+      if (conf == null) {
+        Map<String, String> args = new HashMap<>();
+        args.put(NAME, "fieldValueCache");
+        args.put("size", "10000");
+        args.put("initialSize", "10");
+        args.put("showItems", "-1");
+        conf = new CacheConfig(FastLRUCache.class, args, null);
+      }
+      fieldValueCacheConfig = conf;
+      useColdSearcher = __("query").__("useColdSearcher")._bool(false);
+      dataDir = __("dataDir").txt();
+      if (dataDir != null && dataDir.length() == 0) dataDir = null;
 
 
-    org.apache.solr.search.SolrIndexSearcher.initRegenerators(this);
+      org.apache.solr.search.SolrIndexSearcher.initRegenerators(this);
 
-    if (__("jmx").exists()) {
-      log.warn("solrconfig.xml: <jmx> is no longer supported, use solr.xml:/metrics/reporter section instead");
-    }
+      if (__("jmx").exists()) {
+        log.warn("solrconfig.xml: <jmx> is no longer supported, use solr.xml:/metrics/reporter section instead");
+      }
 
-    httpCachingConfig = new HttpCachingConfig(this);
+      httpCachingConfig = new HttpCachingConfig(this);
 
-    maxWarmingSearchers = __("query").__("maxWarmingSearchers")._int(1);
-    slowQueryThresholdMillis = __("query").__("slowQueryThresholdMillis")._int(-1);
-    for (SolrPluginInfo plugin : plugins) loadPluginInfo(plugin);
+      maxWarmingSearchers = __("query").__("maxWarmingSearchers")._int(1);
+      slowQueryThresholdMillis = __("query").__("slowQueryThresholdMillis")._int(-1);
+      for (SolrPluginInfo plugin : plugins) loadPluginInfo(plugin);
 
-    Map<String, CacheConfig> userCacheConfigs = CacheConfig.getMultipleConfigs(this, "query/cache",
-        __("query").children("cache"));
-    List<PluginInfo> caches = getPluginInfos(SolrCache.class.getName());
-    if (!caches.isEmpty()) {
-      for (PluginInfo c : caches) {
-        userCacheConfigs.put(c.name, CacheConfig.getConfig(this, "cache", c.attributes, null));
+      Map<String, CacheConfig> userCacheConfigs = CacheConfig.getMultipleConfigs(this, "query/cache",
+          __("query").children("cache"));
+      List<PluginInfo> caches = getPluginInfos(SolrCache.class.getName());
+      if (!caches.isEmpty()) {
+        for (PluginInfo c : caches) {
+          userCacheConfigs.put(c.name, CacheConfig.getConfig(this, "cache", c.attributes, null));
+        }
       }
-    }
-    this.userCacheConfigs = Collections.unmodifiableMap(userCacheConfigs);
+      this.userCacheConfigs = Collections.unmodifiableMap(userCacheConfigs);
 
-    updateHandlerInfo = loadUpdatehandlerInfo();
+      updateHandlerInfo = loadUpdatehandlerInfo();
 
-    multipartUploadLimitKB = __("requestDispatcher").__("requestParsers").intAttr("multipartUploadLimitInKB", Integer.MAX_VALUE);
-    if (multipartUploadLimitKB == -1) multipartUploadLimitKB = Integer.MAX_VALUE;
+      multipartUploadLimitKB = __("requestDispatcher").__("requestParsers").intAttr("multipartUploadLimitInKB", Integer.MAX_VALUE);
+      if (multipartUploadLimitKB == -1) multipartUploadLimitKB = Integer.MAX_VALUE;
 
-    formUploadLimitKB = __("requestDispatcher").__("requestParsers").intAttr("formdataUploadLimitInKB", Integer.MAX_VALUE);
-    if (formUploadLimitKB == -1) formUploadLimitKB = Integer.MAX_VALUE;
+      formUploadLimitKB = __("requestDispatcher").__("requestParsers").intAttr("formdataUploadLimitInKB", Integer.MAX_VALUE);
+      if (formUploadLimitKB == -1) formUploadLimitKB = Integer.MAX_VALUE;
 
-    enableRemoteStreams = __("requestDispatcher").__("requestParsers").boolAttr("enableRemoteStreaming", false);
+      enableRemoteStreams = __("requestDispatcher").__("requestParsers").boolAttr("enableRemoteStreaming", false);
 
-    enableStreamBody = __("requestDispatcher").__("requestParsers").boolAttr("enableStreamBody", false);
+      enableStreamBody = __("requestDispatcher").__("requestParsers").boolAttr("enableStreamBody", false);
 
-    handleSelect = __("requestDispatcher").boolAttr("handleSelect", !luceneMatchVersion.onOrAfter(Version.LUCENE_7_0_0)) ;
-    addHttpRequestToContext = __("requestDispatcher").__("requestParsers").boolAttr("addHttpRequestToContext", false);
+      handleSelect = __("requestDispatcher").boolAttr("handleSelect", !luceneMatchVersion.onOrAfter(Version.LUCENE_7_0_0));
+      addHttpRequestToContext = __("requestDispatcher").__("requestParsers").boolAttr("addHttpRequestToContext", false);
+
+      List<PluginInfo> argsInfos = getPluginInfos(InitParams.class.getName());
+      if (argsInfos != null) {
+        Map<String, InitParams> argsMap = new HashMap<>();
+        for (PluginInfo p : argsInfos) {
+          InitParams args = new InitParams(p);
+          argsMap.put(args.name == null ? String.valueOf(args.hashCode()) : args.name, args);
+        }
+        this.initParams = Collections.unmodifiableMap(argsMap);
 
-    List<PluginInfo> argsInfos = getPluginInfos(InitParams.class.getName());
-    if (argsInfos != null) {
-      Map<String, InitParams> argsMap = new HashMap<>();
-      for (PluginInfo p : argsInfos) {
-        InitParams args = new InitParams(p);
-        argsMap.put(args.name == null ? String.valueOf(args.hashCode()) : args.name, args);
       }
-      this.initParams = Collections.unmodifiableMap(argsMap);
 
+      solrRequestParsers = new SolrRequestParsers(this);
+      log.debug("Loaded SolrConfig: {}", name);
+    } finally {
+      ConfigNode.SUBSTITUTES.remove();
     }
-
-    solrRequestParsers = new SolrRequestParsers(this);
-    log.debug("Loaded SolrConfig: {}", name);
   }
 
   private void readXml(SolrResourceLoader loader, String name) throws ParserConfigurationException, IOException, SAXException {
@@ -1004,6 +1016,7 @@ public class SolrConfig implements MapSerializable {
     if (o == null || PackageLoader.LATEST.equals(o)) return null;
     return o.toString();
   }
+
   public RequestParams refreshRequestParams() {
     requestParams = RequestParams.getFreshRequestParams(resourceLoader, requestParams);
     if (log.isDebugEnabled()) {
@@ -1034,12 +1047,91 @@ public class SolrConfig implements MapSerializable {
    *
    */
   public ConfigNode __(String name) {
-    return root.__(name);
+    if (!overlay.hasKey(name)) {
+      //there is no overlay
+      return root.__(name);
+    }
+    return new OverlaidConfigNode(name, null,root.__(name));
   }
 
   public ConfigNode __(String name, Predicate<ConfigNode> test) {
     return root.__(name, test);
   }
+   private class OverlaidConfigNode implements ConfigNode {
+
+    private final String _name;
+    private final ConfigNode delegate;
+    private final OverlaidConfigNode parent;
+
+     private OverlaidConfigNode(String name, OverlaidConfigNode parent, ConfigNode delegate) {
+       this._name = name;
+       this.delegate = delegate;
+       this.parent = parent;
+     }
+
+     private List<String> path(List<String> path) {
+       if(path== null) path = new ArrayList<>(5);
+       try {
+         if (parent != null) return parent.path(path);
+       } finally {
+         path.add(_name);
+       }
+       return path;
+     }
+
+     @Override
+    public ConfigNode __(String name) {
+      return wrap(delegate.__(name), name);
+    }
+
+    private ConfigNode wrap(ConfigNode n, String name) {
+      return new OverlaidConfigNode(name,this, n);
+    }
 
+    @Override
+    public ConfigNode __(String name, Predicate<ConfigNode> test) {
+      return wrap(delegate.__(name, test), name);
+    }
 
+     @Override
+     public String txt() {
+       return overlayText(delegate.txt(), null);
+     }
+
+     @Override
+    public ConfigNode __(String name, int idx) {
+      return wrap(delegate.__(name, idx), name);
+    }
+
+    @Override
+    public String name() {
+      return delegate.name();
+    }
+    @Override
+    public SimpleMap<String> attributes() {
+      return delegate.attributes();
+    }
+
+     @Override
+     public boolean exists() {
+       return delegate.exists();
+     }
+
+     @Override
+     public String attr(String name) {
+       return overlayText(delegate.attr(name),name);
+     }
+
+     private String overlayText(String def, String appendToPath) {
+       List<String> path = path(null);
+       if(appendToPath !=null) path.add(appendToPath);
+       Object val = overlay.getXPathProperty(path);
+       return val ==null? def: val.toString();
+     }
+
+     @Override
+    public void forEachChild(Function<ConfigNode, Boolean> fun) {
+       delegate.forEachChild(fun);
+    }
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
index 4ce5fa5..c99ca79 100644
--- a/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
@@ -36,6 +36,7 @@ import static org.apache.solr.common.params.CommonParams.NAME;
 
 public class DumpRequestHandler extends RequestHandlerBase
 {
+
   @Override
   @SuppressWarnings({"unchecked"})
   public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException
diff --git a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
index 918b878..564158b 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -565,7 +565,7 @@ public class IndexSchema {
       if (node==null) {
         log.warn("no {} specified in schema.", UNIQUE_KEY);
       } else {
-        uniqueKeyField=getIndexedField(node.textValue().trim());
+        uniqueKeyField=getIndexedField(node.txt().trim());
         uniqueKeyFieldName=uniqueKeyField.getName();
         uniqueKeyFieldType=uniqueKeyField.getType();
 
diff --git a/solr/core/src/java/org/apache/solr/util/DOMConfigNode.java b/solr/core/src/java/org/apache/solr/util/DOMConfigNode.java
index 6afc5a5..944c9ed 100644
--- a/solr/core/src/java/org/apache/solr/util/DOMConfigNode.java
+++ b/solr/core/src/java/org/apache/solr/util/DOMConfigNode.java
@@ -43,7 +43,7 @@ public class DOMConfigNode implements ConfigNode {
   }
 
   @Override
-  public String textValue() {
+  public String txt() {
     return DOMUtil.getText(node);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/util/DataConfigNode.java b/solr/core/src/java/org/apache/solr/util/DataConfigNode.java
index f059c2d..b1e37fa 100644
--- a/solr/core/src/java/org/apache/solr/util/DataConfigNode.java
+++ b/solr/core/src/java/org/apache/solr/util/DataConfigNode.java
@@ -30,20 +30,23 @@ import java.util.function.Predicate;
 import org.apache.solr.cluster.api.SimpleMap;
 import org.apache.solr.common.ConfigNode;
 import org.apache.solr.common.util.PropertiesUtil;
+import org.apache.solr.common.util.WrappedSimpleMap;
 
 /**
  * ConfigNode impl that copies and maintains data internally from DOM
  */
 public class DataConfigNode implements ConfigNode {
-  final String name;
-  final SimpleMap<String> attributes;
-  private final Map<String, List<ConfigNode>> kids = new HashMap<>();
-  private final String textData;
+  public final String name;
+  public final SimpleMap<String> attributes;
+  public final SimpleMap<List<ConfigNode>> kids ;
+  public final String textData;
+
 
   public DataConfigNode(ConfigNode root) {
+    Map<String, List<ConfigNode>> kids = new HashMap<>();
     name = root.name();
     attributes = wrap(root.attributes());
-    textData = root.textValue();
+    textData = root.txt();
     root.forEachChild(it -> {
       List<ConfigNode> nodes = kids.computeIfAbsent(it.name(),
           k -> new ArrayList<>());
@@ -56,7 +59,7 @@ public class DataConfigNode implements ConfigNode {
         e.setValue(Collections.unmodifiableList(e.getValue()));
       }
     }
-
+    this.kids = new WrappedSimpleMap<>(kids);
   }
 
   public String subtituteVal(String s) {
@@ -88,8 +91,8 @@ public class DataConfigNode implements ConfigNode {
   }
 
   @Override
-  public String textValue() {
-    return  subtituteVal(textData);
+  public String txt() {
+    return subtituteVal(textData);
   }
 
   @Override
@@ -105,7 +108,7 @@ public class DataConfigNode implements ConfigNode {
 
   @Override
   public List<ConfigNode> children(String name) {
-    return kids.getOrDefault(name, Collections.emptyList());
+    return kids.get(name, Collections.emptyList());
   }
 
   @Override
@@ -126,7 +129,7 @@ public class DataConfigNode implements ConfigNode {
 
   @Override
   public void forEachChild(Function<ConfigNode, Boolean> fun) {
-    kids.forEach((s, configNodes) -> {
+    kids.forEachEntry((s, configNodes) -> {
       if (configNodes != null) {
         configNodes.forEach(fun::apply);
       }
diff --git a/solr/core/src/resources/EditableSolrConfigAttributes.json b/solr/core/src/resources/EditableSolrConfigAttributes.json
index 03bb1b6..fe06fa0 100644
--- a/solr/core/src/resources/EditableSolrConfigAttributes.json
+++ b/solr/core/src/resources/EditableSolrConfigAttributes.json
@@ -56,10 +56,6 @@
     "enableLazyFieldLoading":1,
     "boolTofilterOptimizer":1,
     "maxBooleanClauses":1},
-  "jmx":{
-    "agentId":0,
-    "serviceUrl":0,
-    "rootName":0},
   "requestDispatcher":{
     "handleSelect":0,
     "requestParsers":{
diff --git a/solr/core/src/test/org/apache/solr/core/TestConfig.java b/solr/core/src/test/org/apache/solr/core/TestConfig.java
index 00c01a1..955be18 100644
--- a/solr/core/src/test/org/apache/solr/core/TestConfig.java
+++ b/solr/core/src/test/org/apache/solr/core/TestConfig.java
@@ -79,7 +79,7 @@ public class TestConfig extends SolrTestCaseJ4 {
   public void testJavaProperty() {
     // property values defined in build.xml
 
-    String s = solrConfig.__("propTest").textValue();
+    String s = solrConfig.__("propTest").txt();
     assertEquals("prefix-proptwo-suffix", s);
 
     s = solrConfig.__("propTest").attr("attr1", "default");
@@ -94,9 +94,9 @@ public class TestConfig extends SolrTestCaseJ4 {
 
     List<ConfigNode> nl = solrConfig.root.children ("propTest");
     assertEquals(1, nl.size());
-    assertEquals("prefix-proptwo-suffix", nl.get(0).textValue());
+    assertEquals("prefix-proptwo-suffix", nl.get(0).txt());
 
-    assertEquals("prefix-proptwo-suffix", solrConfig.__("propTest"));
+    assertEquals("prefix-proptwo-suffix", solrConfig.__("propTest").txt());
   }
 
   // sometime if the config referes to old things, it must be replaced with new stuff
diff --git a/solr/solrj/src/java/org/apache/solr/cluster/api/SimpleMap.java b/solr/solrj/src/java/org/apache/solr/cluster/api/SimpleMap.java
index cd9a372..885b11d 100644
--- a/solr/solrj/src/java/org/apache/solr/cluster/api/SimpleMap.java
+++ b/solr/solrj/src/java/org/apache/solr/cluster/api/SimpleMap.java
@@ -85,9 +85,12 @@ public interface SimpleMap<T> extends MapWriter {
     forEachEntry(ew::putNoEx);
   }
 
+  default Map<String, T> asMap( Map<String, T> sink) {
+    forEachEntry(sink::put);
+    return sink;
+  }
+
   default Map<String, T> asMap() {
-    Map<String, T> result = new LinkedHashMap<>();
-    forEachEntry((k, v) -> result.put(k, v));
-    return result;
+    return asMap(new LinkedHashMap<String, T>());
   }
 }
diff --git a/solr/solrj/src/java/org/apache/solr/common/ConfigNode.java b/solr/solrj/src/java/org/apache/solr/common/ConfigNode.java
index adbe914..8b887d4 100644
--- a/solr/solrj/src/java/org/apache/solr/common/ConfigNode.java
+++ b/solr/solrj/src/java/org/apache/solr/common/ConfigNode.java
@@ -43,11 +43,6 @@ public interface ConfigNode {
   String name();
 
   /**
-   * Text value of the node
-   */
-  String textValue();
-
-  /**
    * Attributes
    */
   SimpleMap<String> attributes();
@@ -95,19 +90,20 @@ public interface ConfigNode {
     return n;
   }
 
-  default boolean _bool(boolean def) { return __bool(textValue(),def); }
-  default int _int(int def) { return __int(textValue(), def); }
+  default boolean _bool(boolean def) { return __bool(txt(),def); }
+  default int _int(int def) { return __int(txt(), def); }
   default String attr(String name, String def) { return __txt(attributes().get(name), def);}
   default String attr(String name) { return attributes().get(name);}
   default String requiredStrAttr(String name, Supplier<RuntimeException> err) {
-    if(attributes().get(name) == null && err != null) throw err.get();
-    return attributes().get(name);
+    String attr = attr(name);
+    if(attr == null && err != null) throw err.get();
+    return attr;
   }
-  default int intAttr(String name, int def) { return __int(attributes().get(name), def); }
-  default boolean boolAttr(String name, boolean def){ return __bool(attributes().get(name), def); }
-  default String txt(String def) { return textValue() == null ? def : textValue();}
-  default String txt() { return textValue();}
-  default double doubleVal(double def){ return __double(textValue(), def); }
+  default int intAttr(String name, int def) { return __int(attr(name), def); }
+  default boolean boolAttr(String name, boolean def){ return __bool(attr(name), def); }
+  default String txt(String def) { return txt() == null ? def : txt();}
+  String txt() ;
+  default double doubleVal(double def){ return __double(txt(), def); }
   /**Iterate through child nodes with the name and return the first child that matches
    */
   default ConfigNode child(Predicate<ConfigNode> test, String name) {
@@ -169,7 +165,7 @@ public interface ConfigNode {
     }
 
     @Override
-    public String textValue() { return null; }
+    public String txt() { return null; }
 
     @Override
     public SimpleMap<String> attributes() {
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/DOMUtil.java b/solr/solrj/src/java/org/apache/solr/common/util/DOMUtil.java
index a2714d4..24f41b4 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/DOMUtil.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/DOMUtil.java
@@ -233,7 +233,7 @@ public class DOMUtil {
       String tag = it.name();
       String varName = it.attributes().get("name");
       if (NL_TAGS.contains(tag)) {
-        result.add(varName, parseVal(tag, varName, it.textValue()));
+        result.add(varName, parseVal(tag, varName, it.txt()));
       }
       if ("lst".equals(tag)) {
         result.add(varName, readNamedListChildren(it));
@@ -242,7 +242,7 @@ public class DOMUtil {
         result.add(varName, l);
         it.forEachChild(n -> {
           if (NL_TAGS.contains(n.name())) {
-            l.add(parseVal(n.name(), null, n.textValue()));
+            l.add(parseVal(n.name(), null, n.txt()));
           }
           return Boolean.TRUE;
         });
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/LinkedSimpleHashMap.java b/solr/solrj/src/java/org/apache/solr/common/util/LinkedSimpleHashMap.java
index 1fc6afc..6581c83 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/LinkedSimpleHashMap.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/LinkedSimpleHashMap.java
@@ -19,6 +19,7 @@ package org.apache.solr.common.util;
 import org.apache.solr.cluster.api.SimpleMap;
 
 import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.function.BiConsumer;
 
 public class LinkedSimpleHashMap<T> extends LinkedHashMap<String, T>  implements SimpleMap<T> {
@@ -31,4 +32,9 @@ public class LinkedSimpleHashMap<T> extends LinkedHashMap<String, T>  implements
     public void forEachEntry(BiConsumer<String, ? super T> fun) {
 
     }
+
+    @Override
+    public Map<String, T> asMap() {
+        return this;
+    }
 }
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/WrappedSimpleMap.java b/solr/solrj/src/java/org/apache/solr/common/util/WrappedSimpleMap.java
index e8689d2..ccf000b 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/WrappedSimpleMap.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/WrappedSimpleMap.java
@@ -47,6 +47,12 @@ public class WrappedSimpleMap<T>  implements SimpleMap<T> {
         this.delegate = delegate;
     }
 
+  @Override
+  public Map<String, T> asMap(Map<String, T> sink) {
+    sink.putAll(delegate);
+    return sink;
+  }
+
     @Override
     public Map<String, T> asMap() {
         return Collections.unmodifiableMap(delegate);