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

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

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

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

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.*;
import jakarta.inject.Inject;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.reactive.messaging.Incoming;
import org.eclipse.microprofile.reactive.messaging.Outgoing;

import io.smallrye.reactive.messaging.*;
import io.smallrye.reactive.messaging.EmitterConfiguration;
import io.smallrye.reactive.messaging.PublisherDecorator;
import io.smallrye.reactive.messaging.SubscriberDecorator;
import io.smallrye.reactive.messaging.annotations.Incomings;
import io.smallrye.reactive.messaging.providers.AbstractMediator;
import io.smallrye.reactive.messaging.providers.MediatorFactory;
import io.smallrye.reactive.messaging.providers.connectors.WorkerPoolRegistry;
import io.smallrye.reactive.messaging.providers.wiring.Graph;
import io.smallrye.reactive.messaging.providers.wiring.Wiring;

/**
 * Class responsible for creating mediators instances and starting the management.
 */
@ApplicationScoped
public class MediatorManager {

    public static final String STRICT_MODE_PROPERTY = "smallrye-messaging-strict-binding";

    private final CollectedMediatorMetadata collected = new CollectedMediatorMetadata();

    @Inject
    MediatorFactory mediatorFactory;

    @Inject
    BeanManager beanManager;

    @Inject
    WorkerPoolRegistry workerPoolRegistry;

    @Inject
    // @Any would only be needed if we wanted to allow implementations with qualifiers
    Instance decorators;

    @Inject
    // @Any would only be needed if we wanted to allow implementations with qualifiers
    Instance subscriberDecorators;

    @Inject
    // @Any would only be needed if we wanted to allow implementations with qualifiers
    Instance converters;

    private final List emitters = new ArrayList<>();

    @Inject
    HealthCenter health;
    private final List channels = new ArrayList<>();
    @Inject
    ChannelRegistry registry;
    @Inject
    Wiring wiring;
    @Inject
    // @Any would only be needed if we wanted to allow implementations with qualifiers
    Instance registars;

    @Inject
    @ConfigProperty(name = STRICT_MODE_PROPERTY, defaultValue = "false")
    boolean strictMode;

    public  void analyze(AnnotatedType annotatedType, Bean bean) {

        if (strictMode) {
            collected.strict();
        }

        log.scanningType(annotatedType.getJavaClass());
        Set> methods = annotatedType.getMethods();

        methods.stream()
                .filter(this::hasMediatorAnnotations)
                .forEach(method -> {
                    if (shouldCollectMethod(method.getJavaMember(), collected)) {
                        collected.add(method.getJavaMember(), bean);
                    }
                });
    }

    /**
     * This method is used in the Quarkus extension.
     *
     * @param beanClass the bean class
     * @param bean the bean instance
     * @param  the type.
     */
    @SuppressWarnings("unused")
    public  void analyze(Class beanClass, Bean bean) {
        Class current = beanClass;
        while (current != Object.class) {
            Arrays.stream(current.getDeclaredMethods())
                    .filter(this::hasMediatorAnnotations)
                    .forEach(method -> {
                        if (shouldCollectMethod(method, collected)) {
                            collected.add(method, bean);
                        }
                    });
            current = current.getSuperclass();
        }
    }

    @SuppressWarnings("unused")
    public void addAnalyzed(Collection mediators) {
        collected.addAll(mediators);
    }

    public void addEmitter(EmitterConfiguration emitterConfiguration) {
        emitters.add(emitterConfiguration);
    }

    public void addChannel(ChannelConfiguration channel) {
        channels.add(channel);
    }

    /**
     * Checks if the given method is not an overloaded version of another method already included.
     */
    private boolean shouldCollectMethod(Method method, CollectedMediatorMetadata collected) {
        Optional existing = collected.mediators().stream()
                .filter(mc -> mc.getMethod().getDeclaringClass() == method.getDeclaringClass()
                        && mc.getMethod().getName().equals(method.getName())
                        && areParametersEquivalent(method, mc.getMethod()))
                .findAny();
        return !existing.isPresent();
    }

    private boolean areParametersEquivalent(Method method1, Method method2) {
        if (method1.getParameterCount() != method2.getParameterCount()) {
            return false;
        }
        for (int i = 0; i < method1.getParameterCount(); i++) {
            Class type1 = method1.getParameterTypes()[i];
            Class type2 = method2.getParameterTypes()[i];
            if (!(type1.isAssignableFrom(type2) || type2.isAssignableFrom(type1))) {
                return false;
            }
        }
        return true;
    }

    private  boolean hasMediatorAnnotations(AnnotatedMethod method) {
        return method.isAnnotationPresent(Incomings.class) || method.isAnnotationPresent(Incoming.class)
                || method.isAnnotationPresent(Outgoing.class);
    }

    private boolean hasMediatorAnnotations(Method m) {
        return m.isAnnotationPresent(Incomings.class) || m.isAnnotationPresent(Incoming.class)
                || m.isAnnotationPresent(Outgoing.class);
    }

    @SuppressWarnings("ConstantConditions")
    public AbstractMediator createMediator(MediatorConfiguration configuration) {
        AbstractMediator mediator = mediatorFactory.create(configuration);
        mediator.setDecorators(decorators);
        mediator.setSubscriberDecorators(subscriberDecorators);
        mediator.setConverters(converters);
        mediator.setHealth(health);
        mediator.setWorkerPoolRegistry(workerPoolRegistry);

        try {
            Object beanInstance = beanManager.getReference(configuration.getBean(), Object.class,
                    beanManager.createCreationalContext(configuration.getBean()));

            if (configuration.getInvokerClass() != null) {
                try {
                    Constructor constructorUsingBeanInstance = configuration.getInvokerClass()
                            .getConstructor(Object.class);
                    if (constructorUsingBeanInstance != null) {
                        mediator.setInvoker(constructorUsingBeanInstance.newInstance(beanInstance));
                    } else {
                        mediator.setInvoker(configuration.getInvokerClass().getDeclaredConstructor()
                                .newInstance());
                    }

                } catch (InstantiationException | IllegalAccessException e) {
                    log.unableToCreateInvoker(configuration.getInvokerClass(), e);
                    throw e;
                }
            }

            mediator.initialize(beanInstance);
        } catch (Throwable e) {
            log.unableToInitializeMediator(mediator.getMethodAsString(), e);
            throw new DefinitionException(e);
        }
        return mediator;
    }

    public void start() {
        // Register connectors and other "ends" managed externally.
        registars.stream().forEach(ChannelRegistar::initialize);

        wiring.prepare(strictMode, registry, emitters, channels, collected.mediators());
        Graph graph = wiring.resolve();

        if (graph.hasWiringErrors()) {
            DeploymentException composite = new DeploymentException("Wiring error(s) detected in application.");
            for (Exception error : graph.getWiringErrors()) {
                composite.addSuppressed(error);
            }
            throw composite;
        }

        graph.materialize(registry);

        health.markInitialized();
    }

    // Visible for testing purpose only.
    CollectedMediatorMetadata getCollected() {
        return collected;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy