| 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 javax.xml.xpath.XPath; |
| import javax.xml.xpath.XPathConstants; |
| import javax.xml.xpath.XPathExpressionException; |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.InputStream; |
| import java.nio.charset.StandardCharsets; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.apache.solr.cloud.CloudConfigSetService; |
| import org.apache.solr.cloud.ZkController; |
| import org.apache.solr.common.SolrException; |
| import org.apache.solr.logging.LogWatcherConfig; |
| import org.apache.solr.util.DOMUtil; |
| import org.apache.solr.util.PropertiesUtil; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.InputSource; |
| |
| |
| public abstract class ConfigSolr { |
| protected static Logger log = LoggerFactory.getLogger(ConfigSolr.class); |
| |
| public final static String SOLR_XML_FILE = "solr.xml"; |
| |
| public static ConfigSolr fromFile(SolrResourceLoader loader, File configFile) { |
| log.info("Loading container configuration from {}", configFile.getAbsolutePath()); |
| |
| InputStream inputStream = null; |
| |
| try { |
| |
| // 4x specific behavior, removed in 5.0... |
| // if configFile doesn't exist, and we aren't in cloud mode, use old style default |
| if (!configFile.exists()) { |
| if (ZkContainer.isZkMode()) { |
| throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, |
| "solr.xml does not exist in " + configFile.getAbsolutePath() + " cannot start Solr"); |
| } |
| log.info("{} does not exist, using default configuration", configFile.getAbsolutePath()); |
| inputStream = new ByteArrayInputStream(ConfigSolrXmlOld.DEF_SOLR_XML.getBytes(StandardCharsets.UTF_8)); |
| } else { |
| inputStream = new FileInputStream(configFile); |
| } |
| return fromInputStream(loader, inputStream); |
| |
| } catch (SolrException exc) { |
| throw exc; |
| } catch (Exception e) { |
| throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, |
| "Could not load SOLR configuration", e); |
| } |
| finally { |
| IOUtils.closeQuietly(inputStream); |
| } |
| } |
| |
| public static ConfigSolr fromString(SolrResourceLoader loader, String xml) { |
| return fromInputStream(loader, new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); |
| } |
| |
| public static ConfigSolr fromInputStream(SolrResourceLoader loader, InputStream is) { |
| try { |
| byte[] buf = IOUtils.toByteArray(is); |
| String originalXml = new String(buf, StandardCharsets.UTF_8); |
| try (ByteArrayInputStream dup = new ByteArrayInputStream(buf)) { |
| Config config = new Config(loader, null, new InputSource(dup), null, false); |
| return fromConfig(config, originalXml); |
| } |
| } catch (SolrException exc) { |
| throw exc; |
| } catch (Exception e) { |
| throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); |
| } |
| } |
| |
| public static ConfigSolr fromSolrHome(SolrResourceLoader loader, String solrHome) { |
| return fromFile(loader, new File(solrHome, SOLR_XML_FILE)); |
| } |
| |
| public static ConfigSolr fromConfig(Config config, String originalXml) { |
| boolean oldStyle = (config.getNode("solr/cores", false) != null); |
| return oldStyle ? new ConfigSolrXmlOld(config, originalXml) |
| : new ConfigSolrXml(config); |
| } |
| |
| public abstract CoresLocator getCoresLocator(); |
| |
| |
| /** |
| * The directory against which relative core instance dirs are resolved. If none is |
| * specified in the config, uses solr home. |
| * |
| * @return core root directory |
| */ |
| public String getCoreRootDirectory() { |
| return SolrResourceLoader.normalizeDir( get(CfgProp.SOLR_COREROOTDIRECTORY, config.getResourceLoader().getInstanceDir()) ); |
| } |
| |
| public PluginInfo getShardHandlerFactoryPluginInfo() { |
| Node node = config.getNode(getShardHandlerFactoryConfigPath(), false); |
| return (node == null) ? null : new PluginInfo(node, "shardHandlerFactory", false, true); |
| } |
| |
| protected abstract String getShardHandlerFactoryConfigPath(); |
| |
| public String getZkHost() { |
| String sysZkHost = System.getProperty("zkHost"); |
| if (sysZkHost != null) |
| return sysZkHost; |
| return get(CfgProp.SOLR_ZKHOST, null); |
| } |
| |
| public int getZkClientTimeout() { |
| String sysProp = System.getProperty("zkClientTimeout"); |
| if (sysProp != null) |
| return Integer.parseInt(sysProp); |
| return get(CfgProp.SOLR_ZKCLIENTTIMEOUT, DEFAULT_ZK_CLIENT_TIMEOUT); |
| } |
| |
| private static final int DEFAULT_ZK_CLIENT_TIMEOUT = 15000; |
| private static final int DEFAULT_LEADER_VOTE_WAIT = 180000; // 3 minutes |
| private static final int DEFAULT_LEADER_CONFLICT_RESOLVE_WAIT = 180000; |
| private static final int DEFAULT_CORE_LOAD_THREADS = 3; |
| |
| // TODO: tune defaults |
| private static final int DEFAULT_AUTO_REPLICA_FAILOVER_WAIT_AFTER_EXPIRATION = 30000; |
| private static final int DEFAULT_AUTO_REPLICA_FAILOVER_WORKLOOP_DELAY = 10000; |
| private static final int DEFAULT_AUTO_REPLICA_FAILOVER_BAD_NODE_EXPIRATION = 60000; |
| |
| protected static final String DEFAULT_CORE_ADMIN_PATH = "/admin/cores"; |
| |
| public String getZkHostPort() { |
| return get(CfgProp.SOLR_HOSTPORT, null); |
| } |
| |
| public String getZkHostContext() { |
| return get(CfgProp.SOLR_HOSTCONTEXT, null); |
| } |
| |
| public String getHost() { |
| return get(CfgProp.SOLR_HOST, null); |
| } |
| |
| public int getLeaderVoteWait() { |
| return get(CfgProp.SOLR_LEADERVOTEWAIT, DEFAULT_LEADER_VOTE_WAIT); |
| } |
| |
| public int getLeaderConflictResolveWait() { |
| return get(CfgProp.SOLR_LEADERCONFLICTRESOLVEWAIT, DEFAULT_LEADER_CONFLICT_RESOLVE_WAIT); |
| } |
| |
| public int getAutoReplicaFailoverWaitAfterExpiration() { |
| return get(CfgProp.SOLR_AUTOREPLICAFAILOVERWAITAFTEREXPIRATION, DEFAULT_AUTO_REPLICA_FAILOVER_WAIT_AFTER_EXPIRATION); |
| } |
| |
| public int getAutoReplicaFailoverWorkLoopDelay() { |
| return get(CfgProp.SOLR_AUTOREPLICAFAILOVERWORKLOOPDELAY, DEFAULT_AUTO_REPLICA_FAILOVER_WORKLOOP_DELAY); |
| } |
| |
| public int getAutoReplicaFailoverBadNodeExpiration() { |
| return get(CfgProp.SOLR_AUTOREPLICAFAILOVERBADNODEEXPIRATION, DEFAULT_AUTO_REPLICA_FAILOVER_BAD_NODE_EXPIRATION); |
| } |
| |
| public boolean getGenericCoreNodeNames() { |
| return get(CfgProp.SOLR_GENERICCORENODENAMES, false); |
| } |
| |
| public int getDistributedConnectionTimeout() { |
| return get(CfgProp.SOLR_DISTRIBUPDATECONNTIMEOUT, 0); |
| } |
| |
| public int getDistributedSocketTimeout() { |
| return get(CfgProp.SOLR_DISTRIBUPDATESOTIMEOUT, 0); |
| } |
| |
| public int getMaxUpdateConnections() { |
| return get(CfgProp.SOLR_MAXUPDATECONNECTIONS, 10000); |
| } |
| |
| public int getMaxUpdateConnectionsPerHost() { |
| return get(CfgProp.SOLR_MAXUPDATECONNECTIONSPERHOST, 100); |
| } |
| |
| public int getCoreLoadThreadCount() { |
| return get(ConfigSolr.CfgProp.SOLR_CORELOADTHREADS, DEFAULT_CORE_LOAD_THREADS); |
| } |
| |
| public String getSharedLibDirectory() { |
| return get(ConfigSolr.CfgProp.SOLR_SHAREDLIB , null); |
| } |
| |
| public String getDefaultCoreName() { |
| return get(CfgProp.SOLR_CORES_DEFAULT_CORE_NAME, null); |
| } |
| |
| public abstract boolean isPersistent(); |
| |
| public String getAdminPath() { |
| return get(CfgProp.SOLR_ADMINPATH, DEFAULT_CORE_ADMIN_PATH); |
| } |
| |
| public String getCoreAdminHandlerClass() { |
| return get(CfgProp.SOLR_ADMINHANDLER, "org.apache.solr.handler.admin.CoreAdminHandler"); |
| } |
| |
| public String getCollectionsHandlerClass() { |
| return get(CfgProp.SOLR_COLLECTIONSHANDLER, "org.apache.solr.handler.admin.CollectionsHandler"); |
| } |
| |
| public String getInfoHandlerClass() { |
| return get(CfgProp.SOLR_INFOHANDLER, "org.apache.solr.handler.admin.InfoHandler"); |
| } |
| |
| public boolean hasSchemaCache() { |
| return get(ConfigSolr.CfgProp.SOLR_SHARESCHEMA, false); |
| } |
| |
| public String getManagementPath() { |
| return get(CfgProp.SOLR_MANAGEMENTPATH, null); |
| } |
| |
| public String getConfigSetBaseDirectory() { |
| return get(CfgProp.SOLR_CONFIGSETBASEDIR, "configsets"); |
| } |
| |
| public LogWatcherConfig getLogWatcherConfig() { |
| String loggingClass = get(CfgProp.SOLR_LOGGING_CLASS, null); |
| String loggingWatcherThreshold = get(CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, null); |
| return new LogWatcherConfig( |
| get(CfgProp.SOLR_LOGGING_ENABLED, true), |
| loggingClass, |
| loggingWatcherThreshold, |
| get(CfgProp.SOLR_LOGGING_WATCHER_SIZE, 50) |
| ); |
| } |
| |
| public int getTransientCacheSize() { |
| return get(CfgProp.SOLR_TRANSIENTCACHESIZE, Integer.MAX_VALUE); |
| } |
| |
| public ConfigSetService createCoreConfigService(SolrResourceLoader loader, ZkController zkController) { |
| if (getZkHost() != null || System.getProperty("zkRun") != null) |
| return new CloudConfigSetService(loader, zkController); |
| if (hasSchemaCache()) |
| return new ConfigSetService.SchemaCaching(loader, getConfigSetBaseDirectory()); |
| return new ConfigSetService.Default(loader, getConfigSetBaseDirectory()); |
| } |
| |
| // Ugly for now, but we'll at least be able to centralize all of the differences between 4x and 5x. |
| protected static enum CfgProp { |
| SOLR_ADMINHANDLER, |
| SOLR_COLLECTIONSHANDLER, |
| SOLR_CORELOADTHREADS, |
| SOLR_COREROOTDIRECTORY, |
| SOLR_DISTRIBUPDATECONNTIMEOUT, |
| SOLR_DISTRIBUPDATESOTIMEOUT, |
| SOLR_MAXUPDATECONNECTIONS, |
| SOLR_MAXUPDATECONNECTIONSPERHOST, |
| SOLR_HOST, |
| SOLR_HOSTCONTEXT, |
| SOLR_HOSTPORT, |
| SOLR_INFOHANDLER, |
| SOLR_LEADERVOTEWAIT, |
| SOLR_LOGGING_CLASS, |
| SOLR_LOGGING_ENABLED, |
| SOLR_LOGGING_WATCHER_SIZE, |
| SOLR_LOGGING_WATCHER_THRESHOLD, |
| SOLR_MANAGEMENTPATH, |
| SOLR_SHAREDLIB, |
| SOLR_SHARESCHEMA, |
| SOLR_TRANSIENTCACHESIZE, |
| SOLR_GENERICCORENODENAMES, |
| SOLR_ZKCLIENTTIMEOUT, |
| SOLR_ZKHOST, |
| SOLR_LEADERCONFLICTRESOLVEWAIT, |
| SOLR_CONFIGSETBASEDIR, |
| |
| SOLR_AUTOREPLICAFAILOVERWAITAFTEREXPIRATION, |
| SOLR_AUTOREPLICAFAILOVERWORKLOOPDELAY, |
| SOLR_AUTOREPLICAFAILOVERBADNODEEXPIRATION, |
| |
| //TODO: Remove all of these elements for 5.0 |
| SOLR_PERSISTENT, |
| SOLR_CORES_DEFAULT_CORE_NAME, |
| SOLR_ADMINPATH |
| } |
| |
| protected Config config; |
| protected Map<CfgProp, Object> propMap = new HashMap<>(); |
| |
| public ConfigSolr(Config config) { |
| this.config = config; |
| config.substituteProperties(); |
| } |
| |
| // for extension & testing. |
| protected ConfigSolr() { |
| |
| } |
| |
| public Config getConfig() { |
| return config; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public <T> T get(CfgProp key, T defaultValue) { |
| if (propMap.containsKey(key) && propMap.get(key) != null) { |
| return (T) propMap.get(key); |
| } |
| return defaultValue; |
| } |
| |
| public Properties getSolrProperties(String path) { |
| try { |
| return readProperties(((NodeList) config.evaluate( |
| path, XPathConstants.NODESET)).item(0)); |
| } catch (Exception e) { |
| SolrException.log(log, null, e); |
| } |
| return null; |
| |
| } |
| |
| protected Properties readProperties(Node node) throws XPathExpressionException { |
| XPath xpath = config.getXPath(); |
| NodeList props = (NodeList) xpath.evaluate("property", node, XPathConstants.NODESET); |
| Properties properties = new Properties(); |
| for (int i = 0; i < props.getLength(); i++) { |
| Node prop = props.item(i); |
| properties.setProperty(DOMUtil.getAttr(prop, "name"), |
| PropertiesUtil.substituteProperty(DOMUtil.getAttr(prop, "value"), null)); |
| } |
| return properties; |
| } |
| |
| } |
| |