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

io.smallrye.reactive.messaging.providers.extension.ReactiveMessagingExtension Maven / Gradle / Ivy

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

import static io.smallrye.reactive.messaging.providers.i18n.ProviderLogging.log;

import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.Flow;

import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.*;
import jakarta.inject.Inject;

import org.eclipse.microprofile.reactive.messaging.*;
import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder;
import org.reactivestreams.Publisher;

import io.smallrye.reactive.messaging.EmitterConfiguration;
import io.smallrye.reactive.messaging.EmitterFactory;
import io.smallrye.reactive.messaging.EmitterType;
import io.smallrye.reactive.messaging.annotations.Blocking;
import io.smallrye.reactive.messaging.annotations.Broadcast;
import io.smallrye.reactive.messaging.annotations.EmitterFactoryFor;
import io.smallrye.reactive.messaging.annotations.Incomings;
import io.smallrye.reactive.messaging.providers.DefaultEmitterConfiguration;
import io.smallrye.reactive.messaging.providers.connectors.WorkerPoolRegistry;
import io.smallrye.reactive.messaging.providers.i18n.ProviderExceptions;

public class ReactiveMessagingExtension implements Extension {

    private final List> mediatorBeans = new ArrayList<>();
    private final List streamInjectionPoints = new ArrayList<>();
    private final Map emitterInjectionPoints = new HashMap();
    private final List> emitterFactoryBeans = new ArrayList<>();
    private final List> workerPoolBeans = new ArrayList<>();

    @Inject
    HealthCenter health;

     void processClassesContainingMediators(@Observes ProcessManagedBean event) {
        AnnotatedType annotatedType = event.getAnnotatedBeanClass();
        if (annotatedType.getMethods()
                .stream()
                .anyMatch(m -> m.isAnnotationPresent(Incomings.class) || m.isAnnotationPresent(Incoming.class)
                        || m.isAnnotationPresent(Outgoing.class))) {
            mediatorBeans.add(new MediatorBean<>(event.getBean(), event.getAnnotatedBeanClass()));
        }
    }

    > void processEmitterFactories(
            @Observes @WithAnnotations({ EmitterFactoryFor.class }) ProcessAnnotatedType event) {
        AnnotatedType annotatedType = event.getAnnotatedType();
        emitterFactoryBeans.add(new EmitterFactoryBean<>(annotatedType));
    }

     void processBlockingAnnotation(@Observes @WithAnnotations({ Blocking.class }) ProcessAnnotatedType event) {
        AnnotatedType annotatedType = event.getAnnotatedType();
        workerPoolBeans.add(new WorkerPoolBean<>(annotatedType));
    }

    > void processStreamPublisherInjectionPoint(@Observes ProcessInjectionPoint pip) {
        Channel stream = ChannelProducer.getChannelQualifier(pip.getInjectionPoint());
        if (stream != null) {
            streamInjectionPoints.add(pip.getInjectionPoint());
        }
    }

    > void processStreamReactiveStreamPublisherInjectionPoint(
            @Observes ProcessInjectionPoint pip) {
        Channel stream = ChannelProducer.getChannelQualifier(pip.getInjectionPoint());
        if (stream != null) {
            streamInjectionPoints.add(pip.getInjectionPoint());
        }
    }

    void processStreamSpecEmitterInjectionPoint(@Observes ProcessInjectionPoint> pip) {
        Channel stream = ChannelProducer.getChannelQualifier(pip.getInjectionPoint());
        if (stream != null) {
            EmitterFactoryFor emitterType = emitterType(pip.getInjectionPoint(), emitterFactoryBeans);
            if (emitterType != null) {
                emitterInjectionPoints.put(pip.getInjectionPoint(), emitterType);
            }
        }
    }

     void processStreamEmitterInjectionPoint(@Observes ProcessInjectionPoint pip) {
        Channel stream = ChannelProducer.getChannelQualifier(pip.getInjectionPoint());
        if (stream != null) {
            EmitterFactoryFor emitterType = emitterType(pip.getInjectionPoint(), emitterFactoryBeans);
            if (emitterType != null) {
                emitterInjectionPoints.put(pip.getInjectionPoint(), emitterType);
            }
        }
    }

