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/19 00:20:07 UTC
[lucene-solr] 01/01: solr15337 untested
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
commit 1ee3629621345df206363c1ce2615445f000d508
Author: Noble Paul <no...@gmail.com>
AuthorDate: Mon Apr 19 10:19:34 2021 +1000
solr15337 untested
---
.../java/org/apache/solr/core/ConfigOverlay.java | 14 +-
.../src/java/org/apache/solr/core/PluginInfo.java | 24 ++
.../src/java/org/apache/solr/core/SolrConfig.java | 262 +++++++++++++--------
.../java/org/apache/solr/schema/IndexSchema.java | 4 +-
.../org/apache/solr/schema/IndexSchemaFactory.java | 4 +-
.../java/org/apache/solr/search/CacheConfig.java | 46 ++--
.../org/apache/solr/update/SolrIndexConfig.java | 83 +++----
.../java/org/apache/solr/update/VersionInfo.java | 4 +-
.../java/org/apache/solr/util/DataConfigNode.java | 4 +-
.../org/apache/solr/core/TestCodecSupport.java | 6 +-
.../src/test/org/apache/solr/core/TestConfig.java | 25 +-
.../org/apache/solr/core/TestSimpleTextCodec.java | 2 +-
.../handler/component/SuggestComponentTest.java | 127 +++++++---
.../apache/solr/update/SolrIndexConfigTest.java | 12 +-
.../org/apache/solr/cluster/api/SimpleMap.java | 8 +
.../java/org/apache/solr/common/ConfigNode.java | 120 ++++++++++
.../apache/solr/common/util/WrappedSimpleMap.java | 5 +
17 files changed, 512 insertions(+), 238 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 1bc8824..62cab00 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
@@ -16,12 +16,14 @@
*/
package org.apache.solr.core;
+import java.util.ArrayList;
import java.util.Collections;
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;
@@ -62,6 +64,12 @@ public class ConfigOverlay implements MapSerializable {
return Utils.getObjectByPath(props, onlyPrimitive, hierarchy);
}
+ public Object getXPathProperty(List<String> path) {
+ List<String> hierarchy = new ArrayList<>();
+ if(isEditable(true, hierarchy, path) == null) return null;
+ return Utils.getObjectByPath(props, true, hierarchy);
+ }
+
@SuppressWarnings({"unchecked"})
public ConfigOverlay setUserProperty(String key, Object val) {
@SuppressWarnings({"rawtypes"})
@@ -180,7 +188,11 @@ public class ConfigOverlay implements MapSerializable {
@SuppressWarnings({"rawtypes"})
public static Class checkEditable(String path, boolean isXpath, List<String> hierarchy) {
- List<String> parts = StrUtils.splitSmart(path, isXpath ? '/' : '.');
+ return isEditable(isXpath, hierarchy, StrUtils.splitSmart(path, isXpath ? '/' : '.'));
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static Class isEditable(boolean isXpath, List<String> hierarchy, List<String> parts) {
Object obj = editable_prop_map;
for (int i = 0; i < parts.size(); i++) {
String part = parts.get(i);
diff --git a/solr/core/src/java/org/apache/solr/core/PluginInfo.java b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
index 011d933..2dcab89 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginInfo.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
@@ -23,6 +23,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import org.apache.solr.common.ConfigNode;
import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.DOMUtil;
@@ -99,6 +100,18 @@ public class PluginInfo implements MapSerializable {
}
+ public PluginInfo(ConfigNode node, String err,boolean requireName, boolean requireClass) {
+ type = node.name();
+ name = node.requiredStrAttr(NAME,requireName? () -> new RuntimeException(err + ": missing mandatory attribute 'name'"):null);
+ cName = parseClassName(node.requiredStrAttr(CLASS_NAME, requireClass? () -> new RuntimeException(err + ": missing mandatory attribute 'class'"):null ));
+ className = cName.className;
+ pkgName = cName.pkg;
+ initArgs = DOMUtil.childNodesToNamedList(node);
+ attributes = node.attributes().asMap();
+ children = loadSubPlugins(node);
+ isFromSolrConfig = true;
+
+ }
public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
type = node.getNodeName();
name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
@@ -143,6 +156,17 @@ public class PluginInfo implements MapSerializable {
isFromSolrConfig = true;
}
+ private List<PluginInfo> loadSubPlugins(ConfigNode node) {
+ List<PluginInfo> children = new ArrayList<>();
+ //if there is another sub tag with a non namedlist tag that has to be another plugin
+ node.forEachChild(nd -> {
+ if (NL_TAGS.contains(nd.name())) return null;
+ PluginInfo pluginInfo = new PluginInfo(nd, null, false, false);
+ if (pluginInfo.isEnabled()) children.add(pluginInfo);
+ return null;
+ });
+ return children.isEmpty() ? Collections.<PluginInfo>emptyList() : unmodifiableList(children);
+ }
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
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 eb4909f..6f1d84e 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
@@ -40,7 +40,9 @@ import java.util.Map;
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.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -52,6 +54,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.common.ConfigNode;
import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
@@ -77,12 +80,12 @@ import org.apache.solr.update.SolrIndexConfig;
import org.apache.solr.update.UpdateLog;
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;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import static org.apache.solr.common.params.CommonParams.NAME;
@@ -96,6 +99,7 @@ import static org.apache.solr.core.SolrConfig.PluginOpts.NOOP;
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_CLASS;
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME;
import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME_IN_OVERLAY;
+import static org.apache.solr.core.XmlConfigFile.assertWarnOrFail;
/**
@@ -103,12 +107,18 @@ import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME_IN_OVERLAY
* configuration data for a a Solr instance -- typically found in
* "solrconfig.xml".
*/
-public class SolrConfig extends XmlConfigFile implements MapSerializable {
+public class SolrConfig implements MapSerializable {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static final String DEFAULT_CONF_FILE = "solrconfig.xml";
+ private final String resourceName;
+// private XmlConfigFile xml;
+ private int znodeVersion;
+ ConfigNode root;
+ private final SolrResourceLoader resourceLoader;
+ private Properties substituteProperties;
private RequestParams requestParams;
@@ -171,26 +181,61 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
*/
private SolrConfig(SolrResourceLoader loader, String name, boolean isConfigsetTrusted, Properties substitutableProperties)
throws ParserConfigurationException, IOException, SAXException {
- // insist we have non-null substituteProperties; it might get overlayed
- super(loader, name, null, "/config/", substitutableProperties == null ? new Properties() : substitutableProperties);
+ this.resourceLoader = loader;
+ this.resourceName = name;
+ this.substituteProperties = substitutableProperties;
getOverlay();//just in case it is not initialized
+ // insist we have non-null substituteProperties; it might get overlayed
+ if(loader.getCoreContainer()!= null && loader.getCoreContainer().getZkController() != null ){
+ @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){
+ InputStream in = loader.openResource(name);
+ if (in instanceof ZkSolrResourceLoader.ZkByteArrayInputStream) {
+ int zkVersion = ((ZkSolrResourceLoader.ZkByteArrayInputStream) in).getStat().getVersion();
+ if(cfg.version == zkVersion) {
+ root = cfg.data;
+ } else {
+ configCache.remove(name);
+ readXml(loader, name);
+ configCache.put(name, new IndexSchemaFactory.VersionedConfig(this.znodeVersion, root));
+ }
+ }
+ }
+
+ }
+ }
+ if(root == null) {
+ readXml(loader, name);
+ }
+
+// 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);
- luceneMatchVersion = SolrConfig.parseLuceneVersionString(getVal(IndexSchema.LUCENE_MATCH_VERSION_PARAM, true));
+ 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 = (getNode("indexDefaults", false) != null) || (getNode("mainIndex", false) != null);
+ 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.", getNode(indexConfigPrefix + "/nrtMode", false) == null,
+ " This config will be removed in future versions.", !__("indexDefaults").__("nrtMode").exists(),
true
);
assertWarnOrFail("Solr no longer supports forceful unlocking via the 'unlockOnStartup' option. "+
@@ -198,14 +243,14 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
"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.",
- null == getNode(indexConfigPrefix + "/unlockOnStartup", false),
+ !__(indexConfigPrefix).__( "unlockOnStartup").exists(),
true // 'fail' in trunk
);
// Parse indexConfig section, using mainIndex as backup in case old config is used
- indexConfig = new SolrIndexConfig(this, "indexConfig", null);
+ indexConfig = new SolrIndexConfig (__("indexConfig"), null);
- booleanQueryMaxClauseCount = getInt("query/maxBooleanClauses", BooleanQuery.getMaxClauseCount());
+ 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()
@@ -214,9 +259,9 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
// Warn about deprecated / discontinued parameters
// boolToFilterOptimizer has had no effect since 3.1
- if (get("query/boolTofilterOptimizer", null) != null)
+ if (__("query").__("boolTofilterOptimizer").exists())
log.warn("solrconfig.xml: <boolTofilterOptimizer> is currently not implemented and has no effect.");
- if (get("query/HashDocSet", null) != null)
+ 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()
@@ -224,15 +269,15 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
// filtOptCacheSize = getInt("query/boolTofilterOptimizer/@cacheSize",32);
// filtOptThreshold = getFloat("query/boolTofilterOptimizer/@threshold",.05f);
- useFilterForSortedQuery = getBool("query/useFilterForSortedQuery", false);
- queryResultWindowSize = Math.max(1, getInt("query/queryResultWindowSize", 1));
- queryResultMaxDocsCached = getInt("query/queryResultMaxDocsCached", Integer.MAX_VALUE);
- enableLazyFieldLoading = getBool("query/enableLazyFieldLoading", false);
+ 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");
- queryResultCacheConfig = CacheConfig.getConfig(this, "query/queryResultCache");
- documentCacheConfig = CacheConfig.getConfig(this, "query/documentCache");
- CacheConfig conf = CacheConfig.getConfig(this, "query/fieldValueCache");
+ 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");
@@ -242,24 +287,25 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
conf = new CacheConfig(FastLRUCache.class, args, null);
}
fieldValueCacheConfig = conf;
- useColdSearcher = getBool("query/useColdSearcher", false);
- dataDir = get("dataDir", null);
+ useColdSearcher = __("query").__("useColdSearcher")._bool(false);
+ dataDir = __("dataDir").txt();
if (dataDir != null && dataDir.length() == 0) dataDir = null;
org.apache.solr.search.SolrIndexSearcher.initRegenerators(this);
- if (get("jmx", null) != null) {
+ if (__("jmx").exists()) {
log.warn("solrconfig.xml: <jmx> is no longer supported, use solr.xml:/metrics/reporter section instead");
}
httpCachingConfig = new HttpCachingConfig(this);
- maxWarmingSearchers = getInt("query/maxWarmingSearchers", 1);
- slowQueryThresholdMillis = getInt("query/slowQueryThresholdMillis", -1);
+ 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");
+ 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) {
@@ -270,25 +316,18 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
updateHandlerInfo = loadUpdatehandlerInfo();
- multipartUploadLimitKB = getInt(
- "requestDispatcher/requestParsers/@multipartUploadLimitInKB", Integer.MAX_VALUE);
+ multipartUploadLimitKB = __("requestDispatcher").__("requestParsers").intAttr("multipartUploadLimitInKB", Integer.MAX_VALUE);
if (multipartUploadLimitKB == -1) multipartUploadLimitKB = Integer.MAX_VALUE;
- formUploadLimitKB = getInt(
- "requestDispatcher/requestParsers/@formdataUploadLimitInKB", Integer.MAX_VALUE);
+ formUploadLimitKB = __("requestDispatcher").__("requestParsers").intAttr("formdataUploadLimitInKB", Integer.MAX_VALUE);
if (formUploadLimitKB == -1) formUploadLimitKB = Integer.MAX_VALUE;
- enableRemoteStreams = getBool(
- "requestDispatcher/requestParsers/@enableRemoteStreaming", false);
-
- enableStreamBody = getBool(
- "requestDispatcher/requestParsers/@enableStreamBody", false);
+ enableRemoteStreams = __("requestDispatcher").__("requestParsers").boolAttr("enableRemoteStreaming", false);
- handleSelect = getBool(
- "requestDispatcher/@handleSelect", !luceneMatchVersion.onOrAfter(Version.LUCENE_7_0_0));
+ enableStreamBody = __("requestDispatcher").__("requestParsers").boolAttr("enableStreamBody", false);
- addHttpRequestToContext = getBool(
- "requestDispatcher/requestParsers/@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) {
@@ -305,6 +344,12 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
log.debug("Loaded SolrConfig: {}", name);
}
+ private void readXml(SolrResourceLoader loader, String name) throws ParserConfigurationException, IOException, SAXException {
+ XmlConfigFile xml = new XmlConfigFile(loader, name, null, "/config/", null);
+ root = new DataConfigNode(new DOMConfigNode(xml.getDocument().getDocumentElement()));
+ this.znodeVersion = xml.getZnodeVersion();
+ }
+
private static final AtomicBoolean versionWarningAlreadyLogged = new AtomicBoolean(false);
public static final Version parseLuceneVersionString(final String matchVersion) {
@@ -430,15 +475,15 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
}
protected UpdateHandlerInfo loadUpdatehandlerInfo() {
- return new UpdateHandlerInfo(get("updateHandler/@class", null),
- getInt("updateHandler/autoCommit/maxDocs", -1),
- getInt("updateHandler/autoCommit/maxTime", -1),
- convertHeapOptionStyleConfigStringToBytes(get("updateHandler/autoCommit/maxSize", "")),
- getBool("updateHandler/indexWriter/closeWaitsForMerges", true),
- getBool("updateHandler/autoCommit/openSearcher", true),
- getInt("updateHandler/autoSoftCommit/maxDocs", -1),
- getInt("updateHandler/autoSoftCommit/maxTime", -1),
- getBool("updateHandler/commitWithin/softCommit", true));
+ return new UpdateHandlerInfo( __("updateHandler").attr("class"),
+ __("updateHandler").__("autoCommit").__("maxDocs")._int( -1),
+ __("updateHandler").__("autoCommit").__("maxTime")._int( -1),
+ convertHeapOptionStyleConfigStringToBytes(__("updateHandler").__("autoCommit").__("maxSize").txt()),
+ __("updateHandler").__("indexWriter").__("closeWaitsForMerges")._bool(true),
+ __("updateHandler").__("autoCommit").__("openSearcher")._bool(true),
+ __("updateHandler").__("autoSoftCommit").__("maxDocs")._int(-1),
+ __("updateHandler").__("autoSoftCommit").__("maxTime")._int(-1),
+ __("updateHandler").__("commitWithin").__("softCommit")._bool(true));
}
/**
@@ -449,7 +494,7 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
* @return the size, in bytes. -1 if the given config string is empty
*/
protected static long convertHeapOptionStyleConfigStringToBytes(String configStr) {
- if (configStr.isEmpty()) {
+ if (configStr== null || configStr.isEmpty()) {
return -1;
}
long multiplier = 1;
@@ -496,9 +541,9 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
public List<PluginInfo> readPluginInfos(String tag, boolean requireName, boolean requireClass) {
ArrayList<PluginInfo> result = new ArrayList<>();
- NodeList nodes = (NodeList) evaluate(tag, XPathConstants.NODESET);
- for (int i = 0; i < nodes.getLength(); i++) {
- PluginInfo pluginInfo = new PluginInfo(nodes.item(i), "[solrconfig.xml] " + tag, requireName, requireClass);
+ List<ConfigNode> nodes = root.children(tag);
+ for (int i = 0; i < nodes.size(); i++) {
+ PluginInfo pluginInfo = new PluginInfo(nodes.get(i), "[solrconfig.xml] " + tag, requireName, requireClass);
if (pluginInfo.isEnabled()) result.add(pluginInfo);
}
return result;
@@ -550,9 +595,9 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
/**
* config xpath prefix for getting HTTP Caching options
*/
- private final static String CACHE_PRE
+ /* private final static String CACHE_PRE
= "requestDispatcher/httpCaching/";
-
+*/
/**
* For extracting Expires "ttl" from <cacheControl> config
*/
@@ -567,7 +612,7 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
"cacheControl", cacheControlHeader);
}
- public static enum LastModFrom {
+ public enum LastModFrom {
OPENTIME, DIRLASTMOD, BOGUS;
/**
@@ -588,18 +633,20 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
private final String cacheControlHeader;
private final Long maxAge;
private final LastModFrom lastModFrom;
+ private ConfigNode configNode;
private HttpCachingConfig(SolrConfig conf) {
+ configNode = conf.root;
- never304 = conf.getBool(CACHE_PRE + "@never304", false);
+ //"requestDispatcher/httpCaching/";
+ never304 = __("requestDispatcher").__("httpCaching").boolAttr("never304", false);
- etagSeed = conf.get(CACHE_PRE + "@etagSeed", "Solr");
+ etagSeed = __("requestDispatcher").__("httpCaching").attr("etagSeed", "Solr");
- lastModFrom = LastModFrom.parse(conf.get(CACHE_PRE + "@lastModFrom",
- "openTime"));
+ lastModFrom = LastModFrom.parse(__("requestDispatcher").__("httpCaching").attr("lastModFrom","openTime"));
- cacheControlHeader = conf.get(CACHE_PRE + "cacheControl", null);
+ cacheControlHeader = __("requestDispatcher").__("httpCaching").__("cacheControl").txt();
Long tmp = null; // maxAge
if (null != cacheControlHeader) {
@@ -617,6 +664,9 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
maxAge = tmp;
}
+ private ConfigNode __(String name){
+ return configNode.__(name);
+ }
public boolean isNever304() {
return never304;
@@ -765,8 +815,8 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
}
}
- NodeList nodes = (NodeList) evaluate("lib", XPathConstants.NODESET);
- if (nodes != null && nodes.getLength() > 0) {
+ List<ConfigNode> nodes = root.children("lib");
+ if (nodes != null && nodes.size() > 0) {
if (!isConfigsetTrusted) {
throw new SolrException(ErrorCode.UNAUTHORIZED,
"The configset for this collection was uploaded without any authentication in place,"
@@ -774,14 +824,14 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
+ " after enabling authentication and authorization.");
}
- for (int i = 0; i < nodes.getLength(); i++) {
- Node node = nodes.item(i);
- String baseDir = DOMUtil.getAttr(node, "dir");
- String path = DOMUtil.getAttr(node, PATH);
+ for (int i = 0; i < nodes.size(); i++) {
+ ConfigNode node = nodes.get(i);
+ String baseDir = node.attr("dir");
+ String path = node.attr(PATH);
if (null != baseDir) {
// :TODO: add support for a simpler 'glob' mutually exclusive of regex
Path dir = instancePath.resolve(baseDir);
- String regex = DOMUtil.getAttr(node, "regex");
+ String regex = node.attr("regex");
try {
if (regex == null)
urls.addAll(SolrResourceLoader.getURLs(dir));
@@ -833,42 +883,28 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
return enableStreamBody;
}
- @Override
- public int getInt(String path) {
- return getInt(path, 0);
- }
-
- @Override
- public int getInt(String path, int def) {
- Object val = overlay.getXPathProperty(path);
- if (val != null) return Integer.parseInt(val.toString());
- return super.getInt(path, def);
- }
-
- @Override
- public boolean getBool(String path, boolean def) {
- Object val = overlay.getXPathProperty(path);
- if (val != null) return Boolean.parseBoolean(val.toString());
- return super.getBool(path, def);
+ /*private Object _getVal(String path) {
+ List<String> parts = StrUtils.split(path,'/');
+ Object val = overlay.getXPathProperty(parts);
+ if(val !=null) return val;
+ return root.child(parts);
}
- @Override
public String get(String path) {
- Object val = overlay.getXPathProperty(path, true);
- return val != null ? val.toString() : super.get(path);
+ Object val = _getVal(path);
+ return val != null ? val.toString() :null;
}
- @Override
public String get(String path, String def) {
- Object val = overlay.getXPathProperty(path, true);
- return val != null ? val.toString() : super.get(path, def);
+ Object val = _getVal(path);
+ return val != null ? val.toString() : xml.get(path, def);
- }
+ }*/
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Map<String, Object> toMap(Map<String, Object> result) {
- if (getZnodeVersion() > -1) result.put(ZNODEVER, getZnodeVersion());
+ if (znodeVersion > -1) result.put(ZNODEVER, znodeVersion);
if(luceneMatchVersion != null) result.put(IndexSchema.LUCENE_MATCH_VERSION_PARAM, luceneMatchVersion.toString());
result.put("updateHandler", getUpdateHandlerInfo());
Map m = new LinkedHashMap();
@@ -929,11 +965,10 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
}
- @Override
public Properties getSubstituteProperties() {
Map<String, Object> p = getOverlay().getUserProps();
- if (p == null || p.isEmpty()) return super.getSubstituteProperties();
- Properties result = new Properties(super.getSubstituteProperties());
+ if (p == null || p.isEmpty()) return substituteProperties;
+ Properties result = new Properties(substituteProperties);
result.putAll(p);
return result;
}
@@ -942,7 +977,7 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
public ConfigOverlay getOverlay() {
if (overlay == null) {
- overlay = getConfigOverlay(getResourceLoader());
+ overlay = getConfigOverlay(resourceLoader);
}
return overlay;
}
@@ -969,13 +1004,42 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
if (o == null || PackageLoader.LATEST.equals(o)) return null;
return o.toString();
}
-
public RequestParams refreshRequestParams() {
- requestParams = RequestParams.getFreshRequestParams(getResourceLoader(), requestParams);
+ requestParams = RequestParams.getFreshRequestParams(resourceLoader, requestParams);
if (log.isDebugEnabled()) {
log.debug("current version of requestparams : {}", requestParams.getZnodeVersion());
}
return requestParams;
}
+ public SolrResourceLoader getResourceLoader() {
+ return resourceLoader;
+ }
+
+ public int getZnodeVersion() {
+ return znodeVersion;
+ }
+
+ public String getName() {
+ return resourceName;
+ }
+
+ public String getResourceName() {
+ return resourceName;
+ }
+
+ /**fetches a child node by name. An "empty node" is returned if the child does not exist
+ * This never returns a null
+ *
+ *
+ */
+ public ConfigNode __(String name) {
+ return root.__(name);
+ }
+
+ public ConfigNode __(String name, Predicate<ConfigNode> test) {
+ return root.__(name, test);
+ }
+
+
}
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 030aa9e..918b878 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -175,7 +175,9 @@ public class IndexSchema {
this(luceneVersion, resourceLoader, substitutableProperties);
this.resourceName = Objects.requireNonNull(name);
- ConfigNode.SUBSTITUTES.set(substitutableProperties::getProperty);
+ ConfigNode.SUBSTITUTES.set(key -> substitutableProperties == null ?
+ null :
+ substitutableProperties.getProperty(key));
try {
readSchema(schemaResource);
loader.inform(loader);
diff --git a/solr/core/src/java/org/apache/solr/schema/IndexSchemaFactory.java b/solr/core/src/java/org/apache/solr/schema/IndexSchemaFactory.java
index c49cb12..da7e046 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchemaFactory.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchemaFactory.java
@@ -117,8 +117,8 @@ public abstract class IndexSchemaFactory implements NamedListInitializedPlugin {
}
public static class VersionedConfig {
- final int version;
- final ConfigNode data;
+ public final int version;
+ public final ConfigNode data;
public VersionedConfig(int version, ConfigNode data) {
this.version = version;
diff --git a/solr/core/src/java/org/apache/solr/search/CacheConfig.java b/solr/core/src/java/org/apache/solr/search/CacheConfig.java
index 9b1c297..b2843d4 100644
--- a/solr/core/src/java/org/apache/solr/search/CacheConfig.java
+++ b/solr/core/src/java/org/apache/solr/search/CacheConfig.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.search;
-import javax.xml.xpath.XPathConstants;
import java.lang.invoke.MethodHandles;
import java.util.Collections;
import java.util.HashMap;
@@ -25,19 +24,15 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
+import org.apache.solr.common.ConfigNode;
+import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.StrUtils;
-import org.apache.solr.common.MapSerializable;
-
import org.apache.solr.core.PluginInfo;
-
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrResourceLoader;
-import org.apache.solr.common.util.DOMUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
import static org.apache.solr.common.params.CommonParams.NAME;
@@ -45,10 +40,8 @@ import static org.apache.solr.common.params.CommonParams.NAME;
* Contains the knowledge of how cache config is
* stored in the solrconfig.xml file, and implements a
* factory to create caches.
- *
- *
*/
-public class CacheConfig implements MapSerializable{
+public class CacheConfig implements MapSerializable {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private String nodeName;
@@ -70,7 +63,8 @@ public class CacheConfig implements MapSerializable{
private String regenImpl;
- public CacheConfig() {}
+ public CacheConfig() {
+ }
@SuppressWarnings({"rawtypes"})
public CacheConfig(Class<? extends SolrCache> clazz, Map<String,String> args, CacheRegenerator regenerator) {
@@ -88,15 +82,13 @@ public class CacheConfig implements MapSerializable{
this.regenerator = regenerator;
}
- public static Map<String, CacheConfig> getMultipleConfigs(SolrConfig solrConfig, String configPath) {
- NodeList nodes = (NodeList) solrConfig.evaluate(configPath, XPathConstants.NODESET);
- if (nodes == null || nodes.getLength() == 0) return new LinkedHashMap<>();
- Map<String, CacheConfig> result = new HashMap<>(nodes.getLength());
- for (int i = 0; i < nodes.getLength(); i++) {
- Node node = nodes.item(i);
- if ("true".equals(DOMUtil.getAttrOrDefault(node, "enabled", "true"))) {
- CacheConfig config = getConfig(solrConfig, node.getNodeName(),
- DOMUtil.toMap(node.getAttributes()), configPath);
+ public static Map<String, CacheConfig> getMultipleConfigs(SolrConfig solrConfig, String configPath, List<ConfigNode> nodes) {
+ if (nodes == null || nodes.size() == 0) return new LinkedHashMap<>();
+ Map<String, CacheConfig> result = new HashMap<>(nodes.size());
+ for (int i = 0; i < nodes.size(); i++) {
+ ConfigNode node = nodes.get(i);
+ if (node.boolAttr("enabled", true)) {
+ CacheConfig config = getConfig(solrConfig, node.name(), node.attributes().asMap(), configPath);
result.put(config.args.get(NAME), config);
}
}
@@ -105,20 +97,20 @@ public class CacheConfig implements MapSerializable{
@SuppressWarnings({"unchecked"})
- public static CacheConfig getConfig(SolrConfig solrConfig, String xpath) {
- Node node = solrConfig.getNode(xpath, false);
- if(node == null || !"true".equals(DOMUtil.getAttrOrDefault(node, "enabled", "true"))) {
+ public static CacheConfig getConfig(SolrConfig solrConfig, ConfigNode node, String xpath) {
+// Node node = solrConfig.getNode(xpath, false);
+ if (!node.exists() || !"true".equals(node.attributes().get("enabled", "true"))) {
Map<String, String> m = solrConfig.getOverlay().getEditableSubProperties(xpath);
- if(m==null) return null;
+ if (m == null) return null;
List<String> parts = StrUtils.splitSmart(xpath, '/');
- return getConfig(solrConfig,parts.get(parts.size()-1) , Collections.EMPTY_MAP,xpath);
+ return getConfig(solrConfig, parts.get(parts.size() - 1), Collections.EMPTY_MAP, xpath);
}
- return getConfig(solrConfig, node.getNodeName(),DOMUtil.toMap(node.getAttributes()), xpath);
+ return getConfig(solrConfig, node.name(), node.attributes().asMap(), xpath);
}
@SuppressWarnings({"unchecked"})
- public static CacheConfig getConfig(SolrConfig solrConfig, String nodeName, Map<String,String> attrs, String xpath) {
+ public static CacheConfig getConfig(SolrConfig solrConfig, String nodeName, Map<String, String> attrs, String xpath) {
CacheConfig config = new CacheConfig();
config.nodeName = nodeName;
@SuppressWarnings({"rawtypes"})
diff --git a/solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java b/solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java
index a364757..e70fb9b 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java
@@ -19,8 +19,8 @@ package org.apache.solr.update;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Collections;
-import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.DelegatingAnalyzerWrapper;
@@ -31,6 +31,7 @@ import org.apache.lucene.index.MergePolicy;
import org.apache.lucene.index.MergeScheduler;
import org.apache.lucene.search.Sort;
import org.apache.lucene.util.InfoStream;
+import org.apache.solr.common.ConfigNode;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.DirectoryFactory;
@@ -91,11 +92,12 @@ public class SolrIndexConfig implements MapSerializable {
public final PluginInfo mergedSegmentWarmerInfo;
public InfoStream infoStream = InfoStream.NO_OUTPUT;
+ private ConfigNode node;
/**
* Internal constructor for setting defaults based on Lucene Version
*/
- private SolrIndexConfig(SolrConfig solrConfig) {
+ private SolrIndexConfig() {
useCompoundFile = false;
maxBufferedDocs = -1;
ramBufferSizeMB = 100;
@@ -109,88 +111,78 @@ public class SolrIndexConfig implements MapSerializable {
// enable coarse-grained metrics by default
metricsInfo = new PluginInfo("metrics", Collections.emptyMap(), null, null);
}
-
+ private ConfigNode __(String s) { return node.__(s); }
+ public SolrIndexConfig(SolrConfig cfg, SolrIndexConfig def) {
+ this(cfg.__("indexConfig"), def);
+ }
/**
* Constructs a SolrIndexConfig which parses the Lucene related config params in solrconfig.xml
- * @param solrConfig the overall SolrConfig object
- * @param prefix the XPath prefix for which section to parse (mandatory)
* @param def a SolrIndexConfig instance to pick default values from (optional)
*/
- public SolrIndexConfig(SolrConfig solrConfig, String prefix, SolrIndexConfig def) {
- if (prefix == null) {
- prefix = "indexConfig";
- log.debug("Defaulting to prefix '{}' for index configuration", prefix);
- }
-
+ public SolrIndexConfig(ConfigNode cfg, SolrIndexConfig def) {
+ this.node = cfg;
if (def == null) {
- def = new SolrIndexConfig(solrConfig);
+ def = new SolrIndexConfig();
}
+
// sanity check: this will throw an error for us if there is more then one
// config section
- Object unused = solrConfig.getNode(prefix, false);
+// Object unused = solrConfig.getNode(prefix, false);
// Assert that end-of-life parameters or syntax is not in our config.
// Warn for luceneMatchVersion's before LUCENE_3_6, fail fast above
assertWarnOrFail("The <mergeScheduler>myclass</mergeScheduler> syntax is no longer supported in solrconfig.xml. Please use syntax <mergeScheduler class=\"myclass\"/> instead.",
- !((solrConfig.getNode(prefix + "/mergeScheduler", false) != null) && (solrConfig.get(prefix + "/mergeScheduler/@class", null) == null)),
+ __("mergeScheduler").isNull() || __("mergeScheduler").attr("class") != null,
true);
assertWarnOrFail("Beginning with Solr 7.0, <mergePolicy>myclass</mergePolicy> is no longer supported, use <mergePolicyFactory> instead.",
- !((solrConfig.getNode(prefix + "/mergePolicy", false) != null) && (solrConfig.get(prefix + "/mergePolicy/@class", null) == null)),
+ __("mergePolicy").isNull() || __("mergePolicy").attr("class") != null,
true);
assertWarnOrFail("The <luceneAutoCommit>true|false</luceneAutoCommit> parameter is no longer valid in solrconfig.xml.",
- solrConfig.get(prefix + "/luceneAutoCommit", null) == null,
+ __("luceneAutoCommit").isNull(),
true);
- useCompoundFile = solrConfig.getBool(prefix+"/useCompoundFile", def.useCompoundFile);
- maxBufferedDocs = solrConfig.getInt(prefix+"/maxBufferedDocs", def.maxBufferedDocs);
- ramBufferSizeMB = solrConfig.getDouble(prefix+"/ramBufferSizeMB", def.ramBufferSizeMB);
- maxCommitMergeWaitMillis = solrConfig.getInt(prefix+"/maxCommitMergeWaitTime", def.maxCommitMergeWaitMillis);
+ useCompoundFile = __("useCompoundFile")._bool(def.useCompoundFile);
+ maxBufferedDocs = __("maxBufferedDocs")._int(def.maxBufferedDocs);
+ ramBufferSizeMB = __("ramBufferSizeMB").doubleVal(def.ramBufferSizeMB);
+ maxCommitMergeWaitMillis = __("maxCommitMergeWaitTime")._int(def.maxCommitMergeWaitMillis);
// how do we validate the value??
- ramPerThreadHardLimitMB = solrConfig.getInt(prefix+"/ramPerThreadHardLimitMB", def.ramPerThreadHardLimitMB);
+ ramPerThreadHardLimitMB = __("ramPerThreadHardLimitMB")._int(def.ramPerThreadHardLimitMB);
- writeLockTimeout=solrConfig.getInt(prefix+"/writeLockTimeout", def.writeLockTimeout);
- lockType=solrConfig.get(prefix+"/lockType", def.lockType);
+ writeLockTimeout= __("writeLockTimeout")._int(def.writeLockTimeout);
+ lockType = __("lockType").txt(def.lockType);
- List<PluginInfo> infos = solrConfig.readPluginInfos(prefix + "/metrics", false, false);
- if (infos.isEmpty()) {
- metricsInfo = def.metricsInfo;
- } else {
- metricsInfo = infos.get(0);
- }
- mergeSchedulerInfo = getPluginInfo(prefix + "/mergeScheduler", solrConfig, def.mergeSchedulerInfo);
- mergePolicyFactoryInfo = getPluginInfo(prefix + "/mergePolicyFactory", solrConfig, def.mergePolicyFactoryInfo);
+ metricsInfo = getPluginInfo(__("metrics"), def.metricsInfo);
+ mergeSchedulerInfo = getPluginInfo(__("mergeScheduler"), def.mergeSchedulerInfo);
+ mergePolicyFactoryInfo = getPluginInfo(__("mergePolicyFactory"), def.mergePolicyFactoryInfo);
assertWarnOrFail("Beginning with Solr 7.0, <mergePolicy> is no longer supported, use <mergePolicyFactory> instead.",
- getPluginInfo(prefix + "/mergePolicy", solrConfig, null) == null,
+ __("mergePolicy").isNull(),
true);
assertWarnOrFail("Beginning with Solr 7.0, <maxMergeDocs> is no longer supported, configure it on the relevant <mergePolicyFactory> instead.",
- solrConfig.getInt(prefix+"/maxMergeDocs", 0) == 0,
+ __("maxMergeDocs").isNull(),
true);
assertWarnOrFail("Beginning with Solr 7.0, <mergeFactor> is no longer supported, configure it on the relevant <mergePolicyFactory> instead.",
- solrConfig.getInt(prefix+"/mergeFactor", 0) == 0,
+ __("maxMergeFactor").isNull(),
true);
- String val = solrConfig.get(prefix + "/termIndexInterval", null);
- if (val != null) {
+ if (__("termIndexInterval").exists()) {
throw new IllegalArgumentException("Illegal parameter 'termIndexInterval'");
}
- boolean infoStreamEnabled = solrConfig.getBool(prefix + "/infoStream", false);
- if(infoStreamEnabled) {
- String infoStreamFile = solrConfig.get(prefix + "/infoStream/@file", null);
- if (infoStreamFile == null) {
+ if(__("infoStream")._bool(false)) {
+ if (__("infoStream").attr("file") == null) {
log.info("IndexWriter infoStream solr logging is enabled");
infoStream = new LoggingInfoStream();
} else {
throw new IllegalArgumentException("Remove @file from <infoStream> to output messages to solr's logfile");
}
}
- mergedSegmentWarmerInfo = getPluginInfo(prefix + "/mergedSegmentWarmer", solrConfig, def.mergedSegmentWarmerInfo);
+ mergedSegmentWarmerInfo = getPluginInfo(__("mergedSegmentWarmer"), def.mergedSegmentWarmerInfo);
assertWarnOrFail("Beginning with Solr 5.0, <checkIntegrityAtMerge> option is no longer supported and should be removed from solrconfig.xml (these integrity checks are now automatic)",
- (null == solrConfig.getNode(prefix + "/checkIntegrityAtMerge", false)),
+ __( "checkIntegrityAtMerge").isNull(),
true);
}
@@ -215,9 +207,10 @@ public class SolrIndexConfig implements MapSerializable {
return m;
}
- private PluginInfo getPluginInfo(String path, SolrConfig solrConfig, PluginInfo def) {
- List<PluginInfo> l = solrConfig.readPluginInfos(path, false, true);
- return l.isEmpty() ? def : l.get(0);
+ private PluginInfo getPluginInfo(ConfigNode node , PluginInfo def) {
+ return node != null && node.exists() ?
+ new PluginInfo(node, "[solrconfig.xml] " + node.name(), false, true) :
+ def;
}
private static class DelayedSchemaAnalyzer extends DelegatingAnalyzerWrapper {
diff --git a/solr/core/src/java/org/apache/solr/update/VersionInfo.java b/solr/core/src/java/org/apache/solr/update/VersionInfo.java
index b97f812..cd36854 100644
--- a/solr/core/src/java/org/apache/solr/update/VersionInfo.java
+++ b/solr/core/src/java/org/apache/solr/update/VersionInfo.java
@@ -94,8 +94,8 @@ public class VersionInfo {
this.ulog = ulog;
IndexSchema schema = ulog.uhandler.core.getLatestSchema();
versionField = getAndCheckVersionField(schema);
- versionBucketLockTimeoutMs = ulog.uhandler.core.getSolrConfig().getInt("updateHandler/versionBucketLockTimeoutMs",
- Integer.parseInt(System.getProperty(SYS_PROP_BUCKET_VERSION_LOCK_TIMEOUT_MS, "0")));
+ versionBucketLockTimeoutMs = ulog.uhandler.core.getSolrConfig().__("updateHandler").__("versionBucketLockTimeoutMs")
+ ._int(Integer.parseInt(System.getProperty(SYS_PROP_BUCKET_VERSION_LOCK_TIMEOUT_MS, "0")));
buckets = new VersionBucket[ BitUtil.nextHighestPowerOfTwo(nBuckets) ];
for (int i=0; i<buckets.length; i++) {
if (versionBucketLockTimeoutMs > 0) {
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 d704e4b..f059c2d 100644
--- a/solr/core/src/java/org/apache/solr/util/DataConfigNode.java
+++ b/solr/core/src/java/org/apache/solr/util/DataConfigNode.java
@@ -60,9 +60,7 @@ public class DataConfigNode implements ConfigNode {
}
public String subtituteVal(String s) {
- Function<String, String> props = SUBSTITUTES.get();
- if (props == null) return s;
- return PropertiesUtil.substitute(s, props);
+ return PropertiesUtil.substitute(s, SUBSTITUTES.get());
}
private SimpleMap<String> wrap(SimpleMap<String> delegate) {
diff --git a/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java b/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
index c021615..74227c7 100644
--- a/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
+++ b/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
@@ -196,9 +196,9 @@ public class TestCodecSupport extends SolrTestCaseJ4 {
SolrCore c = null;
SolrConfig config = TestHarness.createConfig(testSolrHome, previousCoreName, "solrconfig_codec2.xml");
- assertEquals("Unexpected codec factory for this test.", "solr.SchemaCodecFactory", config.get("codecFactory/@class"));
- assertNull("Unexpected configuration of codec factory for this test. Expecting empty element",
- config.getNode("codecFactory", false).getFirstChild());
+ assertEquals("Unexpected codec factory for this test.", "solr.SchemaCodecFactory", config.__("codecFactory").attr("class"));
+ assertTrue("Unexpected configuration of codec factory for this test. Expecting empty element",
+ config.__("codecFactory").children(null, (String)null).isEmpty());
IndexSchema schema = IndexSchemaFactory.buildIndexSchema("schema_codec.xml", config);
CoreContainer coreContainer = h.getCoreContainer();
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 ccf3114..00c01a1 100644
--- a/solr/core/src/test/org/apache/solr/core/TestConfig.java
+++ b/solr/core/src/test/org/apache/solr/core/TestConfig.java
@@ -16,17 +16,18 @@
*/
package org.apache.solr.core;
-import javax.xml.xpath.XPathConstants;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Collections;
+import java.util.List;
import org.apache.lucene.index.ConcurrentMergeScheduler;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.TieredMergePolicy;
import org.apache.lucene.util.InfoStream;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.ConfigNode;
import org.apache.solr.handler.admin.ShowFileRequestHandler;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.IndexSchemaFactory;
@@ -35,8 +36,6 @@ import org.apache.solr.update.SolrIndexConfig;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
public class TestConfig extends SolrTestCaseJ4 {
@@ -80,24 +79,24 @@ public class TestConfig extends SolrTestCaseJ4 {
public void testJavaProperty() {
// property values defined in build.xml
- String s = solrConfig.get("propTest");
+ String s = solrConfig.__("propTest").textValue();
assertEquals("prefix-proptwo-suffix", s);
- s = solrConfig.get("propTest/@attr1", "default");
+ s = solrConfig.__("propTest").attr("attr1", "default");
assertEquals("propone-${literal}", s);
- s = solrConfig.get("propTest/@attr2", "default");
+ s = solrConfig.__("propTest").attr("attr2", "default");
assertEquals("default-from-config", s);
- s = solrConfig.get("propTest[@attr2='default-from-config']", "default");
- assertEquals("prefix-proptwo-suffix", s);
- NodeList nl = (NodeList) solrConfig.evaluate("propTest", XPathConstants.NODESET);
- assertEquals(1, nl.getLength());
- assertEquals("prefix-proptwo-suffix", nl.item(0).getTextContent());
+ assertEquals("prefix-proptwo-suffix", solrConfig.__("propTest",
+ it -> "default-from-config".equals(it.attr("attr2"))).txt());
+
+ List<ConfigNode> nl = solrConfig.root.children ("propTest");
+ assertEquals(1, nl.size());
+ assertEquals("prefix-proptwo-suffix", nl.get(0).textValue());
- Node node = solrConfig.getNode("propTest", true);
- assertEquals("prefix-proptwo-suffix", node.getTextContent());
+ assertEquals("prefix-proptwo-suffix", solrConfig.__("propTest"));
}
// sometime if the config referes to old things, it must be replaced with new stuff
diff --git a/solr/core/src/test/org/apache/solr/core/TestSimpleTextCodec.java b/solr/core/src/test/org/apache/solr/core/TestSimpleTextCodec.java
index 9f6776b..1607ceb 100644
--- a/solr/core/src/test/org/apache/solr/core/TestSimpleTextCodec.java
+++ b/solr/core/src/test/org/apache/solr/core/TestSimpleTextCodec.java
@@ -33,7 +33,7 @@ public class TestSimpleTextCodec extends SolrTestCaseJ4 {
public void test() throws Exception {
SolrConfig config = h.getCore().getSolrConfig();
- String codecFactory = config.get("codecFactory/@class");
+ String codecFactory = config.__("codecFactory").attr("class");
assertEquals("Unexpected solrconfig codec factory", "solr.SimpleTextCodecFactory", codecFactory);
assertEquals("Unexpected core codec", "SimpleText", h.getCore().getCodec().getName());
diff --git a/solr/core/src/test/org/apache/solr/handler/component/SuggestComponentTest.java b/solr/core/src/test/org/apache/solr/handler/component/SuggestComponentTest.java
index b15e167..f144bb1 100644
--- a/solr/core/src/test/org/apache/solr/handler/component/SuggestComponentTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/component/SuggestComponentTest.java
@@ -16,7 +16,10 @@
*/
package org.apache.solr.handler.component;
+import java.util.function.Predicate;
+
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.ConfigNode;
import org.apache.solr.common.SolrException;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
@@ -25,6 +28,8 @@ import org.apache.solr.spelling.suggest.SuggesterParams;
import org.junit.BeforeClass;
import org.junit.Test;
+import static org.apache.solr.common.ConfigNode.Helpers.at;
+
public class SuggestComponentTest extends SolrTestCaseJ4 {
@@ -204,14 +209,25 @@ public class SuggestComponentTest extends SolrTestCaseJ4 {
final String suggester = "suggest_doc_default_startup_no_store";
// validate that this suggester is not storing the lookup
- assertEquals(suggester,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[8]/str[@name='name']", false));
- assertNull(h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[8]/str[@name='storeDir']", false));
+ assertEquals(suggester,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",8).
+ __("str", n -> "name".equals(n.attr("name"))).txt());
+
+ assertNull( h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",8).
+ __("str", n -> "storeDir".equals(n.attr("name"))).txt());
// validate that this suggester only builds manually and has not buildOnStartup parameter
- assertEquals("false",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[8]/str[@name='buildOnCommit']", true));
- assertNull(h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[8]/str[@name='buildOnStartup']", false));
+
+ assertEquals("false",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",8).
+ __("str", n -> "buildOnCommit".equals(n.attr("name"))).txt());
+
+ assertNull(h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",8).
+ __("str", n -> "buildOnStartup".equals(n.attr("name"))).txt());
reloadCore(random().nextBoolean());
@@ -254,15 +270,27 @@ public class SuggestComponentTest extends SolrTestCaseJ4 {
final String suggester = "suggest_doc_default_startup";
// validate that this suggester is storing the lookup
- assertEquals(suggester,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[7]/str[@name='name']", false));
- assertEquals(suggester,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[7]/str[@name='storeDir']", false));
+
+ assertEquals(suggester,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",7).
+ __("str", n -> "name".equals(n.attr("name"))).txt());
+
+ assertEquals(suggester,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",7).
+ __("str", n -> "storeDir".equals(n.attr("name"))).txt());
// validate that this suggester only builds manually and has not buildOnStartup parameter
- assertEquals("false",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[7]/str[@name='buildOnCommit']", true));
- assertNull(h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[7]/str[@name='buildOnStartup']", false));
+
+ assertEquals("false",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",7).
+ __("str", n -> "buildOnCommit".equals(n.attr("name"))).txt());
+
+ assertNull( h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",7).
+ __("str", n -> "buildOnStartup".equals(n.attr("name"))).txt());
assertQ(req("qt", rh,
SuggesterParams.SUGGEST_DICT, suggester,
@@ -339,16 +367,27 @@ public class SuggestComponentTest extends SolrTestCaseJ4 {
final String suggester = "suggest_fuzzy_doc_manal_build";
// validate that this suggester is storing the lookup
- assertEquals(suggester,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[6]/str[@name='name']", false));
- assertEquals(suggester,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[6]/str[@name='storeDir']", false));
+
+ assertEquals(suggester,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",6).
+ __("str", n -> "name".equals(n.attr("name"))).txt());
+
+ assertEquals(suggester,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",6).
+ __("str", n -> "storeDir".equals(n.attr("name"))).txt());
// validate that this suggester only builds manually
- assertEquals("false",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[6]/str[@name='buildOnCommit']", true));
- assertEquals("false",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[6]/str[@name='buildOnStartup']", true));
+
+ assertEquals("false",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",6).
+ __("str", n -> "buildOnCommit".equals(n.attr("name"))).txt());
+ assertEquals("false",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",6).
+ __("str", n -> "buildOnStartup".equals(n.attr("name"))).txt());
// build the suggester manually
assertQ(req("qt", rh,
@@ -402,15 +441,25 @@ public class SuggestComponentTest extends SolrTestCaseJ4 {
h.getCore().getSolrConfig().useColdSearcher);
// validate that this suggester is not storing the lookup and buildOnStartup is not set
- assertEquals(suggesterFuzzy,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[3]/str[@name='name']", false));
- assertNull(h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[3]/str[@name='storeDir']", false));
+ assertEquals(suggesterFuzzy,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",3).
+ __("str", n -> "buildOnStartup".equals(n.attr("name"))).txt());
+
+ assertNull( h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",3).
+ __("str", n -> "storeDir".equals(n.attr("name"))).txt());
+
// assert that buildOnStartup=false
- assertEquals("false",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[3]/str[@name='buildOnStartup']", false));
- assertEquals("true",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[3]/str[@name='buildOnCommit']", false));
+ assertEquals("false",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",3).
+ __("str", n -> "buildOnStartup".equals(n.attr("name"))).txt());
+ assertEquals("true",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",3).
+ __("str", n -> "buildOnCommit".equals(n.attr("name"))).txt());
// verify that this suggester is built (there was a commit in setUp)
assertQ(req("qt", rh,
@@ -453,13 +502,21 @@ public class SuggestComponentTest extends SolrTestCaseJ4 {
final String suggestStartup = "suggest_fuzzy_doc_dict_build_startup";
// repeat the test with "suggest_fuzzy_doc_dict_build_startup", it is exactly the same but with buildOnStartup=true
- assertEquals(suggestStartup,
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[5]/str[@name='name']", false));
- assertNull(h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[5]/str[@name='storeDir']", false));
- assertEquals("true",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[5]/str[@name='buildOnStartup']", false));
- assertEquals("false",
- h.getCore().getSolrConfig().getVal("//searchComponent[@name='suggest']/lst[5]/str[@name='buildOnCommit']", false));
+ assertEquals(suggestStartup,
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",5).
+ __("str", n -> "name".equals(n.attr("name"))).txt());
+ assertNull( h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",5).
+ __("str", n -> "storeDir".equals(n.attr("name"))).txt());
+ assertEquals("true",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",5).
+ __("str", n -> "buildOnStartup".equals(n.attr("name"))).txt());
+ assertEquals("false",
+ h.getCore().getSolrConfig().__("searchComponent", n -> "suggest".equals(n.attr("name")))
+ .__("lst",5).
+ __("str", n -> "buildOnCommit".equals(n.attr("name"))).txt());
// reload the core
reloadCore(createNewCores);
diff --git a/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java b/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
index 4f43b10..221dd07 100644
--- a/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
+++ b/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
@@ -70,7 +70,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
@Test
public void testFailingSolrIndexConfigCreation() throws Exception {
SolrConfig solrConfig = new SolrConfig(instanceDir,"bad-mpf-solrconfig.xml");
- SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null);
IndexSchema indexSchema = IndexSchemaFactory.buildIndexSchema(schemaFileName, solrConfig);
h.getCore().setLatestSchema(indexSchema);
@@ -83,7 +83,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
public void testTieredMPSolrIndexConfigCreation() throws Exception {
String solrConfigFileName = solrConfigFileNameTieredMergePolicyFactory;
SolrConfig solrConfig = new SolrConfig(instanceDir, solrConfigFileName);
- SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null);
IndexSchema indexSchema = IndexSchemaFactory.buildIndexSchema(schemaFileName, solrConfig);
h.getCore().setLatestSchema(indexSchema);
@@ -108,7 +108,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
public void testConcurrentMergeSchedularSolrIndexConfigCreation() throws Exception {
String solrConfigFileName = solrConfigFileNameConnMSPolicyFactory;
SolrConfig solrConfig = new SolrConfig(instanceDir, solrConfigFileName);
- SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null);
IndexSchema indexSchema = IndexSchemaFactory.buildIndexSchema(schemaFileName, solrConfig);
h.getCore().setLatestSchema(indexSchema);
@@ -132,7 +132,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
final boolean expectedFieldSortDescending = true;
SolrConfig solrConfig = new SolrConfig(instanceDir, solrConfigFileNameSortingMergePolicyFactory);
- SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null);
assertNotNull(solrIndexConfig);
IndexSchema indexSchema = IndexSchemaFactory.buildIndexSchema(schemaFileName, solrConfig);
@@ -150,7 +150,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
public void testMergedSegmentWarmerIndexConfigCreation() throws Exception {
SolrConfig solrConfig = new SolrConfig(instanceDir, solrConfigFileNameWarmerRandomMergePolicyFactory);
- SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null);
assertNotNull(solrIndexConfig);
assertNotNull(solrIndexConfig.mergedSegmentWarmerInfo);
assertEquals(SimpleMergedSegmentWarmer.class.getName(),
@@ -166,7 +166,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
final String solrConfigFileNameTMP = solrConfigFileNameTieredMergePolicyFactory;
final String solrConfigFileName = (random().nextBoolean() ? solrConfigFileNameWarmer : solrConfigFileNameTMP);
SolrConfig solrConfig = new SolrConfig(instanceDir, solrConfigFileName);
- SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null);
assertNotNull(solrIndexConfig);
assertNotNull(solrIndexConfig.mergePolicyFactoryInfo);
if (solrConfigFileName.equals(solrConfigFileNameWarmerRandomMergePolicyFactory)) {
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 81da171..cd9a372 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
@@ -20,6 +20,8 @@ package org.apache.solr.cluster.api;
import org.apache.solr.common.MapWriter;
import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -82,4 +84,10 @@ public interface SimpleMap<T> extends MapWriter {
default void writeMap(EntryWriter ew) throws IOException {
forEachEntry(ew::putNoEx);
}
+
+ default Map<String, T> asMap() {
+ Map<String, T> result = new LinkedHashMap<>();
+ forEachEntry((k, v) -> result.put(k, v));
+ return result;
+ }
}
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 91e289d..adbe914 100644
--- a/solr/solrj/src/java/org/apache/solr/common/ConfigNode.java
+++ b/solr/solrj/src/java/org/apache/solr/common/ConfigNode.java
@@ -24,8 +24,12 @@ import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.function.Supplier;
import org.apache.solr.cluster.api.SimpleMap;
+import org.apache.solr.common.util.WrappedSimpleMap;
+
+import static org.apache.solr.common.ConfigNode.Helpers.*;
/**
* A generic interface that represents a config file, mostly XML
@@ -55,6 +59,55 @@ public interface ConfigNode {
return child(null, name);
}
+ /**
+ * Child by name or return an empty node if null
+ * if there are multiple values , it returns the first elem
+ * This never returns a null
+ */
+ default ConfigNode __(String name) {
+ ConfigNode child = child(null, name);
+ return child == null? EMPTY: child;
+ }
+ default ConfigNode __(String name, Predicate<ConfigNode> test) {
+ List<ConfigNode> children = children(test, name);
+ if(children.isEmpty()) return EMPTY;
+ return children.get(0);
+ }
+ default ConfigNode __(String name, int idx) {
+ List<ConfigNode> children = children(null, name);
+ if(idx < children.size()) return children.get(idx);
+ return EMPTY;
+
+ }
+
+ default ConfigNode child(List<String> path) {
+ ConfigNode node = this;
+ for (String s : path) {
+ node = node.child(s);
+ if (node == null) break;
+ }
+ return node;
+ }
+
+ default ConfigNode child(String name, Supplier<RuntimeException> err) {
+ ConfigNode n = child(name);
+ if(n == null) throw err.get();
+ return n;
+ }
+
+ default boolean _bool(boolean def) { return __bool(textValue(),def); }
+ default int _int(int def) { return __int(textValue(), 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);
+ }
+ 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); }
/**Iterate through child nodes with the name and return the first child that matches
*/
default ConfigNode child(Predicate<ConfigNode> test, String name) {
@@ -96,11 +149,78 @@ public interface ConfigNode {
return children(null, Collections.singleton(name));
}
+ default boolean exists() { return true; }
+ default boolean isNull() { return false; }
+
+ default <T> T compute(Function<ConfigNode, T> ifNotNull, Supplier<T> ifNull) {
+ return ifNotNull.apply(this);
+ }
+
/** abortable iterate through children
*
* @param fun consume the node and return true to continue or false to abort
*/
void forEachChild(Function<ConfigNode, Boolean> fun);
+ ConfigNode EMPTY = new ConfigNode() {
+ @Override
+ public String name() {
+ return null;
+ }
+
+ @Override
+ public String textValue() { return null; }
+
+ @Override
+ public SimpleMap<String> attributes() {
+ return empty_attrs;
+ }
+
+ @Override
+ public String attr(String name) { return null; }
+
+ @Override
+ public String attr(String name, String def) { return def; }
+
+ @Override
+ public ConfigNode child(String name) { return null; }
+
+ @Override
+ public ConfigNode __(String name) {
+ return EMPTY;
+ }
+
+ public boolean exists() { return false; }
+
+ @Override
+ public boolean isNull() { return true; }
+
+ @Override
+ public <T> T compute(Function<ConfigNode, T> ifNotNull, Supplier<T> ifNull) { return ifNull.get(); }
+
+ @Override
+ public void forEachChild(Function<ConfigNode, Boolean> fun) { }
+ } ;
+ SimpleMap<String> empty_attrs = new WrappedSimpleMap<>(Collections.emptyMap());
+
+ public class Helpers {
+ static boolean __bool(Object v, boolean def) { return v == null ? def : Boolean.parseBoolean(v.toString()); }
+ static String __txt(Object v, String def) { return v == null ? def : v.toString(); }
+ static int __int(Object v, int def) { return v==null? def: Integer.parseInt(v.toString()); }
+ static double __double(Object v, double def) { return v == null ? def: Double.parseDouble(v.toString()); }
+ public static Predicate<ConfigNode> at(int i) {
+ return new Predicate<ConfigNode>() {
+ int index =0;
+ @Override
+ public boolean test(ConfigNode node) {
+ if(index == i) return true;
+ index++;
+ return false;
+ }
+ };
+ }
+
+
+ }
}
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 e8f58a5..e8689d2 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
@@ -19,6 +19,7 @@ package org.apache.solr.common.util;
import org.apache.solr.cluster.api.SimpleMap;
+import java.util.Collections;
import java.util.Map;
import java.util.function.BiConsumer;
@@ -46,4 +47,8 @@ public class WrappedSimpleMap<T> implements SimpleMap<T> {
this.delegate = delegate;
}
+ @Override
+ public Map<String, T> asMap() {
+ return Collections.unmodifiableMap(delegate);
+ }
}