All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.core.CoreDescriptor Maven / Gradle / Ivy

There is a newer version: 9.6.1
Show newest version
/*
 * 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 java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.PropertiesUtil;
import org.apache.solr.common.util.StrUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Metadata about a {@link SolrCore}. It's mostly loaded from a file on disk at the very beginning
 * of loading a core.
 *
 * 

It's mostly but not completely immutable; we should fix this! * * @since solr 1.3 */ public class CoreDescriptor { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); // Properties file name constants public static final String CORE_NAME = "name"; public static final String CORE_CONFIG = "config"; public static final String CORE_DATADIR = "dataDir"; public static final String CORE_ULOGDIR = "ulogDir"; public static final String CORE_SCHEMA = "schema"; public static final String CORE_SHARD = "shard"; public static final String CORE_COLLECTION = "collection"; public static final String CORE_ROLES = "roles"; public static final String CORE_PROPERTIES = "properties"; public static final String CORE_LOADONSTARTUP = "loadOnStartup"; public static final String CORE_TRANSIENT = "transient"; public static final String CORE_NODE_NAME = "coreNodeName"; public static final String CORE_CONFIGSET = "configSet"; public static final String CORE_CONFIGSET_PROPERTIES = "configSetProperties"; public static final String SOLR_CORE_PROP_PREFIX = "solr.core."; public static final String DEFAULT_EXTERNAL_PROPERTIES_FILE = "conf" + File.separator + "solrcore.properties"; /** * Whether this core was configured using a configSet that was trusted. This helps in avoiding the * loading of plugins that have potential vulnerabilities, when the configSet was not uploaded * from a trusted user. */ private boolean trustedConfigSet = true; /** * Get the standard properties in persistable form * * @return the standard core properties in persistable form */ public Properties getPersistableStandardProperties() { return originalCoreProperties; } /** * Get user-defined core properties in persistable form * * @return user-defined core properties in persistable form */ public Properties getPersistableUserProperties() { return originalExtraProperties; } private static final Map defaultProperties = Map.of( CORE_CONFIG, "solrconfig.xml", CORE_SCHEMA, "schema.xml", CORE_CONFIGSET_PROPERTIES, ConfigSetProperties.DEFAULT_FILENAME, CORE_DATADIR, "data" + File.separator, CORE_TRANSIENT, "false", CORE_LOADONSTARTUP, "true"); private static final List requiredProperties = List.of(CORE_NAME); public static List standardPropNames = List.of( CORE_NAME, CORE_CONFIG, CORE_DATADIR, CORE_ULOGDIR, CORE_SCHEMA, CORE_PROPERTIES, CORE_CONFIGSET_PROPERTIES, CORE_LOADONSTARTUP, CORE_TRANSIENT, CORE_CONFIGSET, // cloud props CORE_SHARD, CORE_COLLECTION, CORE_ROLES, CORE_NODE_NAME, CloudDescriptor.NUM_SHARDS); private final CloudDescriptor cloudDesc; /** The absolute path to where the core lives. */ private final Path instanceDir; /** The original standard core properties, before substitution */ protected final Properties originalCoreProperties = new Properties(); /** The original extra core properties, before substitution */ protected final Properties originalExtraProperties = new Properties(); /** The properties for this core, as available through getProperty() */ protected final Properties coreProperties = new Properties(); /** The properties for this core, substitutable by resource loaders */ protected final Properties substitutableProperties = new Properties(); /** TESTS ONLY */ public CoreDescriptor( String name, Path instanceDir, CoreContainer coreContainer, String... coreProps) { this( name, instanceDir, toMap(coreProps), coreContainer.getContainerProperties(), coreContainer.getZkController()); } private static Map toMap(String... properties) { Map props = new HashMap<>(); assert properties.length % 2 == 0; for (int i = 0; i < properties.length; i += 2) { props.put(properties[i], properties[i + 1]); } return props; } /** * Create a new CoreDescriptor using the properties of an existing one * * @param coreName the new CoreDescriptor's name * @param other the CoreDescriptor to copy */ public CoreDescriptor(String coreName, CoreDescriptor other) { this.cloudDesc = other.cloudDesc; this.instanceDir = other.instanceDir; this.originalExtraProperties.putAll(other.originalExtraProperties); this.originalCoreProperties.putAll(other.originalCoreProperties); this.coreProperties.putAll(other.coreProperties); this.substitutableProperties.putAll(other.substitutableProperties); this.coreProperties.setProperty(CORE_NAME, coreName); this.originalCoreProperties.setProperty(CORE_NAME, coreName); this.substitutableProperties.setProperty(SOLR_CORE_PROP_PREFIX + CORE_NAME, coreName); this.trustedConfigSet = other.trustedConfigSet; } /** * Create a new CoreDescriptor. * * @param name the CoreDescriptor's name * @param instanceDir a Path resolving to the instanceDir. Must be absolute. * @param coreProps a Map of the properties for this core * @param containerProperties the properties from the enclosing container. * @param zkController the ZkController in SolrCloud mode, otherwise null. */ public CoreDescriptor( String name, Path instanceDir, Map coreProps, Properties containerProperties, ZkController zkController) { this.instanceDir = instanceDir; assert instanceDir.isAbsolute(); originalCoreProperties.setProperty(CORE_NAME, name); name = PropertiesUtil.substituteProperty( checkPropertyIsNotEmpty(name, CORE_NAME), containerProperties); coreProperties.putAll(defaultProperties); coreProperties.put(CORE_NAME, name); for (Map.Entry entry : coreProps.entrySet()) { String propname = entry.getKey(); String propvalue = entry.getValue(); if (isUserDefinedProperty(propname)) originalExtraProperties.put(propname, propvalue); else originalCoreProperties.put(propname, propvalue); // Required props are already dealt with if (!requiredProperties.contains(propname)) { coreProperties.setProperty( propname, PropertiesUtil.substituteProperty(propvalue, containerProperties)); } } loadExtraProperties(); buildSubstitutableProperties(); // TODO maybe make this a CloudCoreDescriptor subclass? if (zkController != null) { cloudDesc = new CloudDescriptor(this, name, coreProperties); } else { cloudDesc = null; } log.debug("Created CoreDescriptor: {}", coreProperties); } /** * Load properties specified in an external properties file. * *

