diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java b/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java index f94722b08ce..cd7fd75ea41 100644 --- a/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java +++ b/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java @@ -190,7 +190,7 @@ public class ZkCLI { if (isXml) { cfg = new ConfigSolrXmlBackCompat(loader, null, is, null, false); } else { - cfg = new SolrProperties(null, is, null); + cfg = new SolrProperties(null, loader, is, null); } } finally { IOUtils.closeQuietly(is); diff --git a/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlBackCompat.java b/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlBackCompat.java index 5a207e72e65..413c892ff13 100644 --- a/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlBackCompat.java +++ b/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlBackCompat.java @@ -25,6 +25,7 @@ import org.apache.solr.schema.IndexSchema; import org.apache.solr.util.DOMUtil; import org.apache.solr.util.PropertiesUtil; import org.apache.solr.util.SystemIdResolver; +import org.apache.solr.util.plugin.PluginInfoInitialized; import org.apache.zookeeper.KeeperException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -132,9 +133,16 @@ public class ConfigSolrXmlBackCompat extends Config implements ConfigSolr { m.put("class", HttpShardHandlerFactory.class.getName()); info = new PluginInfo("shardHandlerFactory", m, null, Collections.emptyList()); } - HttpShardHandlerFactory fac = new HttpShardHandlerFactory(); - if (info != null) { - fac.init(info); + + ShardHandlerFactory fac; + try { + fac = getResourceLoader().findClass(info.className, ShardHandlerFactory.class).newInstance(); + } catch (Exception e) { + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, + "Error instantiating shardHandlerFactory class " + info.className); + } + if (fac instanceof PluginInfoInitialized) { + ((PluginInfoInitialized) fac).init(info); } return fac; } 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 7ecc01aab7d..06139e81594 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -377,7 +377,7 @@ public class CoreContainer cfg = new ConfigSolrXmlBackCompat(loader, null, is, null, false); this.cfg = new ConfigSolrXmlBackCompat(loader, (ConfigSolrXmlBackCompat)cfg); } else { - cfg = new SolrProperties(this, is, fileName); + cfg = new SolrProperties(this, loader, is, fileName); this.cfg = new SolrProperties(this, loader, (SolrProperties)cfg); } } catch (Exception e) { diff --git a/solr/core/src/java/org/apache/solr/core/SolrProperties.java b/solr/core/src/java/org/apache/solr/core/SolrProperties.java index 42aad794e51..309b4324544 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrProperties.java +++ b/solr/core/src/java/org/apache/solr/core/SolrProperties.java @@ -27,6 +27,7 @@ import org.apache.solr.handler.component.ShardHandlerFactory; import org.apache.solr.schema.IndexSchema; import org.apache.solr.util.PropertiesUtil; import org.apache.solr.util.SystemIdResolver; +import org.apache.solr.util.plugin.PluginInfoInitialized; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,13 +105,15 @@ public class SolrProperties implements ConfigSolr { * Create a SolrProperties object from an opened input stream, useful for creating defaults * * @param container - the container for this Solr instance. There should be one and only one... + * @param loader - Solr resource loader * @param is - Input stream for loading properties. * @param fileName - the name for this properties object. * @throws IOException - It's possible to walk a very deep tree, if that process goes awry, or if reading any * of the files found doesn't work, you'll get an IO exception */ - public SolrProperties(CoreContainer container, InputStream is, String fileName) throws IOException { + public SolrProperties(CoreContainer container, SolrResourceLoader loader, InputStream is, String fileName) throws IOException { origsolrprops.load(is); + this.loader = loader; this.container = container; init(fileName); } @@ -241,29 +244,39 @@ public class SolrProperties implements ConfigSolr { boolean haveHandler = false; for (String s : solrProperties.stringPropertyNames()) { String val = solrProperties.getProperty(s); - if (s.indexOf(SHARD_HANDLER_FACTORY) != -1) { + int index = s.indexOf(SHARD_HANDLER_FACTORY); + if (index != -1) { haveHandler = true; if (SHARD_HANDLER_NAME.equals(s) || SHARD_HANDLER_CLASS.equals(s)) { - attrs.put(s, val); + // remove shardHandlerFactory. prefix + attrs.put(s.substring(SHARD_HANDLER_FACTORY.length()+1), val); } else { - args.add(s, val); + // remove shardHandlerFactory. prefix + args.add(s.substring(SHARD_HANDLER_FACTORY.length()+1), val); } } } if (haveHandler) { - // public PluginInfo(String type, Map attrs ,NamedList initArgs, List children) { - info = new PluginInfo(SHARD_HANDLER_FACTORY, attrs, args, null); } else { Map m = new HashMap(); m.put("class", HttpShardHandlerFactory.class.getName()); info = new PluginInfo("shardHandlerFactory", m, null, Collections.emptyList()); } - HttpShardHandlerFactory fac = new HttpShardHandlerFactory(); - if (info != null) { - fac.init(info); + + assert loader != null; + ShardHandlerFactory fac; + try { + fac = loader.findClass(info.className, ShardHandlerFactory.class).newInstance(); + } catch (Exception e) { + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, + "Error instantiating shardHandlerFactory class " + info.className); } + if (fac instanceof PluginInfoInitialized) { + ((PluginInfoInitialized) fac).init(info); + } + return fac; } diff --git a/solr/core/src/test-files/solr/solr-shardhandler.properties b/solr/core/src/test-files/solr/solr-shardhandler.properties new file mode 100644 index 00000000000..664a79ae742 --- /dev/null +++ b/solr/core/src/test-files/solr/solr-shardhandler.properties @@ -0,0 +1,18 @@ +# 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. +# solr.properties specifying a custom shard handler factory +shardHandlerFactory.name=shardHandlerFactory +shardHandlerFactory.class=org.apache.solr.core.MockShardHandlerFactory +shardHandlerFactory.myMagicRequiredParameter=myMagicRequiredValue diff --git a/solr/core/src/test-files/solr/solr-shardhandler.xml b/solr/core/src/test-files/solr/solr-shardhandler.xml new file mode 100644 index 00000000000..246ce581e36 --- /dev/null +++ b/solr/core/src/test-files/solr/solr-shardhandler.xml @@ -0,0 +1,29 @@ + + + + + + + + myMagicRequiredValue + + + diff --git a/solr/core/src/test/org/apache/solr/core/MockShardHandlerFactory.java b/solr/core/src/test/org/apache/solr/core/MockShardHandlerFactory.java new file mode 100644 index 00000000000..289111db439 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/core/MockShardHandlerFactory.java @@ -0,0 +1,65 @@ +package org.apache.solr.core; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.handler.component.ResponseBuilder; +import org.apache.solr.handler.component.ShardHandler; +import org.apache.solr.handler.component.ShardHandlerFactory; +import org.apache.solr.handler.component.ShardRequest; +import org.apache.solr.handler.component.ShardResponse; +import org.apache.solr.util.plugin.PluginInfoInitialized; + +/** a fake shardhandler factory that does nothing. */ +public class MockShardHandlerFactory extends ShardHandlerFactory implements PluginInfoInitialized { + NamedList args; + + @Override + public void init(PluginInfo info) { + args = info.initArgs; + } + + @Override + public ShardHandler getShardHandler() { + return new ShardHandler() { + @Override + public void checkDistributed(ResponseBuilder rb) {} + + @Override + public void submit(ShardRequest sreq, String shard, + ModifiableSolrParams params) {} + + @Override + public ShardResponse takeCompletedIncludingErrors() { + return null; + } + + @Override + public ShardResponse takeCompletedOrError() { + return null; + } + + @Override + public void cancelAll() {} + }; + } + + @Override + public void close() {} +} diff --git a/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java b/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java new file mode 100644 index 00000000000..3f5865f232a --- /dev/null +++ b/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java @@ -0,0 +1,52 @@ +/* + * 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 org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.handler.component.ShardHandlerFactory; + +import java.io.File; + +/** + * Tests specifying a custom ShardHandlerFactory + */ +public class TestShardHandlerFactory extends SolrTestCaseJ4 { + + public void testXML() throws Exception { + CoreContainer cc = new CoreContainer(TEST_HOME()); + cc.load(TEST_HOME(), new File(TEST_HOME(), "solr-shardhandler.xml")); + ShardHandlerFactory factory = cc.getShardHandlerFactory(); + assertTrue(factory instanceof MockShardHandlerFactory); + NamedList args = ((MockShardHandlerFactory)factory).args; + assertEquals("myMagicRequiredValue", args.get("myMagicRequiredParameter")); + factory.close(); + cc.shutdown(); + } + + public void testProperties() throws Exception { + CoreContainer cc = new CoreContainer(TEST_HOME()); + cc.load(TEST_HOME(), new File(TEST_HOME(), "solr-shardhandler.properties")); + ShardHandlerFactory factory = cc.getShardHandlerFactory(); + assertTrue(factory instanceof MockShardHandlerFactory); + NamedList args = ((MockShardHandlerFactory)factory).args; + assertEquals("myMagicRequiredValue", args.get("myMagicRequiredParameter")); + factory.close(); + cc.shutdown(); + } +}