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

se.hiq.oss.spring.nats.config.xmlns.parser.AbstractNatsBeanDefinitionParser Maven / Gradle / Ivy

The newest version!
package se.hiq.oss.spring.nats.config.xmlns.parser;

import java.time.Duration;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;

import io.nats.client.Options;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Element;
import static se.hiq.oss.spring.nats.config.NatsBeans.*;

import se.hiq.oss.spring.nats.NatsTemplateImpl;
import se.hiq.oss.spring.nats.config.xmlns.XmlNamespaceUtils;
import se.hiq.oss.spring.nats.connection.ConnectionFactoryBean;
import se.hiq.oss.spring.nats.consumer.NatsConsumerManagerImpl;
import se.hiq.oss.spring.nats.consumer.NatsPostBeanProcessor;
import se.hiq.oss.spring.nats.metrics.NatsMetricsRegistry;


public abstract class AbstractNatsBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    protected boolean isAttributeTrue(Element element, String name, boolean defaltValue) {
        return getAttributeValue(element, name).map(s -> "true".equals(s)).orElse(defaltValue);
    }

    protected Optional getAttributeValue(Element element, String name) {
        String value = element.getAttribute(name);
        if (StringUtils.isEmpty(value)) {
            return Optional.empty();
        } else {
            return Optional.of(value);
        }
    }

    protected void createBeans(ParserContext pc, Element element, String serDeFactoryBeanName) {
        Optional connection = getAttributeValue(element, "connection");
        if (!connection.isPresent()) {
            createConnection(pc, element);
        }

        boolean enableMetrics = isAttributeTrue(element, "enable-metrics", true);
        Optional meterRegistry = getAttributeValue(element, "meter-registry");

        if (enableMetrics && meterRegistry.isPresent()) {
            createNatsMetricsRegistry(pc, connection.orElse(NATS_CONNECTION_FACTORY), meterRegistry.get());
        }

        createNatsTemplate(pc, connection.orElse(NATS_CONNECTION_FACTORY), serDeFactoryBeanName);
        createConsumerManager(
                pc,
                connection.orElse(NATS_CONNECTION_FACTORY),
                serDeFactoryBeanName,
                isAttributeTrue(element, "auto-start-consumers", true)
        );
        createPostBeanProcessor(pc);
    }

    private void createConnection(ParserContext pc, Element element) {


        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .rootBeanDefinition(ConnectionFactoryBean.class);
        builder.setLazyInit(false);

        XmlNamespaceUtils.setValueIfPresent(
                "connection-url",
                "urls",
                element,
                builder,
                v -> Stream.of(StringUtils.split(v, ",")).map(u -> u.trim()).collect(Collectors.toList()));

        pc.registerBeanComponent(new BeanComponentDefinition(builder
                .getBeanDefinition(), NATS_CONNECTION_FACTORY));
    }


    private void createNatsMetricsRegistry(ParserContext pc, String connection, String meterRegistry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .rootBeanDefinition(NatsMetricsRegistry.class);
        builder.setLazyInit(false);
        builder.addConstructorArgReference(meterRegistry);
        builder.addConstructorArgReference(connection);

        pc.registerBeanComponent(new BeanComponentDefinition(builder
                .getBeanDefinition(), METER_REGISTRY));

    }

    private void createPostBeanProcessor(ParserContext pc) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .rootBeanDefinition(NatsPostBeanProcessor.class);
        builder.setLazyInit(false);

        builder.addConstructorArgReference(CONSUMER_MANAGER);

        pc.registerBeanComponent(new BeanComponentDefinition(builder
                .getBeanDefinition(), POST_BEAN_PROCESSOR));
    }

    private void createNatsTemplate(ParserContext pc, String connection, String serDeFactory) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .rootBeanDefinition(NatsTemplateImpl.class);
        builder.setLazyInit(false);

        builder.addConstructorArgReference(connection);
        builder.addConstructorArgReference(serDeFactory);

        pc.registerBeanComponent(new BeanComponentDefinition(builder
                .getBeanDefinition(), NATS_TEMPLATE));
    }

    private void createConsumerManager(ParserContext pc, String connection, String serDeFactory, boolean autoStart) {
        Optional drainTimeoutSeconds = resolveDrainTimeoutSeconds(pc);
        long drainTimeout = drainTimeoutSeconds.orElse(Options.DEFAULT_CONNECTION_TIMEOUT.getSeconds());
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .rootBeanDefinition(NatsConsumerManagerImpl.class);
        builder.setLazyInit(false);
        builder.addConstructorArgReference(connection);
        builder.addConstructorArgReference(serDeFactory);
        builder.addConstructorArgValue(drainTimeout);
        builder.addConstructorArgValue(autoStart);

        if (pc.getRegistry().containsBeanDefinition(METER_REGISTRY)) {
            builder.addPropertyReference("natsMetricsRegistry", METER_REGISTRY);
        }

        pc.registerBeanComponent(new BeanComponentDefinition(builder
                .getBeanDefinition(), CONSUMER_MANAGER));
    }


    private Optional resolveDrainTimeoutSeconds(ParserContext pc) {
        Optional connectionFactoryBean = Arrays.stream(pc.getRegistry().getBeanDefinitionNames())
                .map(n -> pc.getRegistry().getBeanDefinition(n))
                .filter(b -> ConnectionFactoryBean.class.getName().equals(b.getBeanClassName())).findFirst();
        return connectionFactoryBean.map(b -> resolveDrainTimeout(b.getPropertyValues().getPropertyValue("drainTimeout")));

    }

    private Long resolveDrainTimeout(PropertyValue propertyValue) {
        if (propertyValue != null) {
            Object value = propertyValue.getValue();
            if (value != null && value instanceof Duration) {
                return ((Duration) value).getSeconds();
            }
        }
        return null;
    }

    protected boolean hasClass(String className) {
        try {
            return Class.forName(className) != null;
        } catch (Exception e) {
            return false;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy