package reactor.spring.messaging; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import org.reactivestreams.Processor; import reactor.core.Cancellation; import reactor.core.publisher.Flux; import reactor.core.publisher.TopicProcessor; import org.springframework.beans.factory.BeanNameAware; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.SubscribableChannel; import org.springframework.util.ObjectUtils; /** * Subscribable {@link org.springframework.messaging.MessageChannel} implementation that uses the RinBuffer-based * Reactor {@link reactor.core.publisher.TopicProcessor} to publish messages for efficiency at high volumes. * * @author Jon Brisbin * @author Stephane Maldini */ public class ReactorSubscribableChannel implements BeanNameAware, MessageChannel, SubscribableChannel { private final Map<MessageHandler, Cancellation> messageHandlerConsumers = new ConcurrentHashMap<>(); private final Processor<Message<?>, Message<?>> processor; private String beanName; /** * Create a default multi-threaded producer channel. */ public ReactorSubscribableChannel() { this(false); } /** * Create a {@literal ReactorSubscribableChannel} with a {@code ProducerType.SINGLE} if {@code * singleThreadedProducer} is {@code true}, otherwise use {@code ProducerType.MULTI}. * * @param singleThreadedProducer whether to create a single-threaded producer or not */ public ReactorSubscribableChannel(boolean singleThreadedProducer) { this.beanName = String.format("%s@%s", getClass().getSimpleName(), ObjectUtils.getIdentityHexString(this)); if (singleThreadedProducer) { this.processor = TopicProcessor.create(); } else { this.processor = TopicProcessor.share(); } } @Override public void setBeanName(String beanName) { this.beanName = beanName; } public String getBeanName() { return beanName; } @Override public boolean subscribe(final MessageHandler handler) { Consumer<Message<?>> consumer = handler::handleMessage; Cancellation c = Flux.from(processor).subscribe(consumer); messageHandlerConsumers.put(handler, c); return true; } @SuppressWarnings("unchecked") @Override public boolean unsubscribe(MessageHandler handler) { Cancellation control = messageHandlerConsumers.remove(handler); if (null == control) { return false; } control.dispose(); return true; } @Override public boolean send(Message<?> message) { return send(message, 0); } @Override public boolean send(Message<?> message, long timeout) { processor.onNext(message); return true; } }