/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ package org.opensearch.common.settings; import org.apache.logging.log4j.Logger; import org.opensearch.OpenSearchException; import org.opensearch.OpenSearchParseException; import org.opensearch.Version; import org.opensearch.common.Booleans; import org.opensearch.common.Nullable; import org.opensearch.common.Strings; import org.opensearch.common.collect.Tuple; import org.opensearch.common.regex.Regex; import org.opensearch.common.unit.MemorySizeValue; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.common.xcontent.XContentType; import org.opensearch.core.common.unit.ByteSizeUnit; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.io.stream.Writeable; import org.opensearch.core.common.unit.ByteSizeValue; import org.opensearch.core.xcontent.DeprecationHandler; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.core.xcontent.XContentParser; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; /** * A setting. Encapsulates typical stuff like default value, parsing, and scope. * Some (Settings.Property.Dynamic) can be modified at run time using the API. * All settings inside opensearch or in any of the plugins should use this type-safe and generic settings infrastructure * together with {@link AbstractScopedSettings}. This class contains several utility methods that makes it straight forward * to add settings for the majority of the cases. For instance a simple boolean settings can be defined like this: *
{@code * public static final Setting* To retrieve the value of the setting a {@link Settings} object can be passed directly to the {@link Setting#get(Settings)} method. *MY_BOOLEAN = Setting.boolSetting("my.bool.setting", true, Setting.Property.NodeScope);} *
* final boolean myBooleanValue = MY_BOOLEAN.get(settings); ** It's recommended to use typed settings rather than string based settings. For example adding a setting for an enum type: *
{@code * public enum Color { * RED, GREEN, BLUE; * } * public static final Setting* * @opensearch.internal */ public class SettingMY_BOOLEAN = * new Setting<>("my.color.setting", Color.RED.toString(), Color::valueOf, Setting.Property.NodeScope); * } *
true
if this setting is dynamically updateable, otherwise false
*/
public final boolean isDynamic() {
return properties.contains(Property.Dynamic);
}
/**
* Returns true
if this setting is final, otherwise false
*/
public final boolean isFinal() {
return properties.contains(Property.Final);
}
public final boolean isInternalIndex() {
return properties.contains(Property.InternalIndex);
}
public final boolean isPrivateIndex() {
return properties.contains(Property.PrivateIndex);
}
/**
* Returns the setting properties
* @see Property
*/
public EnumSettrue
if this setting must be filtered, otherwise false
*/
public boolean isFiltered() {
return properties.contains(Property.Filtered);
}
/**
* Returns true
if this setting has a node scope, otherwise false
*/
public boolean hasNodeScope() {
return properties.contains(Property.NodeScope);
}
/**
* Returns true
if this setting's value can be checked for equality across all nodes. Only {@link SecureSetting} instances
* may have this qualifier.
*/
public boolean isConsistent() {
return properties.contains(Property.Consistent);
}
/**
* Returns true
if this setting has an index scope, otherwise false
*/
public boolean hasIndexScope() {
return properties.contains(Property.IndexScope);
}
/**
* Returns true
if this setting is deprecated, otherwise false
*/
public boolean isDeprecated() {
return properties.contains(Property.Deprecated);
}
/**
* Returns true
iff this setting is a group setting. Group settings represent a set of settings rather than a single value.
* The key, see {@link #getKey()}, in contrast to non-group settings is a prefix like {@code cluster.store.} that matches all settings
* with this prefix.
*/
boolean isGroupSetting() {
return false;
}
final boolean isListSetting() {
return this instanceof ListSetting;
}
boolean hasComplexMatcher() {
return isGroupSetting();
}
/**
* Validate the current setting value only without dependencies with {@link Setting.Validator#validate(Object)}.
* @param settings a settings object for settings that has a default value depending on another setting if available
*/
void validateWithoutDependencies(Settings settings) {
validator.validate(get(settings, false));
}
/**
* Returns the default value string representation for this setting.
* @param settings a settings object for settings that has a default value depending on another setting if available
*/
public String getDefaultRaw(Settings settings) {
return defaultValue.apply(settings);
}
/**
* Returns the default value for this setting.
* @param settings a settings object for settings that has a default value depending on another setting if available
*/
public T getDefault(Settings settings) {
return parser.apply(getDefaultRaw(settings));
}
/**
* Returns true if and only if this setting is present in the given settings instance. Note that fallback settings are excluded.
*
* @param settings the settings
* @return true if the setting is present in the given settings instance, otherwise false
*/
public boolean exists(final Settings settings) {
return exists(settings.keySet());
}
public boolean exists(final Settings.Builder builder) {
return exists(builder.keys());
}
private boolean exists(final Settrue
iff the given key matches the settings key or if this setting is a group setting if the
* given key is part of the settings group.
* @see #isGroupSetting()
*/
public final boolean match(String toTest) {
return key.match(toTest);
}
@Override
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("key", key.toString());
builder.field("properties", properties);
builder.field("is_group_setting", isGroupSetting());
builder.field("default", defaultValue.apply(Settings.EMPTY));
builder.endObject();
return builder;
}
@Override
public String toString() {
return Strings.toString(XContentType.JSON, this, true, true);
}
/**
* Returns the value for this setting but falls back to the second provided settings object
*/
public final T get(Settings primary, Settings secondary) {
if (exists(primary)) {
return get(primary);
}
if (exists(secondary)) {
return get(secondary);
}
if (fallbackSetting == null) {
return get(primary);
}
if (fallbackSetting.exists(primary)) {
return fallbackSetting.get(primary);
}
return fallbackSetting.get(secondary);
}
public Setting