SOLR-5028,SOLR-5029: Fix ShardHandlerFactory creation and persistence

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1502231 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alan Woodward 2013-07-11 14:15:35 +00:00
parent 748cb61e82
commit 417f1ba3b4
16 changed files with 172 additions and 114 deletions

View File

@ -294,6 +294,10 @@ Bug Fixes
* SOLR-5018: The Overseer should avoid publishing the state for collections that do not
exist under the /collections zk node. (Mark Miller)
* SOLR-5028,SOLR-5029: ShardHandlerFactory was not being created properly when
using new-style solr.xml, and was not being persisted properly when using
old-style. (Tomás Fernández Löbbe, Ryan Ernst, Alan Woodward)
Optimizations
----------------------

View File

@ -224,7 +224,15 @@ public class Config {
}
}
public Node getNode(String path, boolean errIfMissing) {
public Node getNode(String path, boolean errifMissing) {
return getNode(path, doc, errifMissing);
}
public Node getUnsubstitutedNode(String path, boolean errIfMissing) {
return getNode(path, origDoc, errIfMissing);
}
public Node getNode(String path, Document doc, boolean errIfMissing) {
XPath xpath = xpathFactory.newXPath();
Node nd = null;
String xstr = normalize(path);

View File

@ -95,6 +95,18 @@ public abstract class ConfigSolr {
: new ConfigSolrXml(config, null);
}
public PluginInfo getShardHandlerFactoryPluginInfo() {
Node node = config.getNode(getShardHandlerFactoryConfigPath(), false);
return (node == null) ? null : new PluginInfo(node, "shardHandlerFactory", false, true);
}
public Node getUnsubsititutedShardHandlerFactoryPluginNode() {
return config.getUnsubstitutedNode(getShardHandlerFactoryConfigPath(), false);
}
protected abstract String getShardHandlerFactoryConfigPath();
// Ugly for now, but we'll at least be able to centralize all of the differences between 4x and 5x.
public static enum CfgProp {
SOLR_ADMINHANDLER,
@ -112,10 +124,6 @@ public abstract class ConfigSolr {
SOLR_LOGGING_WATCHER_THRESHOLD,
SOLR_MANAGEMENTPATH,
SOLR_SHAREDLIB,
SOLR_SHARDHANDLERFACTORY_CLASS,
SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT,
SOLR_SHARDHANDLERFACTORY_NAME,
SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT,
SOLR_SHARESCHEMA,
SOLR_TRANSIENTCACHESIZE,
SOLR_GENERICCORENODENAMES,
@ -133,6 +141,7 @@ public abstract class ConfigSolr {
public ConfigSolr(Config config) {
this.config = config;
}
// for extension & testing.

View File

@ -131,10 +131,6 @@ public class ConfigSolrXml extends ConfigSolr {
propMap.put(CfgProp.SOLR_LOGGING_ENABLED, doSub("solr/logging/str[@name='enabled']"));
propMap.put(CfgProp.SOLR_LOGGING_WATCHER_SIZE, doSub("solr/logging/watcher/int[@name='size']"));
propMap.put(CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, doSub("solr/logging/watcher/int[@name='threshold']"));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS, doSub("solr/shardHandlerFactory/@class"));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_NAME, doSub("solr/shardHandlerFactory/@name"));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT, doSub("solr/shardHandlerFactory/int[@name='connTimeout']"));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, doSub("solr/shardHandlerFactory/int[@name='socketTimeout']"));
}
@ -191,6 +187,11 @@ public class ConfigSolrXml extends ConfigSolr {
return p;
}
@Override
protected String getShardHandlerFactoryConfigPath() {
return "solr/shardHandlerFactory";
}
@Override
public void substituteProperties() {
config.substituteProperties();

View File

@ -48,6 +48,11 @@ public class ConfigSolrXmlOld extends ConfigSolr {
private NodeList coreNodes = null;
@Override
protected String getShardHandlerFactoryConfigPath() {
return "solr/cores/shardHandlerFactory";
}
public ConfigSolrXmlOld(Config config) {
super(config);
try {
@ -136,15 +141,7 @@ public class ConfigSolrXmlOld extends ConfigSolr {
config.getVal("solr/cores/@transientCacheSize", false));
propMap.put(CfgProp.SOLR_ZKCLIENTTIMEOUT,
config.getVal("solr/cores/@zkClientTimeout", false));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS,
config.getVal("solr/shardHandlerFactory/@class", false));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_NAME,
config.getVal("solr/shardHandlerFactory/@name", false));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT,
config.getVal("solr/shardHandlerFactory/int[@name='connTimeout']", false));
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT,
config.getVal("solr/shardHandlerFactory/int[@name='socketTimeout']", false));
// These have no counterpart in 5.0, asking, for any of these in Solr 5.0
// will result in an error being
// thrown.

View File

@ -26,7 +26,6 @@ import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.handler.admin.CollectionsHandler;
import org.apache.solr.handler.admin.CoreAdminHandler;
import org.apache.solr.handler.admin.InfoHandler;
import org.apache.solr.handler.component.HttpShardHandlerFactory;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.logging.LogWatcher;
import org.apache.solr.logging.jul.JulWatcher;
@ -35,14 +34,11 @@ import org.apache.solr.schema.IndexSchemaFactory;
import org.apache.solr.util.DefaultSolrThreadFactory;
import org.apache.solr.util.FileUtils;
import org.apache.solr.util.PropertiesUtil;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Collection;
@ -207,7 +203,7 @@ public class CoreContainer
loader.reloadLuceneSPI();
}
shardHandlerFactory = initShardHandler(cfg);
shardHandlerFactory = ShardHandlerFactory.newInstance(cfg.getShardHandlerFactoryPluginInfo(), loader);
solrCores.allocateLazyCores(cfg, loader);
@ -430,42 +426,6 @@ public class CoreContainer
}
}
}
private ShardHandlerFactory initShardHandler(ConfigSolr configSolr) {
PluginInfo info = null;
Node shfn = configSolr.getConfig().getNode("solr/cores/shardHandlerFactory", false);
if (shfn != null) {
info = new PluginInfo(shfn, "shardHandlerFactory", false, true);
} else {
Map m = new HashMap();
m.put("class", HttpShardHandlerFactory.class.getName());
info = new PluginInfo("shardHandlerFactory", m, null, Collections.<PluginInfo>emptyList());
}
ShardHandlerFactory fac;
try {
fac = configSolr.getConfig().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;
}
// To make this available to TestHarness.
protected void initShardHandler() {
if (cfg != null) {
initShardHandler(cfg);
} else {
// Cough! Hack! But tests run this way.
HttpShardHandlerFactory fac = new HttpShardHandlerFactory();
shardHandlerFactory = fac;
}
}
private volatile boolean isShutDown = false;
@ -1109,6 +1069,7 @@ public class CoreContainer
cfg.get(ConfigSolr.CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, null));
/*
Map<String, String> shardHandlerAttrib = new HashMap<String, String>();
addAttrib(shardHandlerAttrib, ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS, "class",
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS, null));
@ -1120,10 +1081,11 @@ public class CoreContainer
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT, null));
addAttrib(shardHandlerProps, ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, "socketTimeout",
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, null));
*/
try {
solrCores.persistCores(cfg.config.getOriginalConfig(), containerProperties, rootSolrAttribs,coresAttribs,
loggingAttribs, watcherAttribs, shardHandlerAttrib, shardHandlerProps, file, loader);
loggingAttribs, watcherAttribs, cfg.getUnsubsititutedShardHandlerFactoryPluginNode(), file, loader);
} catch (XPathExpressionException e) {
throw new SolrException(ErrorCode.SERVER_ERROR, null, e);
}