    > void processStreamPublisherBuilderInjectionPoint(
            @Observes ProcessInjectionPoint pip) {
        Channel stream = ChannelProducer.getChannelQualifier(pip.getInjectionPoint());
        if (stream != null) {
            streamInjectionPoints.add(pip.getInjectionPoint());
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    void afterDeploymentValidation(@Observes AfterDeploymentValidation done, BeanManager beanManager) {
        Instance instance = beanManager.createInstance();
        MediatorManager mediatorManager = instance.select(MediatorManager.class).get();
        WorkerPoolRegistry workerPoolRegistry = instance.select(WorkerPoolRegistry.class).get();

        List emitters = createEmitterConfigurations();
        for (EmitterConfiguration emitter : emitters) {
            mediatorManager.addEmitter(emitter);
        }

        List channels = createChannelConfigurations();
        for (ChannelConfiguration channel : channels) {
            mediatorManager.addChannel(channel);
        }

        for (MediatorBean mediatorBean : mediatorBeans) {
            log.analyzingMediatorBean(mediatorBean.bean);
            mediatorManager.analyze(mediatorBean.annotatedType, mediatorBean.bean);
        }

        for (WorkerPoolBean workerPoolBean : workerPoolBeans) {
            workerPoolRegistry.analyzeWorker(workerPoolBean.annotatedType);
        }

        mediatorManager.start();
    }

    private List createChannelConfigurations() {
        List channels = new ArrayList<>();
        for (InjectionPoint ip : streamInjectionPoints) {
            String name = ChannelProducer.getChannelName(ip);
            channels.add(new ChannelConfiguration(name));
        }
        return channels;
    }

    private List createEmitterConfigurations() {
        List emitters = new ArrayList<>();
        createEmitterConfiguration(emitterInjectionPoints, emitters);
        return emitters;
    }

    private void createEmitterConfiguration(Map emitterInjectionPoints,
            List emitters) {
        for (Map.Entry entry : emitterInjectionPoints.entrySet()) {
            InjectionPoint point = entry.getKey();
            EmitterFactoryFor emitterType = entry.getValue();
            String name = ChannelProducer.getChannelName(point);
            OnOverflow onOverflow = point.getAnnotated().getAnnotation(OnOverflow.class);
            if (onOverflow == null) {
                onOverflow = createOnOverflowForLegacyAnnotation(point);
            }
            Broadcast broadcast = point.getAnnotated().getAnnotation(Broadcast.class);
            emitters.add(new DefaultEmitterConfiguration(name, emitterType, onOverflow, broadcast));
        }
    }

    @SuppressWarnings("deprecation")
    private OnOverflow createOnOverflowForLegacyAnnotation(InjectionPoint point) {
        io.smallrye.reactive.messaging.annotations.OnOverflow legacy = point.getAnnotated()
                .getAnnotation(io.smallrye.reactive.messaging.annotations.OnOverflow.class);
        if (legacy != null) {
            return new OnOverflow() {

                @Override
                public Class annotationType() {
                    return OnOverflow.class;
                }

                @Override
                public Strategy value() {
                    return Strategy.valueOf(legacy.value().name());
                }

                @Override
                public long bufferSize() {
                    return legacy.bufferSize();
                }
            };
        }
        return null;
    }

    private EmitterFactoryFor emitterType(InjectionPoint point, List> emitterFactoryBeans) {
        for (EmitterFactoryBean emitterFactoryBean : emitterFactoryBeans) {
            EmitterFactoryFor annotation = emitterFactoryBean.emitterFactoryType.getAnnotation(EmitterFactoryFor.class);
            Type type = point.getType();
            if (type instanceof ParameterizedType && ((ParameterizedType) type).getActualTypeArguments().length > 0) {
                if (((ParameterizedType) type).getRawType().equals(annotation.value())) {
                    return annotation;
                }
            } else {
                throw ProviderExceptions.ex.invalidRawEmitter(point);
            }
        }
        return null;
    }

    static class MediatorBean {

        final Bean bean;

        final AnnotatedType annotatedType;

        MediatorBean(Bean bean, AnnotatedType annotatedType) {
            this.bean = bean;
            this.annotatedType = annotatedType;
        }

    }

    static class WorkerPoolBean {
        final AnnotatedType annotatedType;

        WorkerPoolBean(AnnotatedType annotatedType) {
            this.annotatedType = annotatedType;
        }
    }

    static class EmitterFactoryBean {
        final AnnotatedType emitterFactoryType;

        EmitterFactoryBean(AnnotatedType emitterFactoryType) {
            this.emitterFactoryType = emitterFactoryType;
        }
    }
}