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

io.smallrye.reactive.messaging.amqp.AmqpClientHelper Maven / Gradle / Ivy

There is a newer version: 4.25.0
Show newest version
package io.smallrye.reactive.messaging.amqp;

import static io.smallrye.reactive.messaging.amqp.i18n.AMQPExceptions.ex;
import static io.smallrye.reactive.messaging.amqp.i18n.AMQPLogging.log;
import static io.vertx.core.net.ClientOptionsBase.DEFAULT_METRICS_NAME;

import java.util.Optional;

import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.literal.NamedLiteral;

import io.smallrye.common.annotation.Identifier;
import io.smallrye.reactive.messaging.ClientCustomizer;
import io.smallrye.reactive.messaging.providers.helpers.ConfigUtils;
import io.smallrye.reactive.messaging.providers.i18n.ProviderLogging;
import io.vertx.amqp.AmqpClientOptions;
import io.vertx.mutiny.amqp.AmqpClient;

public class AmqpClientHelper {

    private AmqpClientHelper() {
        // avoid direct instantiation.
    }

    static AmqpClient createClient(AmqpConnector connector, AmqpConnectorCommonConfiguration config,
            Instance amqpClientOptions,
            Instance> configCustomizers) {
        Optional clientOptionsName = config.getClientOptionsName();
        AmqpClientOptions options;
        if (clientOptionsName.isPresent()) {
            options = createClientFromClientOptionsBean(amqpClientOptions, clientOptionsName.get(), config);
        } else {
            options = getOptionsFromChannel(config);
        }
        AmqpClientOptions clientOptions = ConfigUtils.customize(config.config(), configCustomizers, options);
        AmqpClient client = AmqpClient.create(connector.getVertx(), clientOptions);
        connector.addClient(client);
        return client;
    }

    static AmqpClientOptions createClientFromClientOptionsBean(Instance instance,
            String optionsBeanName, AmqpConnectorCommonConfiguration config) {
        Instance options = instance.select(Identifier.Literal.of(optionsBeanName));
        if (options.isUnsatisfied()) {
            // this `if` block should be removed when support for the `@Named` annotation is removed
            options = instance.select(NamedLiteral.of(optionsBeanName));
            if (!options.isUnsatisfied()) {
                ProviderLogging.log.deprecatedNamed();
            }
        }
        if (options.isUnsatisfied()) {
            throw ex.illegalStateFindingBean(AmqpClientOptions.class.getName(), optionsBeanName);
        }
        log.createClientFromBean(optionsBeanName);

        // We must merge the channel config and the AMQP Client options.
        // In case of conflict, use the channel config.
        AmqpClientOptions customizerOptions = options.get();
        merge(customizerOptions, config);
        return customizerOptions;
    }

    /**
     * Checks whether the given attribute is set in the channel configuration.
     * It does not check for aliases or into the global connector configuration.
     *
     * @param attribute the attribute
     * @param configuration the configuration object
     * @return {@code true} is the given attribute is configured in the channel configuration
     */
    static boolean isSetInChannelConfiguration(String attribute, AmqpConnectorCommonConfiguration configuration) {
        return configuration.config().getConfigValue(attribute).getRawValue() != null;
    }

    /**
     * Merges the values from {@code channel} (the channel configuration), into the {@code custom}.
     * Values from {@code channel} replaces the values from {@code custom}.
     *
     * @param custom the custom configuration
     * @param config the common configuration
     */
    static void merge(AmqpClientOptions custom, AmqpConnectorCommonConfiguration config) {
        AmqpClientOptions channel = getOptionsFromChannel(config);
        String hostFromChannel = channel.getHost();
        int portFromChannel = channel.getPort();

        if (isSetInChannelConfiguration("username", config)) {
            custom.setUsername(channel.getUsername());
        }

        // If the username is not set, use the one from the channel (alias or connector config)
        if (custom.getUsername() == null) {
            custom.setUsername(channel.getUsername());
        }

        if (isSetInChannelConfiguration("password", config)) {
            custom.setPassword(channel.getPassword());
        }

        // If the password is not set, use the one from the channel (alias or connector config)
        if (custom.getPassword() == null) {
            custom.setPassword(channel.getPassword());
        }

        if (isSetInChannelConfiguration("host", config)) {
            custom.setHost(hostFromChannel);
        }

        // If the host is not set, use the one from the channel (alias or connector config)
        if (custom.getHost() == null) {
            custom.setHost(channel.getHost());
        }

        if (isSetInChannelConfiguration("port", config)) {
            custom.setPort(portFromChannel);
        }

        // custom.getPort() will return a value (might be the default port, or not, or the default port as set by the user)
        // the channel port may be set (using the alias or connector config)
        // we can compare, but we cannot decide which one is going to be used.
        // so, we use the one from the customizer except is explicitly set on the channel.
        // The same apply for ssl, reconnect-attempts, reconnect-interval and connect-timeout.

        if (isSetInChannelConfiguration("use-ssl", config)) {
            custom.setSsl(channel.isSsl());
        }

        if (isSetInChannelConfiguration("reconnect-attempts", config)) {
            custom.setReconnectAttempts(channel.getReconnectAttempts());
        }
        if (isSetInChannelConfiguration("reconnect-interval", config)) {
            custom.setReconnectInterval(channel.getReconnectInterval());
        }
        if (isSetInChannelConfiguration("connect-timeout", config)) {
            custom.setConnectTimeout(channel.getConnectTimeout());
        }

        if (DEFAULT_METRICS_NAME.equals(custom.getMetricsName())) {
            custom.setMetricsName(channel.getMetricsName());
        }
    }

    static AmqpClientOptions getOptionsFromChannel(AmqpConnectorCommonConfiguration config) {
        String username = config.getUsername().orElse(null);
        String password = config.getPassword().orElse(null);
        String host = config.getHost();
        int port = config.getPort();
        log.brokerConfigured(host, port, config.getChannel());
        boolean useSsl = config.getUseSsl();
        int reconnectAttempts = config.getReconnectAttempts();
        int reconnectInterval = config.getReconnectInterval();
        int connectTimeout = config.getConnectTimeout();

        // We renamed containerID into container-id. So we must check both.
        String containerId = config.getContainerId()
                .orElseGet(() -> config.config.getOptionalValue("containerId", String.class).orElse(null));

        AmqpClientOptions options = new AmqpClientOptions()
                .setUsername(username)
                .setPassword(password)
                .setHost(host)
                .setPort(port)
                .setContainerId(containerId)
                .setSsl(useSsl)
                .setReconnectAttempts(reconnectAttempts)
                .setReconnectInterval(reconnectInterval)
                .setConnectTimeout(connectTimeout);

        options.setMetricsName("amqp|" + config.getChannel());

        config.getSniServerName().ifPresent(options::setSniServerName);
        config.getVirtualHost().ifPresent(options::setVirtualHost);
        return options;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy