<commit_before>package liquibase.configuration;

import liquibase.Scope;
import liquibase.command.CommandArgumentDefinition;
import liquibase.util.ObjectUtil;
import liquibase.util.StringUtil;

import java.util.*;
import java.util.regex.Pattern;

/**
 * A higher-level/detailed definition to provide type-safety, metadata, default values, etc..
 * Any code that is working with configurations should be using an instance of this class, rather than the lower-level, generic {@link LiquibaseConfiguration}
 * <p>
 * ConfigurationDefinitions that are registered with {@link LiquibaseConfiguration#registerDefinition(ConfigurationDefinition)} will
 * be available in generated help etc.
 * <p>
 * These objects are immutable, so to construct definitions, use {@link Builder}
 * <p>
 * The definition keys should be dot-separated, camelCased names, using a unique "namespace" as part of it.
 * For example: <pre>yourCorp.yourProperty</pre> or <pre>yourCorp.sub.otherProperty</pre>.
 * Liquibase uses "liquibase" as the base namespace like <pre>liquibase.shouldRun</pre>
 */
public class ConfigurationDefinition<DataType> implements Comparable<ConfigurationDefinition<DataType>> {

    private final String key;
    private final Set<String> aliasKeys = new TreeSet<>();
    private final Class<DataType> dataType;
    private String description;
    private DataType defaultValue;
    private String defaultValueDescription;
    private boolean commonlyUsed;
    private boolean internal;
    private ConfigurationValueConverter<DataType> valueConverter;
    private ConfigurationValueObfuscator<DataType> valueObfuscator;

    private static final Pattern ALLOWED_KEY_PATTERN = Pattern.compile("[<KEY>");

    private boolean loggedUsingDefault = false;

    /**
     * Constructor private to force {@link Builder} usage
     *
     * @throws IllegalArgumentException if an invalid key is specified.
     */
    private ConfigurationDefinition(String key, Class<DataType> dataType) throws IllegalArgumentException {
        if (!ALLOWED_KEY_PATTERN.matcher(key).matches()) {
            throw new IllegalArgumentException("Invalid key format: " + key);
        }

        this.key = key;
        this.dataType = dataType;
        this.valueConverter = value -> ObjectUtil.convert(value, dataType);
    }

    /**
     * Convenience method around {@link #getCurrentConfiguredValue(ConfigurationValueProvider...)} to return the value.
     */
    public DataType getCurrentValue() {
        final Object value = getCurrentConfiguredValue().getProvidedValue().getValue();
        try {
            return (DataType) value;
        } catch (ClassCastException e) {
            throw new IllegalArgumentException("The current value of " + key + " not the expected type: " + e.getMessage(), e);
        }
    }

    public ConfigurationValueConverter<DataType> getValueConverter() {
        return valueConverter;
    }

    /**
     * Convenience method around {@link #getCurrentConfiguredValue(ConfigurationValueProvider...)} to return the obfuscated version of the value.
     *
     * @return the obfuscated value, or the plain-text value if no obfuscator is defined for this definition.
     */
    public DataType getCurrentValueObfuscated() {
        return getCurrentConfiguredValue().getValueObfuscated();
    }

    /**
     * @return Full details on the current value for this definition.
     * Will always return a {@link ConfiguredValue},
     *
     * @param additionalValueProviders additional {@link ConfigurationValueProvider}s to use with higher priority than the ones registered in {@link LiquibaseConfiguration}. The higher the array index, the higher the priority.
     */
    public ConfiguredValue<DataType> getCurrentConfiguredValue(ConfigurationValueProvider... additionalValueProviders) {
        final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class);

        List<String> keyList = new ArrayList<>();
        keyList.add(this.getKey());
        keyList.addAll(this.getAliasKeys());

        ConfiguredValue<?> configurationValue = liquibaseConfiguration.getCurrentConfiguredValue(valueConverter, valueObfuscator, additionalValueProviders, keyList.toArray(new String[0]));