The file to load can be specified in a {@code properties} property on the original * Properties object used to create this CoreDescriptor. If this has not been set, then we look * for {@code conf/solrcore.properties} underneath the instance dir. * *

File paths are taken as read from the core's instance directory if they are not absolute. */ protected void loadExtraProperties() { String filename = coreProperties.getProperty(CORE_PROPERTIES, DEFAULT_EXTERNAL_PROPERTIES_FILE); Path propertiesFile = instanceDir.resolve(filename); if (Files.exists(propertiesFile)) { try (Reader r = Files.newBufferedReader(propertiesFile, StandardCharsets.UTF_8)) { Properties externalProps = new Properties(); externalProps.load(r); coreProperties.putAll(externalProps); } catch (IOException e) { String message = String.format(Locale.ROOT, "Could not load properties from %s: %s:", propertiesFile, e); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, message); } } } /** * Create the properties object used by resource loaders, etc., for property substitution. The * default solr properties are prefixed with 'solr.core.', so, e.g., 'name' becomes * 'solr.core.name' */ protected void buildSubstitutableProperties() { for (String propName : coreProperties.stringPropertyNames()) { String propValue = coreProperties.getProperty(propName); if (!isUserDefinedProperty(propName)) propName = SOLR_CORE_PROP_PREFIX + propName; substitutableProperties.setProperty(propName, propValue); } substitutableProperties.setProperty("solr.core.instanceDir", instanceDir.toString()); } /** * Is this property a Solr-standard property, or is it an extra property defined per-core by the * user? * * @param propName the Property name * @return {@code true} if this property is user-defined */ protected static boolean isUserDefinedProperty(String propName) { return !standardPropNames.contains(propName); } public static String checkPropertyIsNotEmpty(String value, String propName) { if (StrUtils.isNullOrEmpty(value)) { String message = String.format(Locale.ROOT, "Cannot create core with empty %s value", propName); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, message); } return value; } public String getPropertiesName() { return coreProperties.getProperty(CORE_PROPERTIES); } public String getDataDir() { return coreProperties.getProperty(CORE_DATADIR); } public boolean usingDefaultDataDir() { return defaultProperties.get(CORE_DATADIR).equals(coreProperties.getProperty(CORE_DATADIR)); } /** The core instance directory (absolute). */ public Path getInstanceDir() { return instanceDir; } /** * @return the core configuration resource name. */ public String getConfigName() { return coreProperties.getProperty(CORE_CONFIG); } /** * @return the core schema resource name. Not actually used if schema is managed mode. */ public String getSchemaName() { return coreProperties.getProperty(CORE_SCHEMA); } /** * @return the initial core name */ public String getName() { return coreProperties.getProperty(CORE_NAME); } /** TODO remove mutability */ void setProperty(String prop, String val) { if (substitutableProperties.containsKey(prop)) { substitutableProperties.setProperty(prop, val); return; } coreProperties.setProperty(prop, val); } public String getCollectionName() { return cloudDesc == null ? null : cloudDesc.getCollectionName(); } public CloudDescriptor getCloudDescriptor() { return cloudDesc; } public boolean isLoadOnStartup() { String tmp = coreProperties.getProperty(CORE_LOADONSTARTUP, "false"); return Boolean.parseBoolean(tmp); } public boolean isTransient() { String tmp = coreProperties.getProperty(CORE_TRANSIENT, "false"); return PropertiesUtil.toBoolean(tmp); } public String getUlogDir() { return coreProperties.getProperty(CORE_ULOGDIR); } /** * Returns a specific property defined on this CoreDescriptor * * @param prop - value to read from the properties structure. * @param defVal - return if no property found. * @return associated string. May be null. */ public String getCoreProperty(String prop, String defVal) { return coreProperties.getProperty(prop, defVal); } /** * Returns all substitutable properties defined on this CoreDescriptor * * @return all substitutable properties defined on this CoreDescriptor */ public Properties getSubstitutableProperties() { return substitutableProperties; } @Override public String toString() { return "CoreDescriptor[name=" + this.getName() + ";instanceDir=" + this.getInstanceDir() + "]"; } public String getConfigSet() { // TODO consider falling back on "collection.configName" ( CollectionAdminParams.COLL_CONF ) return coreProperties.getProperty(CORE_CONFIGSET); } /** TODO remove mutability or at least make this non-public? */ public void setConfigSet(String configSetName) { coreProperties.setProperty(CORE_CONFIGSET, configSetName); } public String getConfigSetPropertiesName() { return coreProperties.getProperty(CORE_CONFIGSET_PROPERTIES); } public boolean isConfigSetTrusted() { return trustedConfigSet; } /** TODO remove mutability */ public void setConfigSetTrusted(boolean trusted) { this.trustedConfigSet = trusted; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy