From fe875669cb7b64e16a54c9d3f9642ae5ed6f70a5 Mon Sep 17 00:00:00 2001 From: Vincent Primault Date: Mon, 4 Sep 2023 15:21:16 +0200 Subject: [PATCH] SOLR-16959: Make CoresContainer class configurable --- .../org/apache/solr/core/CoreContainer.java | 11 ++-- .../org/apache/solr/core/CoresLocator.java | 23 ++++++++ .../java/org/apache/solr/core/NodeConfig.java | 14 +++++ .../org/apache/solr/core/SolrXmlConfig.java | 3 ++ .../apache/solr/core/CoresLocatorTest.java | 54 +++++++++++++++++++ .../pages/configuring-solr-xml.adoc | 12 +++++ .../org/apache/solr/util/NoCoresLocator.java | 40 ++++++++++++++ 7 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 solr/core/src/test/org/apache/solr/core/CoresLocatorTest.java create mode 100644 solr/test-framework/src/java/org/apache/solr/util/NoCoresLocator.java diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 0bc9ad59d27..ba66dae7b4d 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -377,21 +377,24 @@ public CoreContainer(Path solrHome, Properties properties) { * @see #load() */ public CoreContainer(NodeConfig config) { - this(config, new CorePropertiesLocator(config.getCoreRootDirectory())); + this(config, CoresLocator.instantiate(config)); } public CoreContainer(NodeConfig config, boolean asyncSolrCoreLoad) { - this(config, new CorePropertiesLocator(config.getCoreRootDirectory()), asyncSolrCoreLoad); + this(config, CoresLocator.instantiate(config), asyncSolrCoreLoad); } /** - * Create a new CoreContainer using the given configuration and locator. The container's cores are - * not loaded. + * Create a new CoreContainer using the given configuration and locator. + * + *

The container's cores are not loaded. This constructor should be used only in tests, as it + * overrides {@link CoresLocator}'s instantiation process. * * @param config a ConfigSolr representation of this container's configuration * @param locator a CoresLocator * @see #load() */ + @VisibleForTesting public CoreContainer(NodeConfig config, CoresLocator locator) { this(config, locator, false); } diff --git a/solr/core/src/java/org/apache/solr/core/CoresLocator.java b/solr/core/src/java/org/apache/solr/core/CoresLocator.java index 10eac005230..c99c348fada 100644 --- a/solr/core/src/java/org/apache/solr/core/CoresLocator.java +++ b/solr/core/src/java/org/apache/solr/core/CoresLocator.java @@ -16,6 +16,7 @@ */ package org.apache.solr.core; +import java.lang.reflect.Constructor; import java.util.List; /** Manage the discovery and persistence of core definitions across Solr restarts */ @@ -72,4 +73,26 @@ public interface CoresLocator { * @return a list of all CoreDescriptors found */ public List discover(CoreContainer cc); + + /** + * Returns a new instance of {@link CoresLocator}, depending on provided config. + * + * @param nodeConfig Solr configuration. + */ + static CoresLocator instantiate(NodeConfig nodeConfig) { + final String coresLocatorClass = nodeConfig.getCoresLocatorClass(); + if (coresLocatorClass != null) { + try { + Class clazz = + nodeConfig.getSolrResourceLoader().findClass(coresLocatorClass, CoresLocator.class); + Constructor constructor = clazz.getConstructor(NodeConfig.class); + return constructor.newInstance(nodeConfig); + } catch (Exception e) { + throw new RuntimeException( + "create CoresLocator instance failed, coresLocatorClass=" + coresLocatorClass, e); + } + } else { + return new CorePropertiesLocator(nodeConfig.getCoreRootDirectory()); + } + } } diff --git a/solr/core/src/java/org/apache/solr/core/NodeConfig.java b/solr/core/src/java/org/apache/solr/core/NodeConfig.java index 581a2d07c0a..1fa300dff28 100644 --- a/solr/core/src/java/org/apache/solr/core/NodeConfig.java +++ b/solr/core/src/java/org/apache/solr/core/NodeConfig.java @@ -79,6 +79,7 @@ public class NodeConfig { private final UpdateShardHandlerConfig updateShardHandlerConfig; private final String configSetServiceClass; + private final String coresLocatorClass; private final String coreAdminHandlerClass; @@ -154,6 +155,7 @@ private NodeConfig( Set allowPaths, List allowUrls, String configSetServiceClass, + String coresLocatorClass, String modules, Set hiddenSysProps) { // all Path params here are absolute and normalized. @@ -190,6 +192,7 @@ private NodeConfig( this.allowPaths = allowPaths; this.allowUrls = allowUrls; this.configSetServiceClass = configSetServiceClass; + this.coresLocatorClass = coresLocatorClass; this.modules = modules; this.hiddenSysProps = hiddenSysProps; this.hiddenSysPropPattern = @@ -258,6 +261,10 @@ public String getConfigSetServiceClass() { return this.configSetServiceClass; } + public String getCoresLocatorClass() { + return this.coresLocatorClass; + } + public String getNodeName() { return nodeName; } @@ -593,6 +600,7 @@ public static class NodeConfigBuilder { private PluginInfo shardHandlerFactoryConfig; private UpdateShardHandlerConfig updateShardHandlerConfig = UpdateShardHandlerConfig.DEFAULT; private String configSetServiceClass; + private String coresLocatorClass; private String coreAdminHandlerClass = DEFAULT_ADMINHANDLERCLASS; private Map coreAdminHandlerActions = Collections.emptyMap(); private String collectionsAdminHandlerClass = DEFAULT_COLLECTIONSHANDLERCLASS; @@ -814,6 +822,11 @@ public NodeConfigBuilder setConfigSetServiceClass(String configSetServiceClass) return this; } + public NodeConfigBuilder setCoresLocatorClass(String coresLocatorClass) { + this.coresLocatorClass = coresLocatorClass; + return this; + } + /** * Set list of modules to add to class path * @@ -903,6 +916,7 @@ public NodeConfig build() { allowPaths, allowUrls, configSetServiceClass, + coresLocatorClass, modules, resolveHiddenSysPropsFromSysPropOrEnvOrDefault(hiddenSysProps)); } diff --git a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java index 85fbaeeb193..c2dbca44f98 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java +++ b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java @@ -348,6 +348,9 @@ private static NodeConfig fillSolrSection(NodeConfig.NodeConfigBuilder builder, case "configSetService": builder.setConfigSetServiceClass(it.txt()); break; + case "coresLocator": + builder.setCoresLocatorClass(it.txt()); + break; case "coreRootDirectory": builder.setCoreRootDirectory(it.txt()); break; diff --git a/solr/core/src/test/org/apache/solr/core/CoresLocatorTest.java b/solr/core/src/test/org/apache/solr/core/CoresLocatorTest.java new file mode 100644 index 00000000000..d004883818f --- /dev/null +++ b/solr/core/src/test/org/apache/solr/core/CoresLocatorTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.solr.core; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.apache.solr.util.NoCoresLocator; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +/** Unit tests for {@link CoresLocator}. */ +public class CoresLocatorTest { + + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void testInstantiateDefaultCoresLocator() throws Exception { + String solrXml = ""; + NodeConfig nodeConfig = SolrXmlConfig.fromString(temporaryFolder.newFolder().toPath(), solrXml); + CoresLocator coresLocator = CoresLocator.instantiate(nodeConfig); + + assertTrue(coresLocator instanceof CorePropertiesLocator); + } + + @Test + public void testInstantiateCustomCoresLocator() throws Exception { + String solrXml = + "\n" + + "\n" + + "org.apache.solr.util.NoCoresLocator\n" + + ""; + NodeConfig nodeConfig = SolrXmlConfig.fromString(temporaryFolder.newFolder().toPath(), solrXml); + CoresLocator coresLocator = CoresLocator.instantiate(nodeConfig); + + assertTrue(coresLocator instanceof NoCoresLocator); + assertSame(nodeConfig, ((NoCoresLocator) coresLocator).getNodeConfig()); + } +} diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/configuring-solr-xml.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/configuring-solr-xml.adoc index 66fa7f8dc76..815fe6111b5 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/configuring-solr-xml.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/configuring-solr-xml.adoc @@ -99,6 +99,18 @@ For example, `com.myorg.CustomConfigSetServicecom.myorg.CustomCoresLocator`. + `adminHandler`:: + [%autowidth,frame=none] diff --git a/solr/test-framework/src/java/org/apache/solr/util/NoCoresLocator.java b/solr/test-framework/src/java/org/apache/solr/util/NoCoresLocator.java new file mode 100644 index 00000000000..4304078233c --- /dev/null +++ b/solr/test-framework/src/java/org/apache/solr/util/NoCoresLocator.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.solr.util; + +import java.util.List; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.core.CoreDescriptor; +import org.apache.solr.core.NodeConfig; + +/** A {@link org.apache.solr.core.CoresLocator} that locates no cores. */ +public class NoCoresLocator extends ReadOnlyCoresLocator { + private final NodeConfig nodeConfig; + + public NoCoresLocator(NodeConfig nodeConfig) { + this.nodeConfig = nodeConfig; + } + + public NodeConfig getNodeConfig() { + return nodeConfig; + } + + @Override + public List discover(CoreContainer cc) { + return List.of(); + } +}