        if (!configurationValue.found()) {
            defaultValue = this.getDefaultValue();
            if (defaultValue != null) {
                DataType obfuscatedValue;
                if (valueObfuscator == null) {
                    obfuscatedValue = defaultValue;
                } else {
                    obfuscatedValue = valueObfuscator.obfuscate(defaultValue);
                }
                if (!loggedUsingDefault) {
                    Scope.getCurrentScope().getLog(getClass()).fine("Configuration " + key + " is using the default value of " + obfuscatedValue);
                    loggedUsingDefault = true;
                }
                configurationValue.override(new DefaultValueProvider(this.getDefaultValue()).getProvidedValue(key));
            }
        }
<commit_msg>readd noarg method for CommandScope arguments for backwards compatibility (#3455)<commit_after>package liquibase.configuration;

import liquibase.Scope;
import liquibase.command.CommandArgumentDefinition;
import liquibase.util.ObjectUtil;
import liquibase.util.StringUtil;

import java.util.*;
import java.util.regex.Pattern;

/**
 * A higher-level/detailed definition to provide type-safety, metadata, default values, etc..
 * Any code that is working with configurations should be using an instance of this class, rather than the lower-level, generic {@link LiquibaseConfiguration}
 * <p>
 * ConfigurationDefinitions that are registered with {@link LiquibaseConfiguration#registerDefinition(ConfigurationDefinition)} will
 * be available in generated help etc.
 * <p>
 * These objects are immutable, so to construct definitions, use {@link Builder}
 * <p>
 * The definition keys should be dot-separated, camelCased names, using a unique "namespace" as part of it.
 * For example: <pre>yourCorp.yourProperty</pre> or <pre>yourCorp.sub.otherProperty</pre>.
 * Liquibase uses "liquibase" as the base namespace like <pre>liquibase.shouldRun</pre>
 */
public class ConfigurationDefinition<DataType> implements Comparable<ConfigurationDefinition<DataType>> {

    private final String key;
    private final Set<String> aliasKeys = new TreeSet<>();
    private final Class<DataType> dataType;
    private String description;
    private DataType defaultValue;
    private String defaultValueDescription;
    private boolean commonlyUsed;
    private boolean internal;
    private ConfigurationValueConverter<DataType> valueConverter;
    private ConfigurationValueObfuscator<DataType> valueObfuscator;

    private static final Pattern ALLOWED_KEY_PATTERN = Pattern.compile("[<KEY>");

    private boolean loggedUsingDefault = false;

    /**
     * Constructor private to force {@link Builder} usage
     *
     * @throws IllegalArgumentException if an invalid key is specified.
     */
    private ConfigurationDefinition(String key, Class<DataType> dataType) throws IllegalArgumentException {
        if (!ALLOWED_KEY_PATTERN.matcher(key).matches()) {
            throw new IllegalArgumentException("Invalid key format: " + key);
        }

        this.key = key;
        this.dataType = dataType;
        this.valueConverter = value -> ObjectUtil.convert(value, dataType);
    }

    /**
     * Convenience method around {@link #getCurrentConfiguredValue(ConfigurationValueProvider...)} to return the value.
     */
    public DataType getCurrentValue() {
        final Object value = getCurrentConfiguredValue().getProvidedValue().getValue();
        try {
            return (DataType) value;
        } catch (ClassCastException e) {
            throw new IllegalArgumentException("The current value of " + key + " not the expected type: " + e.getMessage(), e);
        }
    }

    public ConfigurationValueConverter<DataType> getValueConverter() {
        return valueConverter;
    }

    /**
     * Convenience method around {@link #getCurrentConfiguredValue(ConfigurationValueProvider...)} to return the obfuscated version of the value.
     *
     * @return the obfuscated value, or the plain-text value if no obfuscator is defined for this definition.
     */
    public DataType getCurrentValueObfuscated() {
        return getCurrentConfiguredValue().getValueObfuscated();
    }

    /**
     * @return Full details on the current value for this definition.
     * Will always return a {@link ConfiguredValue},
     */
    public ConfiguredValue<DataType> getCurrentConfiguredValue() {
        return getCurrentConfiguredValue(new ConfigurationValueProvider[]{});
    }

    /**
     * @return Full details on the current value for this definition.
     * Will always return a {@link ConfiguredValue},
     *
     * @param additionalValueProviders additional {@link ConfigurationValueProvider}s to use with higher priority than the ones registered in {@link LiquibaseConfiguration}. The higher the array index, the higher the priority.
     */
    public ConfiguredValue<DataType> getCurrentConfiguredValue(ConfigurationValueProvider... additionalValueProviders) {
        final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class);

        List<String> keyList = new ArrayList<>();
        keyList.add(this.getKey());
        keyList.addAll(this.getAliasKeys());

        ConfiguredValue<?> configurationValue = liquibaseConfiguration.getCurrentConfiguredValue(valueConverter, valueObfuscator, additionalValueProviders, keyList.toArray(new String[0]));

        if (!configurationValue.found()) {
            defaultValue = this.getDefaultValue();
            if (defaultValue != null) {
                DataType obfuscatedValue;
                if (valueObfuscator == null) {
                    obfuscatedValue = defaultValue;
                } else {
                    obfuscatedValue = valueObfuscator.obfuscate(defaultValue);
                }
                if (!loggedUsingDefault) {
                    Scope.getCurrentScope().getLog(getClass()).fine("Configuration " + key + " is using the default value of " + obfuscatedValue);
                    loggedUsingDefault = true;
                }
                configurationValue.override(new DefaultValueProvider(this.getDefaultValue()).getProvidedValue(key));
            }
        }

{'fraction_non_alphanumeric': 0.08706016973395633, 'fraction_numerical': 0.0005721369314389244, 'mean_word_length': 3.4197218710493047, 'pattern_counts': {'":': 0, '<': 52, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5835104', 'n_tokens_mistral': 2596, 'n_tokens_neox': 2526, 'n_words': 755}