View File

@ -328,7 +328,7 @@ class SolrCores {
public void persistCores(Config cfg, Properties containerProperties,
Map<String,String> rootSolrAttribs, Map<String,String> coresAttribs,
Map<String, String> loggingAttribs, Map<String,String> watcherAttribs,
Map<String, String> shardHandlerAttrib, Map<String,String> shardHandlerProps,
Node shardHandlerNode,
File file, SolrResourceLoader loader) throws XPathExpressionException {
@ -361,8 +361,7 @@ class SolrCores {
solrXMLDef.coresAttribs = coresAttribs;
solrXMLDef.loggingAttribs = loggingAttribs;
solrXMLDef.watcherAttribs = watcherAttribs;
solrXMLDef.shardHandlerAttribs = shardHandlerAttrib;
solrXMLDef.shardHandlerProps = shardHandlerProps;
solrXMLDef.shardHandlerNode = shardHandlerNode;
SOLR_XML_SERIALIZER.persistFile(file, solrXMLDef);
}

View File

@ -21,13 +21,20 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.channels.FileChannel;
import java.util.List;
@ -81,22 +88,6 @@ public class SolrXMLSerializer {
w.write(INDENT + "</logging>\n");
}
// Output shard handler section if any
if (solrXMLDef.shardHandlerAttribs.size() > 0 || solrXMLDef.shardHandlerProps.size() > 0) {
w.write(INDENT + "<shardHandlerFactory");
for (Map.Entry<String, String> ent : solrXMLDef.shardHandlerAttribs.entrySet()) {
writeAttribute(w, ent.getKey(), ent.getValue());
}
w.write(">\n");
if (solrXMLDef.shardHandlerProps.size() > 0) {
for (Map.Entry<String, String> ent : solrXMLDef.shardHandlerProps.entrySet()) {
w.write(INDENT + INDENT + "<int name=\"" + ent.getKey() + "\"" + ">" + ent.getValue() + "</int>\n");
}
}
w.write(INDENT + "</shardHandlerFactory>\n");
}
w.write(INDENT + "<cores");
Map<String,String> coresAttribs = solrXMLDef.coresAttribs;
Set<String> coreAttribKeys = coresAttribs.keySet();
@ -110,9 +101,28 @@ public class SolrXMLSerializer {
persist(w, coreDef);
}
// Shard handler section
if (solrXMLDef.shardHandlerNode != null) {
w.write(nodeToXML(solrXMLDef.shardHandlerNode));
}
w.write(INDENT + "</cores>\n");
w.write("</solr>\n");
}
private String nodeToXML(Node node) {
try {
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer tx = tfactory.newTransformer();
StringWriter buffer = new StringWriter();
tx.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
tx.transform(new DOMSource(node), new StreamResult(buffer));
return buffer.toString();
}
catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error transforming XML: " + e.getMessage());
}
}
/** Writes the cores configuration node for a given core. */
private void persist(Writer w, SolrCoreXMLDef coreDef) throws IOException {
@ -235,8 +245,7 @@ public class SolrXMLSerializer {
Map<String,String> coresAttribs;
Map<String, String> loggingAttribs;
Map<String, String> watcherAttribs;
Map<String, String> shardHandlerAttribs;
Map<String, String> shardHandlerProps;
Node shardHandlerNode;
List<SolrCoreXMLDef> coresDefs;
}

View File

@ -17,9 +17,48 @@ package org.apache.solr.handler.component;
*/
import com.google.common.collect.ImmutableMap;
import org.apache.solr.common.SolrException;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import java.util.Collections;
import java.util.Locale;
public abstract class ShardHandlerFactory {
public abstract ShardHandler getShardHandler();
public abstract void close();
/**
* Create a new ShardHandlerFactory instance
* @param info a PluginInfo object defining which type to create. If null,
* the default {@link HttpShardHandlerFactory} will be used
* @param loader a SolrResourceLoader used to find the ShardHandlerFactory classes
* @return a new, initialized ShardHandlerFactory instance
*/
public static ShardHandlerFactory newInstance(PluginInfo info, SolrResourceLoader loader) {
if (info == null)
info = DEFAULT_SHARDHANDLER_INFO;
try {
ShardHandlerFactory shf = loader.findClass(info.className, ShardHandlerFactory.class).newInstance();
if (PluginInfoInitialized.class.isAssignableFrom(shf.getClass()))
PluginInfoInitialized.class.cast(shf).init(info);
return shf;
}
catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
String.format(Locale.ROOT, "Error instantiating shardHandlerFactory class [%s]: %s",
info.className, e.getMessage()));
}
}
public static final PluginInfo DEFAULT_SHARDHANDLER_INFO =
new PluginInfo("shardHandlerFactory", ImmutableMap.of("class", HttpShardHandlerFactory.class.getName()),
null, Collections.<PluginInfo>emptyList());
}

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
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.
-->
<!--
old-style solr.xml specifying a custom shardHandlerFactory
-->
<solr>
<cores>
<shardHandlerFactory name="shardHandlerFactory"
class="org.apache.solr.core.MockShardHandlerFactory">
<str name="myMagicRequiredParameter">myMagicRequiredValue</str>
</shardHandlerFactory>
</cores>
</solr>

