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

io.smallrye.reactive.messaging.providers.impl.ConnectorConfig Maven / Gradle / Ivy

package io.smallrye.reactive.messaging.providers.impl;

import static io.smallrye.reactive.messaging.providers.i18n.ProviderExceptions.ex;
import static io.smallrye.reactive.messaging.providers.i18n.ProviderMessages.msg;
import static org.eclipse.microprofile.reactive.messaging.spi.ConnectorFactory.*;

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

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigValue;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.Converter;

/**
 * Implementation of config used to configured the different messaging provider / connector.
 */
public class ConnectorConfig implements Config {

    /**
     * Name of the attribute checking if the channel is enabled (default) or disabled.
     * The value must be either `true` or `false`.
     */
    public static final String CHANNEL_ENABLED_PROPERTY = "enabled";

    /**
     * Name of the attribute configuring the broadcast on a connector.
     */
    public static final String BROADCAST_PROPERTY = "broadcast";

    /**
     * Name of the attribute configuring the merge on a connector.
     */
    public static final String MERGE_PROPERTY = "merge";

    private final String prefix;
    private final Config overall;

    private final String name;
    private final String connector;

    protected ConnectorConfig(String prefix, Config overall, String channel) {
        this.prefix = Objects.requireNonNull(prefix, msg.prefixMustNotBeSet());
        this.overall = Objects.requireNonNull(overall, msg.configMustNotBeSet());
        this.name = Objects.requireNonNull(channel, msg.channelMustNotBeSet());

        Optional value = overall.getOptionalValue(channelKey(CONNECTOR_ATTRIBUTE), String.class);
        this.connector = value
                .orElseGet(() -> overall.getOptionalValue(channelKey("type"), String.class) // Legacy
                        .orElseThrow(() -> ex.illegalArgumentChannelConnectorConfiguration(name)));

        // Detect invalid channel-name attribute
        for (String key : overall.getPropertyNames()) {
            if ((channelKey(CHANNEL_NAME_ATTRIBUTE)).equalsIgnoreCase(key)) {
                throw ex.illegalArgumentInvalidChannelConfiguration(name);
            }
        }
    }

    private String channelKey(String keyName) {
        return name.contains(".") ? prefix + "\"" + name + "\"." + keyName : prefix + name + "." + keyName;
    }

    private String connectorKey(String keyName) {
        return CONNECTOR_PREFIX + connector + "." + keyName;
    }

    @Override
    public  T getValue(String propertyName, Class propertyType) {
        if (CHANNEL_NAME_ATTRIBUTE.equalsIgnoreCase(propertyName)) {
            return convert(name, propertyType);
        }
        if (CONNECTOR_ATTRIBUTE.equalsIgnoreCase(propertyName) || "type".equalsIgnoreCase(propertyName)) {
            return convert(connector, propertyType);
        }

        // First check if the channel configuration contains the desired attribute.
        Optional maybeResult = overall.getOptionalValue(channelKey(propertyName), propertyType);
        if (maybeResult.isPresent()) {
            return maybeResult.get();
        }

        // Then check if the connector configuration contains the desired attribute.
        maybeResult = overall.getOptionalValue(connectorKey(propertyName), propertyType);
        if (maybeResult.isPresent()) {
            return maybeResult.get();
        }

        throw ex.noSuchElementForAttribute(propertyName, name, channelKey(propertyName), connectorKey(propertyName));
    }

    @Override
    public ConfigValue getConfigValue(String propertyName) {
        if (CHANNEL_NAME_ATTRIBUTE.equalsIgnoreCase(propertyName)) {
            return new ConfigValueImpl(CHANNEL_NAME_ATTRIBUTE, name);
        }
        if (CONNECTOR_ATTRIBUTE.equalsIgnoreCase(propertyName) || "type".equalsIgnoreCase(propertyName)) {
            return new ConfigValueImpl(CONNECTOR_ATTRIBUTE, connector);
        }
        // First check if the channel configuration contains the desired attribute.
        ConfigValue value = overall.getConfigValue(channelKey(propertyName));
        if (value.getRawValue() == null) {
            // Try connector configuration
            return overall.getConfigValue(connectorKey(propertyName));
        }
        return value;
    }

