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

io.smallrye.reactive.messaging.providers.AbstractMediator Maven / Gradle / Ivy

package io.smallrye.reactive.messaging.providers;

import static io.smallrye.reactive.messaging.providers.helpers.CDIUtils.getSortedInstances;
import static io.smallrye.reactive.messaging.providers.i18n.ProviderExceptions.ex;
import static io.smallrye.reactive.messaging.providers.i18n.ProviderLogging.log;
import static io.smallrye.reactive.messaging.providers.i18n.ProviderMessages.msg;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Flow;
import java.util.function.Function;

import jakarta.enterprise.inject.Instance;

import org.eclipse.microprofile.reactive.messaging.Acknowledgment;
import org.eclipse.microprofile.reactive.messaging.Message;

import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.smallrye.reactive.messaging.Invoker;
import io.smallrye.reactive.messaging.MediatorConfiguration;
import io.smallrye.reactive.messaging.MessageConverter;
import io.smallrye.reactive.messaging.PublisherDecorator;
import io.smallrye.reactive.messaging.SubscriberDecorator;
import io.smallrye.reactive.messaging.providers.connectors.WorkerPoolRegistry;
import io.smallrye.reactive.messaging.providers.extension.HealthCenter;
import io.smallrye.reactive.messaging.providers.helpers.BroadcastHelper;
import io.smallrye.reactive.messaging.providers.helpers.ConverterUtils;
import io.smallrye.reactive.messaging.providers.locals.LocalContextMetadata;
import io.vertx.mutiny.core.Context;
import io.vertx.mutiny.core.Vertx;

public abstract class AbstractMediator {

    protected final MediatorConfiguration configuration;
    protected WorkerPoolRegistry workerPoolRegistry;
    private Invoker invoker;
    private Instance decorators;

    private Instance subscriberDecorators;
    protected HealthCenter health;
    private Instance converters;

    public AbstractMediator(MediatorConfiguration configuration) {
        this.configuration = configuration;
    }

    public synchronized void setInvoker(Invoker invoker) {
        this.invoker = invoker;
    }

    public void setDecorators(Instance decorators) {
        this.decorators = decorators;
    }

    public void setSubscriberDecorators(Instance decorators) {
        this.subscriberDecorators = decorators;
    }

    public void setConverters(Instance converters) {
        this.converters = converters;
    }

    public void setWorkerPoolRegistry(WorkerPoolRegistry workerPoolRegistry) {
        this.workerPoolRegistry = workerPoolRegistry;
    }

    public void run() {
        // Do nothing by default.
    }

    public void connectToUpstream(Multi> publisher) {
        // Do nothing by default.
    }

    public MediatorConfiguration configuration() {
        return configuration;
    }

    public void initialize(Object bean) {
        // Method overriding initialize MUST call super(bean).
        synchronized (this) {
            if (this.invoker == null) {
                this.invoker = args -> {
                    try {
                        return this.configuration.getMethod().invoke(bean, args);
                    } catch (Exception e) {
                        throw ex.processingException(configuration.methodAsString(), e);
                    }
                };
            }
        }
        Objects.requireNonNull(this.invoker, msg.invokerNotInitialized());
        if (this.configuration.isBlocking()) {
            Objects.requireNonNull(this.workerPoolRegistry, msg.workerPoolNotInitialized());
        }
    }

    @SuppressWarnings("unchecked")
    protected  T invoke(Object... args) {
        try {
            return (T) this.invoker.invoke(args);
        } catch (RuntimeException e) { // NOSONAR
            log.methodException(configuration().methodAsString(), e);
            throw e;
        }
    }

    protected  Uni invokeOnMessageContext(Message message, Object... args) {
        return LocalContextMetadata.invokeOnMessageContext(message, x -> invoke(args));
    }

    @SuppressWarnings("unchecked")
    protected  Uni invokeBlocking(Message message, Object... args) {
        try {
            Optional metadata = message != null ? message.getMetadata().get(LocalContextMetadata.class)
                    : Optional.empty();
            Context currentContext = metadata.map(m -> Context.newInstance(m.context()))
                    .orElseGet(Vertx::currentContext);
            return workerPoolRegistry.executeWork(currentContext,
                    Uni.createFrom().emitter(emitter -> {
                        try {
                            Object result = this.invoker.invoke(args);
                            if (result instanceof CompletionStage) {
                                ((CompletionStage) result).thenAccept(x -> emitter.complete((T) x));
                            } else {
                                emitter.complete((T) result);
                            }
                        } catch (RuntimeException e) {
                            log.methodException(configuration().methodAsString(), e);
                            emitter.fail(e);
                        }
                    }),
                    configuration.getWorkerPoolName(),
                    configuration.isBlockingExecutionOrdered());
        } catch (RuntimeException e) {
            log.methodException(configuration().methodAsString(), e);
            throw e;
        }
    }

    protected CompletionStage> getAckOrCompletion(Message message) {
        CompletionStage ack = message.ack();
        if (ack != null) {
            return ack.thenApply(x -> message);
        } else {
            return CompletableFuture.completedFuture(message);
        }
    }

    public Multi> getStream() {
        return null;
    }

    public MediatorConfiguration getConfiguration() {
        return configuration;
    }

    public String getMethodAsString() {
        return configuration.methodAsString();
    }

    public Flow.Subscriber> getComputedSubscriber() {
        return null;
    }

    public abstract boolean isConnected();

    protected Function, ? extends CompletionStage>> managePreProcessingAck() {
        return this::handlePreProcessingAck;
    }

    protected CompletionStage> handlePreProcessingAck(Message message) {
        if (configuration.getAcknowledgment() == Acknowledgment.Strategy.PRE_PROCESSING) {
            return getAckOrCompletion(message);
        }
        return CompletableFuture.completedFuture(message);
    }

    public Multi> decorate(Multi> input) {
        if (input == null) {
            return null;
        }

        for (PublisherDecorator decorator : getSortedInstances(decorators)) {
            input = decorator.decorate(input, getConfiguration().getOutgoing(), false);
        }

        if (configuration.getBroadcast()) {
            return BroadcastHelper.broadcastPublisher(input, configuration.getNumberOfSubscriberBeforeConnecting());
        } else {
            return input;
        }
    }

    public Multi> decorateSubscriberSource(Multi> input) {
        if (input == null) {
            return null;
        }

        for (SubscriberDecorator decorator : getSortedInstances(subscriberDecorators)) {
            input = decorator.decorate(input, configuration.getIncoming(), false);
        }
        return input;
    }

    public void setHealth(HealthCenter health) {
        this.health = health;
    }

    public Multi> convert(Multi> upstream) {
        return ConverterUtils.convert(upstream, converters, configuration.getIngestedPayloadType());
    }

    public void terminate() {
        // Do nothing by default.
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy