/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.processor.strategy;
import static org.mule.runtime.api.i18n.I18nMessageFactory.createStaticMessage;
import static org.mule.runtime.core.transaction.TransactionCoordination.isTransactionActive;
import org.mule.runtime.api.lifecycle.Disposable;
import org.mule.runtime.api.scheduler.Scheduler;
import org.mule.runtime.core.api.DefaultMuleException;
import org.mule.runtime.core.api.Event;
import org.mule.runtime.core.api.construct.FlowConstruct;
import org.mule.runtime.core.api.processor.ReactiveProcessor;
import org.mule.runtime.core.api.processor.Sink;
import org.mule.runtime.core.api.processor.strategy.ProcessingStrategy;
import org.mule.runtime.core.exception.MessagingException;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import reactor.core.publisher.BlockingSink;
import reactor.core.publisher.FluxSink;
/**
* Abstract base {@link ProcessingStrategy} that creates a basic {@link Sink} that serializes events.
*/
public abstract class AbstractProcessingStrategy implements ProcessingStrategy {
public static final String TRANSACTIONAL_ERROR_MESSAGE = "Unable to process a transactional flow asynchronously";
@Override
public Sink createSink(FlowConstruct flowConstruct, ReactiveProcessor pipeline) {
return new DirectSink(pipeline, createOnEventConsumer());
}
protected Consumer<Event> createOnEventConsumer() {
return event -> {
if (isTransactionActive()) {
event.getContext().error(new MessagingException(event,
new DefaultMuleException(createStaticMessage(TRANSACTIONAL_ERROR_MESSAGE))));
}
};
}
protected ExecutorService decorateScheduler(Scheduler scheduler) {
return scheduler;
}
/**
* Implementation of {@link Sink} using Reactor's {@link FluxSink} to accept events.
*/
static final class ReactorSink implements Sink, Disposable {
private final BlockingSink<Event> blockingSink;
private final reactor.core.Disposable disposable;
private final Consumer onEventConsumer;
ReactorSink(BlockingSink<Event> blockingSink, reactor.core.Disposable disposable,
Consumer<Event> onEventConsumer) {
this.blockingSink = blockingSink;
this.disposable = disposable;
this.onEventConsumer = onEventConsumer;
}
@Override
public void accept(Event event) {
onEventConsumer.accept(event);
// TODO MULE-11449 Implement handling of back-pressure via OVERLOAD exception type.
blockingSink.accept(event);
}
@Override
public void dispose() {
blockingSink.complete();
disposable.dispose();
}
}
}