View File

@ -20,10 +20,10 @@
solr.xml specifying a custom shardHandlerFactory
-->
<solr>
<cores>
<shardHandlerFactory name="shardHandlerFactory"
class="org.apache.solr.core.MockShardHandlerFactory">
<str name="myMagicRequiredParameter">myMagicRequiredValue</str>
</shardHandlerFactory>
</cores>
</solr>

View File

@ -37,4 +37,14 @@ public class TestShardHandlerFactory extends SolrTestCaseJ4 {
factory.close();
cc.shutdown();
}
public void testOldXML() throws Exception {
CoreContainer cc = CoreContainer.createAndLoad(TEST_HOME(), new File(TEST_HOME(), "solr-shardhandler-old.xml"));
ShardHandlerFactory factory = cc.getShardHandlerFactory();
assertTrue(factory instanceof MockShardHandlerFactory);
NamedList args = ((MockShardHandlerFactory)factory).args;
assertEquals("myMagicRequiredValue", args.get("myMagicRequiredParameter"));
factory.close();
cc.shutdown();
}
}

View File

@ -17,6 +17,23 @@ package org.apache.solr.core;
* limitations under the License.
*/
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util._TestUtil;
import org.apache.solr.core.SolrXMLSerializer.SolrCoreXMLDef;
import org.apache.solr.core.SolrXMLSerializer.SolrXMLDef;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
@ -29,24 +46,6 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util._TestUtil;
import org.apache.solr.core.SolrXMLSerializer.SolrCoreXMLDef;
import org.apache.solr.core.SolrXMLSerializer.SolrXMLDef;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TestSolrXMLSerializer extends LuceneTestCase {
private static final XPathFactory xpathFactory = XPathFactory.newInstance();
@ -144,8 +143,6 @@ public class TestSolrXMLSerializer extends LuceneTestCase {
solrXMLDef.solrAttribs = rootSolrAttribs;
solrXMLDef.coresAttribs = coresAttribs;
solrXMLDef.loggingAttribs = new HashMap<String, String>();
solrXMLDef.shardHandlerProps = new HashMap<String, String>();
solrXMLDef.shardHandlerAttribs = new HashMap<String, String>();
solrXMLDef.loggingAttribs = new HashMap<String, String>();
solrXMLDef.watcherAttribs = new HashMap<String, String>();
return solrXMLDef;

View File

@ -64,10 +64,6 @@ public class TestSolrXml extends SolrTestCaseJ4 {
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, 0), 99);
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_MANAGEMENTPATH, null), "testManagementPath");
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHAREDLIB, null), "testSharedLib");
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS, null), "testHttpShardHandlerFactory");
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT, 0), 110);
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_NAME, null), "testShardHandlerFactory");
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, 0), 100);
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHARESCHEMA, null), "testShareSchema");
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_TRANSIENTCACHESIZE, 0), 66);
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_ZKCLIENTTIMEOUT, 0), 77);
@ -109,8 +105,6 @@ public class TestSolrXml extends SolrTestCaseJ4 {
}
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_COREROOTDIRECTORY, null), "myCoreRoot");
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_HOSTPORT, 0), 8888);
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT, 0), 200);
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, 0), 220);
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHARESCHEMA, null), "newShareSchema");
} finally {

View File

@ -600,10 +600,6 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
" <logging class=\"${logclass:log4j.class}\" enabled=\"{logenable:true}\">\n" +
" <watcher size=\"{watchSize:13}\" threshold=\"${logThresh:54}\" />\n" +
" </logging>\n" +
" <shardHandlerFactory name=\"${shhandler:shardHandlerFactory}\" class=\"${handlefac:HttpShardHandlerFactory}\">\n" +
" <int name=\"socketTimeout\">${socketTimeout:120000}</int> \n" +
" <int name=\"connTimeout\">${connTimeout:15000}</int> \n" +
" </shardHandlerFactory> \n" +
" <cores adminPath=\"/admin/cores\" defaultCoreName=\"SystemVars1\" host=\"127.0.0.1\" \n" +
" hostPort=\"${hostPort:8983}\" hostContext=\"${hostContext:solr}\" \n" +
" zkClientTimeout=\"${solr.zkclienttimeout:30000}\" \n" +
@ -624,6 +620,11 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
" <property name=\"schema\" value=\"${schema:schema.xml}\"/>\n" +
" <property name=\"coreNodeName\" value=\"EricksCore\"/>\n" +
" </core>\n" +
" <shardHandlerFactory name=\"${shhandler:shardHandlerFactory}\" class=\"${handlefac:HttpShardHandlerFactory}\">\n" +
" <int name=\"socketTimeout\">${socketTimeout:120000}</int> \n" +
" <int name=\"connTimeout\">${connTimeout:15000}</int> \n" +
" <str name=\"arbitraryName\">${arbitrarySysValue:foobar}</str>\n" +
" </shardHandlerFactory> \n" +
" </cores>\n" +
"</solr>";

View File

@ -76,7 +76,6 @@ import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;