Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.smallrye.reactive.messaging.providers.ProcessorMediator Maven / Gradle / Ivy
package io.smallrye.reactive.messaging.providers;
import static io.smallrye.reactive.messaging.MediatorConfiguration.Production.STREAM_OF_MESSAGE;
import static io.smallrye.reactive.messaging.MediatorConfiguration.Production.STREAM_OF_PAYLOAD;
import static io.smallrye.reactive.messaging.providers.i18n.ProviderExceptions.ex;
import static io.smallrye.reactive.messaging.providers.i18n.ProviderMessages.msg;
import java.util.Objects;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Flow;
import java.util.function.Function;
import org.eclipse.microprofile.reactive.messaging.Acknowledgment;
import org.eclipse.microprofile.reactive.messaging.Message;
import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder;
import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder;
import org.reactivestreams.Processor;
import org.reactivestreams.Publisher;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.smallrye.reactive.messaging.MediatorConfiguration;
import io.smallrye.reactive.messaging.Shape;
import io.smallrye.reactive.messaging.providers.helpers.ClassUtils;
import io.smallrye.reactive.messaging.providers.helpers.MultiUtils;
import mutiny.zero.flow.adapters.AdaptersToFlow;
public class ProcessorMediator extends AbstractMediator {
private Function>, Multi>> mapper;
private Multi> publisher;
public ProcessorMediator(MediatorConfiguration configuration) {
super(configuration);
if (configuration.shape() != Shape.PROCESSOR) {
throw ex.illegalArgumentForProcessorShape(configuration.shape());
}
// IMPORTANT When returning a Multi, Publisher or a PublisherBuilder, you can't mix payloads and messages.
if (configuration.production() == STREAM_OF_MESSAGE
&& configuration.consumption() == MediatorConfiguration.Consumption.PAYLOAD) {
throw ex.definitionProduceMessageStreamAndConsumePayload(configuration.methodAsString());
}
if (configuration.production() == STREAM_OF_PAYLOAD
&& configuration.consumption() == MediatorConfiguration.Consumption.MESSAGE) {
throw ex.definitionProducePayloadStreamAndConsumeMessage(configuration.methodAsString());
}
}
@Override
public void connectToUpstream(Multi> publisher) {
assert mapper != null;
this.publisher = decorate(publisher.plug(m -> mapper.apply(convert(m))));
}
@Override
public Multi> getStream() {
return Objects.requireNonNull(publisher);
}
@Override
public boolean isConnected() {
return publisher != null;
}
@Override
protected Uni invokeBlocking(Message message, Object... args) {
return super.invokeBlocking(message, args);
}
@Override
public void initialize(Object bean) {
super.initialize(bean);
// Supported signatures:
// 1. Flow.Processor, Message>, Processor, Message>, ProcessorBuilder, Message> method()
// 2. Flow.Processor, Processor, ProcessorBuilder method()
// 5. Flow.Publisher>, Publisher>, PublisherBuilder> method(Message msg)
// 6. Flow.Publisher, Publisher, PublisherBuilder method(I payload)
// 9. Message method(Message msg)
// 10. O method(I payload)
// 11. CompletionStage method(I payload)
// 12. CompletionStage> method(Message msg)
// IMPORTANT When returning a Publisher or a PublisherBuilder, you can't mix payloads and messages
switch (configuration.production()) {
case STREAM_OF_MESSAGE:
// Case 1, 5
if (isReturningAProcessorOrAReactiveStreamsProcessorOrAProcessorBuilder()) {
// Case 1
if (configuration.usesBuilderTypes()) {
processMethodReturningAProcessorBuilderOfMessages();
} else if (configuration.usesReactiveStreams()) {
processMethodReturningAReactiveStreamsProcessorOfMessages();
} else {
processMethodReturningAProcessorOfMessages();
}
} else if (isReturningAPublisherOrAReactiveStreamsPublisherOrAPublisherBuilder()) {
// Case 5
if (configuration.usesBuilderTypes()) {
processMethodReturningAPublisherBuilderOfMessageAndConsumingMessages();
} else if (configuration.usesReactiveStreams()) {
processMethodReturningAReactiveStreamsPublisherOfMessageAndConsumingMessages();
} else {
processMethodReturningAPublisherOfMessageAndConsumingMessages();
}
} else {
throw ex.illegalArgumentForInitialize(configuration.methodAsString());
}
break;
case STREAM_OF_PAYLOAD:
// Case 2, 6
if (isReturningAProcessorOrAReactiveStreamsProcessorOrAProcessorBuilder()) {
// Case 2
if (configuration.usesBuilderTypes()) {
processMethodReturningAProcessorBuilderOfPayloads();
} else if (configuration.usesReactiveStreams()) {
processMethodReturningAReactiveStreamsProcessorOfPayloads();
} else {
processMethodReturningAProcessorOfPayloads();
}
} else if (isReturningAPublisherOrAReactiveStreamsPublisherOrAPublisherBuilder()) {
// Case 6
if (configuration.usesBuilderTypes()) {
processMethodReturningAPublisherBuilderOfPayloadsAndConsumingPayloads();
} else if (configuration.usesReactiveStreams()) {
processMethodReturningAReactiveStreamsPublisherOfPayloadsAndConsumingPayloads();
} else {
processMethodReturningAPublisherOfPayloadsAndConsumingPayloads();
}
} else {
throw ex.illegalArgumentForInitialize(configuration.methodAsString());
}
break;
case INDIVIDUAL_MESSAGE:
// Case 9
processMethodReturningIndividualMessageAndConsumingIndividualItem();
break;
case INDIVIDUAL_PAYLOAD:
// Case 10
processMethodReturningIndividualPayloadAndConsumingIndividualItem();
break;
case COMPLETION_STAGE_OF_MESSAGE:
// Case 11
processMethodReturningACompletionStageOfMessageAndConsumingIndividualItem();
break;
case COMPLETION_STAGE_OF_PAYLOAD:
// Case 12
processMethodReturningACompletionStageOfPayloadAndConsumingIndividualItem();
break;
case UNI_OF_MESSAGE:
// Case 11 - Uni variant
processMethodReturningAUniOfMessageAndConsumingIndividualItem();
break;
case UNI_OF_PAYLOAD:
// Case 12 - Uni variant
processMethodReturningAUniOfPayloadAndConsumingIndividualItem();
break;
default:
throw ex.illegalArgumentForUnexpectedProduction(configuration.production());
}
}
@SuppressWarnings("unchecked")
private void processMethodReturningAPublisherBuilderOfMessageAndConsumingMessages() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
msg -> AdaptersToFlow.publisher(((PublisherBuilder>) invoke(msg)).buildRs()));
}
@SuppressWarnings("unchecked")
private void processMethodReturningAReactiveStreamsPublisherOfMessageAndConsumingMessages() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
msg -> AdaptersToFlow.publisher((Publisher>) invoke(msg)));
}
@SuppressWarnings("unchecked")
private void processMethodReturningAPublisherOfMessageAndConsumingMessages() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(msg -> (Flow.Publisher>) invoke(msg));
}
private void processMethodReturningAProcessorBuilderOfMessages() {
ProcessorBuilder, Message> builder = Objects.requireNonNull(invoke(),
msg.methodReturnedNull(configuration.methodAsString()));
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return MultiUtils.via(multi, AdaptersToFlow.processor(builder.buildRs()));
};
}
private void processMethodReturningAReactiveStreamsProcessorOfMessages() {
Processor, Message> result = Objects.requireNonNull(invoke(),
msg.methodReturnedNull(configuration.methodAsString()));
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return MultiUtils.via(multi, AdaptersToFlow.processor(result));
};
}
private void processMethodReturningAProcessorOfMessages() {
Flow.Processor, Message> result = Objects.requireNonNull(invoke(),
msg.methodReturnedNull(configuration.methodAsString()));
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return MultiUtils.via(multi, result);
};
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void processMethodReturningAProcessorBuilderOfPayloads() {
ProcessorBuilder returnedProcessorBuilder = invoke();
Objects.requireNonNull(returnedProcessorBuilder, msg.methodReturnedNull(configuration.methodAsString()));
this.mapper = upstream -> {
Multi multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transform(Message::getPayload);
return MultiUtils.via(multi, AdaptersToFlow.processor(returnedProcessorBuilder.buildRs()))
.onItem().transform(Message::of);
};
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void processMethodReturningAReactiveStreamsProcessorOfPayloads() {
Processor returnedProcessor = invoke();
Objects.requireNonNull(returnedProcessor, msg.methodReturnedNull(configuration.methodAsString()));
this.mapper = upstream -> {
Multi multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transform(Message::getPayload);
return MultiUtils.via(multi, AdaptersToFlow.processor(returnedProcessor))
.onItem().transform(Message::of);
};
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void processMethodReturningAProcessorOfPayloads() {
Flow.Processor returnedProcessor = invoke();
Objects.requireNonNull(returnedProcessor, msg.methodReturnedNull(configuration.methodAsString()));
this.mapper = upstream -> {
Multi multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transform(Message::getPayload);
return MultiUtils.via(multi, returnedProcessor)
.onItem().transform(Message::of);
};
}
private void processMethodReturningAPublisherBuilderOfPayloadsAndConsumingPayloads() {
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return multi.onItem().transformToMultiAndConcatenate(message -> {
PublisherBuilder pb = invoke(message.getPayload());
return MultiUtils.publisher(AdaptersToFlow.publisher(pb.buildRs()))
.onItem().transform(payload -> Message.of(payload, message.getMetadata()));
// TODO We can handle post-acknowledgement here. -> onCompletion
});
};
}
private void processMethodReturningAReactiveStreamsPublisherOfPayloadsAndConsumingPayloads() {
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return multi.onItem().transformToMultiAndConcatenate(message -> {
Publisher pb = invoke(message.getPayload());
return MultiUtils.publisher(AdaptersToFlow.publisher(pb))
.onItem().transform(payload -> Message.of(payload, message.getMetadata()));
// TODO We can handle post-acknowledgement here. -> onCompletion
});
};
}
private void processMethodReturningAPublisherOfPayloadsAndConsumingPayloads() {
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return multi.onItem().transformToMultiAndConcatenate(message -> {
Flow.Publisher pub = invoke(message.getPayload());
return MultiUtils.publisher(pub)
.onItem().transform(payload -> Message.of(payload, message.getMetadata()));
// TODO We can handle post-acknowledgement here. -> onCompletion
});
};
}
private void processMethodReturningIndividualMessageAndConsumingIndividualItem() {
// Item can be a message or a payload
if (configuration.isBlocking()) {
if (configuration.isBlockingExecutionOrdered()) {
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return multi
.onItem()
.transformToMultiAndConcatenate(message -> invokeBlocking(message, withPayloadOrMessage(message))
.onItemOrFailure()
.transformToUni((o, t) -> this.handlePostInvocationWithMessage((Message) o, t))
.onItem().transformToMulti(this::handleSkip));
};
} else {
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return multi
.onItem().transformToMultiAndMerge(message -> invokeBlocking(message, withPayloadOrMessage(message))
.onItemOrFailure()
.transformToUni((o, t) -> this.handlePostInvocationWithMessage((Message) o, t))
.onItem().transformToMulti(this::handleSkip));
};
}
} else {
this.mapper = upstream -> {
Multi> multi = MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration);
return multi
.onItem().transformToMultiAndConcatenate(
message -> invokeOnMessageContext(message, withPayloadOrMessage(message))
.onItem().transform(o -> (Message) o)
.onItemOrFailure().transformToUni(this::handlePostInvocationWithMessage)
.onItem().transformToMulti(this::handleSkip));
};
}
}
private boolean isPostAck() {
return configuration.getAcknowledgment() == Acknowledgment.Strategy.POST_PROCESSING;
}
private void processMethodReturningIndividualPayloadAndConsumingIndividualItem() {
// Item can be message or payload.
if (configuration.isBlocking()) {
if (configuration.isBlockingExecutionOrdered()) {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem()
.transformToMultiAndConcatenate(message -> invokeBlocking(message, withPayloadOrMessage(message))
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocation(message, r, f))
.onItem().transformToMulti(this::handleSkip));
} else {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndMerge(message -> invokeBlocking(message, withPayloadOrMessage(message))
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocation(message, r, f))
.onItem().transformToMulti(this::handleSkip));
}
} else {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
message -> invokeOnMessageContext(message, withPayloadOrMessage(message))
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocation(message, r, f))
.onItem().transformToMulti(this::handleSkip));
}
}
private Flow.Publisher> handleSkip(Message m) {
if (m == null) { // If message is null, skip.
return Multi.createFrom().empty();
} else {
return Multi.createFrom().item(m);
}
}
private Uni> handlePostInvocation(Message message, Object res, Throwable fail) {
if (fail != null) {
if (isPostAck()) {
return Uni.createFrom()
.completionStage(message.nack(fail).thenApply(x -> null));
} else {
throw ex.processingException(getMethodAsString(), fail);
}
} else if (res != null) {
if (isPostAck()) {
return Uni.createFrom().item(message.withPayload(res));
} else {
return Uni.createFrom().item(Message.of(res, message.getMetadata()));
}
} else {
// the method returned null, the message is not forwarded, but we ack the message in post ack
if (isPostAck()) {
return Uni.createFrom()
.completionStage(message.ack().thenApply(x -> null));
} else {
return Uni.createFrom().nullItem();
}
}
}
private Uni> handlePostInvocationWithMessage(Message res,
Throwable fail) {
if (fail != null) {
throw ex.processingException(getMethodAsString(), fail);
} else if (res != null) {
return Uni.createFrom().item((Message) res);
} else {
// the method returned null, the message is not forwarded
return Uni.createFrom().nullItem();
}
}
private void processMethodReturningACompletionStageOfMessageAndConsumingIndividualItem() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
message -> invokeOnMessageContext(message, withPayloadOrMessage(message))
.onItem().transformToUni(cs -> Uni.createFrom().completionStage((CompletionStage) cs))
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocationWithMessage((Message) r, f))
.onItem().transformToMulti(this::handleSkip));
}
private void processMethodReturningAUniOfMessageAndConsumingIndividualItem() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
message -> invokeOnMessageContext(message, withPayloadOrMessage(message))
.onItem().transformToUni(u -> (Uni) u)
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocationWithMessage((Message) r, f))
.onItem().transformToMulti(this::handleSkip));
}
private void processMethodReturningACompletionStageOfPayloadAndConsumingIndividualItem() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
message -> invokeOnMessageContext(message, withPayloadOrMessage(message))
.onItem().transformToUni(cs -> Uni.createFrom().completionStage((CompletionStage) cs))
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocation(message, r, f))
.onItem().transformToMulti(this::handleSkip));
}
private void processMethodReturningAUniOfPayloadAndConsumingIndividualItem() {
this.mapper = upstream -> MultiUtils.handlePreProcessingAcknowledgement(upstream, configuration)
.onItem().transformToMultiAndConcatenate(
message -> invokeOnMessageContext(message, withPayloadOrMessage(message))
.onItem().transformToUni(u -> (Uni) u)
.onItemOrFailure().transformToUni((r, f) -> handlePostInvocation(message, r, f))
.onItem().transformToMulti(this::handleSkip));
}
private boolean isReturningAPublisherOrAReactiveStreamsPublisherOrAPublisherBuilder() {
Class returnType = configuration.getReturnType();
return ClassUtils.isAssignable(returnType, Flow.Publisher.class)
|| ClassUtils.isAssignable(returnType, Publisher.class)
|| ClassUtils.isAssignable(returnType, PublisherBuilder.class);
}
private boolean isReturningAProcessorOrAReactiveStreamsProcessorOrAProcessorBuilder() {
Class returnType = configuration.getReturnType();
return ClassUtils.isAssignable(returnType, Flow.Processor.class)
|| ClassUtils.isAssignable(returnType, Processor.class)
|| ClassUtils.isAssignable(returnType, ProcessorBuilder.class);
}
private Object withPayloadOrMessage(Message message) {
return (configuration.consumption() == MediatorConfiguration.Consumption.PAYLOAD) ? message.getPayload() : message;
}
}