    @Override
    public  Optional getOptionalValue(String propertyName, Class propertyType) {
        if (CHANNEL_NAME_ATTRIBUTE.equalsIgnoreCase(propertyName)) {
            return convertOptional(name, propertyType);
        }
        if (CONNECTOR_ATTRIBUTE.equalsIgnoreCase(propertyName) || "type".equalsIgnoreCase(propertyName)) {
            return convertOptional(connector, propertyType);
        }

        // First check if the channel configuration contains the desired attribute.
        Optional maybe = overall.getOptionalValue(channelKey(propertyName), propertyType);
        return maybe.isPresent() ? maybe
                : overall.getOptionalValue(connectorKey(propertyName), propertyType);
    }

    private  T convert(String rawValue, Class propertyType) {
        Optional> converter = overall.getConverter(propertyType);

        if (!converter.isPresent()) {
            if (propertyType.isAssignableFrom(String.class)) {
                return propertyType.cast(rawValue);
            }
            throw ex.noConverterForType(propertyType);
        }

        T result = converter.get().convert(rawValue);

        if (result == null) {
            throw ex.converterReturnedNull(converter.get(), rawValue);
        }

        return result;
    }

    private  Optional convertOptional(String rawValue, Class propertyType) {
        Optional> converter = overall.getConverter(propertyType);

        if (!converter.isPresent() && propertyType.isAssignableFrom(String.class)) {
            return Optional.of(propertyType.cast(rawValue));
        }

        return converter.map(c -> c.convert(rawValue));
    }

    /**
     * Gets the lists of config keys for the given connector.
     * Note that the list contains property names from the config and env variables.
     * It includes keys from the connector config and channel config.
     *
     * @return the list of keys
     */
    @Override
    public Iterable getPropertyNames() {
        String prefix = this.prefix + name + ".";
        if (name.contains(".")) {
            prefix = this.prefix + "\"" + name + "\".";
        }

        String prefixAlpha = toAlpha(prefix);
        String prefixAlphaUpper = prefixAlpha.toUpperCase();
        String connectorPrefix = CONNECTOR_PREFIX + connector + ".";
        String connectorPrefixAlpha = toAlpha(connectorPrefix);
        String connectorPrefixAlphaUpper = connectorPrefixAlpha.toUpperCase();

        Set names = new HashSet<>();
        for (String name : overall.getPropertyNames()) {
            if (name.startsWith(connectorPrefix)) {
                String computed = name.substring(connectorPrefix.length());
                names.add(computed);
            } else if (name.startsWith(connectorPrefixAlpha)) {
                String computed = name.substring(connectorPrefixAlpha.length());
                if (nameExists(connectorPrefix + computed)) {
                    names.add(computed);
                }
            } else if (name.startsWith(connectorPrefixAlphaUpper)) {
                String computed = name.substring(connectorPrefixAlphaUpper.length());
                if (nameExists(connectorPrefix + computed)) {
                    names.add(computed);
                }
            } else if (name.startsWith(prefix)) {
                String computed = name.substring(prefix.length());
                names.add(computed);
            } else if (name.startsWith(prefixAlpha)) {
                String computed = name.substring(prefixAlpha.length());
                if (nameExists(prefix + computed)) {
                    names.add(computed);
                }
            } else if (name.startsWith(prefixAlphaUpper)) {
                String computed = name.substring(prefixAlphaUpper.length());
                if (nameExists(prefix + computed)) {
                    names.add(computed);
                }
            }
        }

        names.add(CHANNEL_NAME_ATTRIBUTE);
        return names;
    }

    private static final Pattern NON_ALPHA = Pattern.compile("\\W");

    private String toAlpha(String key) {
        return NON_ALPHA.matcher(key).replaceAll("_");
    }

    private boolean nameExists(String name) {
        return overall.getConfigValue(name).getRawValue() != null;
    }

    @Override
    public Iterable getConfigSources() {
        return overall.getConfigSources();
    }

    @Override
    public  Optional> getConverter(Class forType) {
        return overall.getConverter(forType);
    }

    @Override
    public  T unwrap(Class type) {
        if (type.isInstance(this)) {
            return type.cast(this);
        } else {
            throw ex.configNotOfType(type);
        }
    }

    private static class ConfigValueImpl implements ConfigValue {

        private final String name;
        private final String value;

        public ConfigValueImpl(String name, String value) {
            super();
            this.name = name;
            this.value = value;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String getValue() {
            return value;
        }

        @Override
        public String getRawValue() {
            return value;
        }

        @Override
        public String getSourceName() {
            return "ConnectorConfig internal";
        }

        @Override
        public int getSourceOrdinal() {
            return 0;
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy