org.apache.kafka.common.config.ConfigDef Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jena-fmod-kafka Show documentation
Show all versions of jena-fmod-kafka Show documentation
Apache Jena Fuseki server Kafka connector
/*
* 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.kafka.common.config;
import org.apache.kafka.common.config.types.Password;
import org.apache.kafka.common.utils.Utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* This class is used for specifying the set of expected configurations. For each configuration, you can specify
* the name, the type, the default value, the documentation, the group information, the order in the group,
* the width of the configuration value and the name suitable for display in the UI.
*
* You can provide special validation logic used for single configuration validation by overriding {@link Validator}.
*
* Moreover, you can specify the dependents of a configuration. The valid values and visibility of a configuration
* may change according to the values of other configurations. You can override {@link Recommender} to get valid
* values and set visibility of a configuration given the current configuration values.
*
*
* To use the class:
*
*
* ConfigDef defs = new ConfigDef();
*
* // check {@link #define(String, Type, Object, Importance, String)} for more details.
* defs.define("config_with_default", Type.STRING, "default string value", Importance.High, "Configuration with default value.");
* // check {@link #define(String, Type, Object, Validator, Importance, String)} for more details.
* defs.define("config_with_validator", Type.INT, 42, Range.atLeast(0), Importance.High, "Configuration with user provided validator.");
* // check {@link #define(String, Type, Importance, String, String, int, Width, String, List) define(String, Type, Importance, String, String, int, Width, String, List<String>)} for more details.
* defs.define("config_with_dependents", Type.INT, Importance.LOW, "Configuration with dependents.", "group", 1, Width.SHORT, "Config With Dependents", Arrays.asList("config_with_default","config_with_validator"));
*
* Map<String, String> props = new HashMap<>();
* props.put("config_with_default", "some value");
* props.put("config_with_dependents", "some other value");
*
* Map<String, Object> configs = defs.parse(props);
* // will return "some value"
* String someConfig = (String) configs.get("config_with_default");
* // will return default value of 42
* int anotherConfig = (Integer) configs.get("config_with_validator");
*
* // To validate the full configuration, use:
* List<ConfigValue> configValues = defs.validate(props);
* // The {@link ConfigValue} contains updated configuration information given the current configuration values.
*
*
* This class can be used standalone or in combination with {@link AbstractConfig} which provides some additional
* functionality for accessing configs.
*/
public class ConfigDef {
private static final Pattern COMMA_WITH_WHITESPACE = Pattern.compile("\\s*,\\s*");
/**
* A unique Java object which represents the lack of a default value.
*/
public static final Object NO_DEFAULT_VALUE = new Object();
private final Map configKeys;
private final List groups;
private Set configsWithNoParent;
public ConfigDef() {
configKeys = new LinkedHashMap<>();
groups = new LinkedList<>();
configsWithNoParent = null;
}
public ConfigDef(ConfigDef base) {
configKeys = new LinkedHashMap<>(base.configKeys);
groups = new LinkedList<>(base.groups);
// It is not safe to copy this from the parent because we may subsequently add to the set of configs and
// invalidate this
configsWithNoParent = null;
}
/**
* Returns unmodifiable set of properties names defined in this {@linkplain ConfigDef}
*
* @return new unmodifiable {@link Set} instance containing the keys
*/
public Set names() {
return Collections.unmodifiableSet(configKeys.keySet());
}
public Map defaultValues() {
Map defaultValues = new HashMap<>();
for (ConfigKey key : configKeys.values()) {
if (key.defaultValue != NO_DEFAULT_VALUE)
defaultValues.put(key.name, key.defaultValue);
}
return defaultValues;
}
public ConfigDef define(ConfigKey key) {
if (configKeys.containsKey(key.name)) {
throw new ConfigException("Configuration " + key.name + " is defined twice.");
}
if (key.group != null && !groups.contains(key.group)) {
groups.add(key.group);
}
configKeys.put(key.name, key);
return this;
}
/**
* Define a new configuration
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param validator the validator to use in checking the correctness of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @param recommender the recommender provides valid values given the parent configuration values
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Validator validator, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, List dependents, Recommender recommender) {
return define(new ConfigKey(name, type, defaultValue, validator, importance, documentation, group, orderInGroup, width, displayName, dependents, recommender, false, null));
}
/**
* Define a new configuration
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param validator the validator to use in checking the correctness of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @param recommender the recommender provides valid values given the parent configuration values
* @param alternativeString the string which will be used to override the string of defaultValue
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Validator validator, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, List dependents, Recommender recommender,
String alternativeString) {
return define(new ConfigKey(name, type, defaultValue, validator, importance, documentation, group, orderInGroup, width, displayName, dependents, recommender, false, alternativeString));
}
/**
* Define a new configuration with no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param validator the validator to use in checking the correctness of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Validator validator, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, List dependents) {
return define(name, type, defaultValue, validator, importance, documentation, group, orderInGroup, width, displayName, dependents, null);
}
/**
* Define a new configuration with no dependents
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param validator the validator to use in checking the correctness of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param recommender the recommender provides valid values given the parent configuration values
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Validator validator, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, Recommender recommender) {
return define(name, type, defaultValue, validator, importance, documentation, group, orderInGroup, width, displayName, Collections.emptyList(), recommender);
}
/**
* Define a new configuration with no dependents and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param validator the validator to use in checking the correctness of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Validator validator, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName) {
return define(name, type, defaultValue, validator, importance, documentation, group, orderInGroup, width, displayName, Collections.emptyList());
}
/**
* Define a new configuration with no special validation logic
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @param recommender the recommender provides valid values given the parent configuration values
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, List dependents, Recommender recommender) {
return define(name, type, defaultValue, null, importance, documentation, group, orderInGroup, width, displayName, dependents, recommender);
}
/**
* Define a new configuration with no special validation logic and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, List dependents) {
return define(name, type, defaultValue, null, importance, documentation, group, orderInGroup, width, displayName, dependents, null);
}
/**
* Define a new configuration with no special validation logic and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param recommender the recommender provides valid values given the parent configuration values
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName, Recommender recommender) {
return define(name, type, defaultValue, null, importance, documentation, group, orderInGroup, width, displayName, Collections.emptyList(), recommender);
}
/**
* Define a new configuration with no special validation logic, not dependents and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Importance importance, String documentation,
String group, int orderInGroup, Width width, String displayName) {
return define(name, type, defaultValue, null, importance, documentation, group, orderInGroup, width, displayName, Collections.emptyList());
}
/**
* Define a new configuration with no default value and no special validation logic
* @param name the name of the config parameter
* @param type the type of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @param recommender the recommender provides valid values given the parent configuration value
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Importance importance, String documentation, String group, int orderInGroup,
Width width, String displayName, List dependents, Recommender recommender) {
return define(name, type, NO_DEFAULT_VALUE, null, importance, documentation, group, orderInGroup, width, displayName, dependents, recommender);
}
/**
* Define a new configuration with no default value, no special validation logic and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param dependents the configurations that are dependents of this configuration
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Importance importance, String documentation, String group, int orderInGroup,
Width width, String displayName, List dependents) {
return define(name, type, NO_DEFAULT_VALUE, null, importance, documentation, group, orderInGroup, width, displayName, dependents, null);
}
/**
* Define a new configuration with no default value, no special validation logic and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @param recommender the recommender provides valid values given the parent configuration value
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Importance importance, String documentation, String group, int orderInGroup,
Width width, String displayName, Recommender recommender) {
return define(name, type, NO_DEFAULT_VALUE, null, importance, documentation, group, orderInGroup, width, displayName, Collections.emptyList(), recommender);
}
/**
* Define a new configuration with no default value, no special validation logic, no dependents and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @param group the group this config belongs to
* @param orderInGroup the order of this config in the group
* @param width the width of the config
* @param displayName the name suitable for display
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Importance importance, String documentation, String group, int orderInGroup,
Width width, String displayName) {
return define(name, type, NO_DEFAULT_VALUE, null, importance, documentation, group, orderInGroup, width, displayName, Collections.emptyList());
}
/**
* Define a new configuration with no group, no order in group, no width, no display name, no dependents and no custom recommender
* @param name the name of the config parameter
* @param type the type of the config
* @param defaultValue the default value to use if this config isn't present
* @param validator the validator to use in checking the correctness of the config
* @param importance the importance of this config
* @param documentation the documentation string for the config
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Validator validator, Importance importance, String documentation) {
return define(name, type, defaultValue, validator, importance, documentation, null, -1, Width.NONE, name);
}
/**
* Define a new configuration with no special validation logic
* @param name The name of the config parameter
* @param type The type of the config
* @param defaultValue The default value to use if this config isn't present
* @param importance The importance of this config: is this something you will likely need to change.
* @param documentation The documentation string for the config
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Importance importance, String documentation) {
return define(name, type, defaultValue, null, importance, documentation);
}
/**
* Define a new configuration with no special validation logic
* @param name The name of the config parameter
* @param type The type of the config
* @param defaultValue The default value to use if this config isn't present
* @param importance The importance of this config: is this something you will likely need to change.
* @param documentation The documentation string for the config
* @param alternativeString The string which will be used to override the string of defaultValue
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Object defaultValue, Importance importance, String documentation, String alternativeString) {
return define(name, type, defaultValue, null, importance, documentation, null, -1, Width.NONE,
name, Collections.emptyList(), null, alternativeString);
}
/**
* Define a new configuration with no default value and no special validation logic
* @param name The name of the config parameter
* @param type The type of the config
* @param importance The importance of this config: is this something you will likely need to change.
* @param documentation The documentation string for the config
* @return This ConfigDef so you can chain calls
*/
public ConfigDef define(String name, Type type, Importance importance, String documentation) {
return define(name, type, NO_DEFAULT_VALUE, null, importance, documentation);
}
/**
* Define a new internal configuration. Internal configuration won't show up in the docs and aren't
* intended for general use.
* @param name The name of the config parameter
* @param type The type of the config
* @param defaultValue The default value to use if this config isn't present
* @param importance The importance of this config (i.e. is this something you will likely need to change?)
* @return This ConfigDef so you can chain calls
*/
public ConfigDef defineInternal(final String name, final Type type, final Object defaultValue, final Importance importance) {
return define(new ConfigKey(name, type, defaultValue, null, importance, "", "", -1, Width.NONE, name, Collections.emptyList(), null, true, null));
}
/**
* Define a new internal configuration. Internal configuration won't show up in the docs and aren't
* intended for general use.
* @param name The name of the config parameter
* @param type The type of the config
* @param defaultValue The default value to use if this config isn't present
* @param validator The validator to use in checking the correctness of the config
* @param importance The importance of this config (i.e. is this something you will likely need to change?)
* @param documentation The documentation string for the config
* @return This ConfigDef so you can chain calls
*/
public ConfigDef defineInternal(final String name, final Type type, final Object defaultValue, final Validator validator, final Importance importance, final String documentation) {
return define(new ConfigKey(name, type, defaultValue, validator, importance, documentation, "", -1, Width.NONE, name, Collections.emptyList(), null, true, null));
}
/**
* Get the configuration keys
* @return a map containing all configuration keys
*/
public Map configKeys() {
return configKeys;
}
/**
* Get the groups for the configuration
* @return a list of group names
*/
public List groups() {
return groups;
}
/**
* Add standard SSL client configuration options.
* @return this
*/
public ConfigDef withClientSslSupport() {
SslConfigs.addClientSslSupport(this);
return this;
}
/**
* Add standard SASL client configuration options.
* @return this
*/
public ConfigDef withClientSaslSupport() {
SaslConfigs.addClientSaslSupport(this);
return this;
}
/**
* Parse and validate configs against this configuration definition. The input is a map of configs. It is expected
* that the keys of the map are strings, but the values can either be strings or they may already be of the
* appropriate type (int, string, etc). This will work equally well with either java.util.Properties instances or a
* programmatically constructed map.
*
* @param props The configs to parse and validate.
* @return Parsed and validated configs. The key will be the config name and the value will be the value parsed into
* the appropriate type (int, string, etc).
*/
public Map parse(Map, ?> props) {
// Check all configurations are defined
List undefinedConfigKeys = undefinedDependentConfigs();
if (!undefinedConfigKeys.isEmpty()) {
String joined = undefinedConfigKeys.stream().map(String::toString).collect(Collectors.joining(","));
throw new ConfigException("Some configurations in are referred in the dependents, but not defined: " + joined);
}
// parse all known keys
Map values = new HashMap<>();
for (ConfigKey key : configKeys.values())
values.put(key.name, parseValue(key, props.get(key.name), props.containsKey(key.name)));
return values;
}
Object parseValue(ConfigKey key, Object value, boolean isSet) {
Object parsedValue;
if (isSet) {
parsedValue = parseType(key.name, value, key.type);
// props map doesn't contain setting, the key is required because no default value specified - its an error
} else if (NO_DEFAULT_VALUE.equals(key.defaultValue)) {
throw new ConfigException("Missing required configuration \"" + key.name + "\" which has no default value.");
} else {
// otherwise assign setting its default value
parsedValue = key.defaultValue;
}
if (key.validator != null) {
key.validator.ensureValid(key.name, parsedValue);
}
return parsedValue;
}
/**
* Validate the current configuration values with the configuration definition.
* @param props the current configuration values
* @return List of Config, each Config contains the updated configuration information given
* the current configuration values.
*/
public List validate(Map props) {
return new ArrayList<>(validateAll(props).values());
}
public Map validateAll(Map props) {
Map configValues = new HashMap<>();
for (String name: configKeys.keySet()) {
configValues.put(name, new ConfigValue(name));
}
List undefinedConfigKeys = undefinedDependentConfigs();
for (String undefinedConfigKey: undefinedConfigKeys) {
ConfigValue undefinedConfigValue = new ConfigValue(undefinedConfigKey);
undefinedConfigValue.addErrorMessage(undefinedConfigKey + " is referred in the dependents, but not defined.");
undefinedConfigValue.visible(false);
configValues.put(undefinedConfigKey, undefinedConfigValue);
}
Map parsed = parseForValidate(props, configValues);
return validate(parsed, configValues);
}
// package accessible for testing
Map parseForValidate(Map props, Map configValues) {
Map parsed = new HashMap<>();
Set configsWithNoParent = getConfigsWithNoParent();
for (String name: configsWithNoParent) {
parseForValidate(name, props, parsed, configValues);
}
return parsed;
}
private Map validate(Map parsed, Map configValues) {
Set configsWithNoParent = getConfigsWithNoParent();
for (String name: configsWithNoParent) {
validate(name, parsed, configValues);
}
return configValues;
}
private List undefinedDependentConfigs() {
Set undefinedConfigKeys = new HashSet<>();
for (ConfigKey configKey : configKeys.values()) {
for (String dependent: configKey.dependents) {
if (!configKeys.containsKey(dependent)) {
undefinedConfigKeys.add(dependent);
}
}
}
return new ArrayList<>(undefinedConfigKeys);
}
// package accessible for testing
Set getConfigsWithNoParent() {
if (this.configsWithNoParent != null) {
return this.configsWithNoParent;
}
Set configsWithParent = new HashSet<>();
for (ConfigKey configKey: configKeys.values()) {
List dependents = configKey.dependents;
configsWithParent.addAll(dependents);
}
Set configs = new HashSet<>(configKeys.keySet());
configs.removeAll(configsWithParent);
this.configsWithNoParent = configs;
return configs;
}
private void parseForValidate(String name, Map props, Map parsed, Map configs) {
if (!configKeys.containsKey(name)) {
return;
}
ConfigKey key = configKeys.get(name);
ConfigValue config = configs.get(name);
Object value = null;
if (props.containsKey(key.name)) {
try {
value = parseType(key.name, props.get(key.name), key.type);
} catch (ConfigException e) {
config.addErrorMessage(e.getMessage());
}
} else if (NO_DEFAULT_VALUE.equals(key.defaultValue)) {
config.addErrorMessage("Missing required configuration \"" + key.name + "\" which has no default value.");
} else {
value = key.defaultValue;
}
if (key.validator != null) {
try {
key.validator.ensureValid(key.name, value);
} catch (ConfigException e) {
config.addErrorMessage(e.getMessage());
}
}
config.value(value);
parsed.put(name, value);
for (String dependent: key.dependents) {
parseForValidate(dependent, props, parsed, configs);
}
}
private void validate(String name, Map parsed, Map configs) {
if (!configKeys.containsKey(name)) {
return;
}
ConfigKey key = configKeys.get(name);
ConfigValue value = configs.get(name);
if (key.recommender != null) {
try {
List