Add initial support for RSockets (#2902)
* Add initial support for RSockets * Add `spring-integration-rsocket` module and respective dependencies * Implement `RSocketOutboundGateway` based on the Spring Messaging `RSocketRequester`. This component supports dynamic RSocket properties via expressions against request message. to handle `Publisher` for requests, it must be present in the request message `payload` instead of `FluxMessageChannel` upstream, since the last one just flattens events to be handled in the `MessageHandler` one by one. The result `Mono` is subscribed downstream in the `FluxMessageChannel` or directly by the `AbstractReplyProducingMessageHandler`. If result is a `Flux` it is just wrapped into the `Mono` to be processed downstream by end-user code. The point is that these request/replies are volatile and live in the particular context meanwhile a `FluxMessageChannel` is long living publisher in the application context boundaries. * The `RSocketOutboundGatewayIntegrationTests` is an adapted copy of `RSocketClientToServerIntegrationTests` from Spring Messaging * Add `doOnError()` into the `Flux` created in the `AbstractMessageProducingHandler` for `Publisher` replies * * Use singular for the `RSocket` term * Use no-op `Consumer` for the `strategiesConfigurer` and `factoryConfigurer` in the `RSocketOutboundGateway` and also `Assert.notNull()` in the appropriate setters to avoid null check during `RSocketRequester.builder()` initialization * Use `TcpServer.create().port(0)` in the `RSocketOutboundGatewayIntegrationTests` to allow to select free OS port and bind into it. The selected port is used later for client configuration in the `RSocketOutboundGateway` bean definition * * Change `RSocketOutboundGatewayIntegrationTests.PORT` to lower case
This commit is contained in:
committed by
Gary Russell
parent
f8f69c9129
commit
89e11f2c46
@@ -82,8 +82,8 @@ public class FluxMessageChannel extends AbstractMessageChannel
|
||||
ConnectableFlux<?> connectableFlux =
|
||||
Flux.from(publisher)
|
||||
.handle((message, sink) -> sink.next(send(message)))
|
||||
.onErrorContinue((throwable, o) -> logger.warn("Error during processing event: " + o, throwable)
|
||||
)
|
||||
.onErrorContinue((throwable, event) ->
|
||||
logger.warn("Error during processing event: " + event, throwable))
|
||||
.doOnComplete(() -> this.publishers.remove(publisher))
|
||||
.publish();
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.integration.IntegrationMessageHeaderAccessor;
|
||||
import org.springframework.integration.channel.ReactiveStreamsSubscribableChannel;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.routingslip.RoutingSlipRouteStrategy;
|
||||
@@ -283,6 +284,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
((ReactiveStreamsSubscribableChannel) messageChannel)
|
||||
.subscribeTo(
|
||||
Flux.from((Publisher<?>) reply)
|
||||
.doOnError((ex) -> sendErrorMessage(requestMessage, ex))
|
||||
.map(result -> createOutputMessage(result, requestHeaders)));
|
||||
}
|
||||
}
|
||||
@@ -311,25 +313,22 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
}
|
||||
|
||||
private void asyncNonReactiveReply(Message<?> requestMessage, Object reply, Object replyChannel) {
|
||||
|
||||
ListenableFuture<?> future;
|
||||
if (reply instanceof ListenableFuture<?>) {
|
||||
future = (ListenableFuture<?>) reply;
|
||||
}
|
||||
else {
|
||||
SettableListenableFuture<Object> settableListenableFuture = new SettableListenableFuture<>();
|
||||
|
||||
Mono.from((Publisher<?>) reply)
|
||||
.subscribe(settableListenableFuture::set, settableListenableFuture::setException);
|
||||
|
||||
future = settableListenableFuture;
|
||||
}
|
||||
|
||||
future.addCallback(new ReplyFutureCallback(requestMessage, replyChannel));
|
||||
}
|
||||
|
||||
private Object getOutputChannelFromRoutingSlip(Object reply, Message<?> requestMessage, List<?> routingSlip,
|
||||
AtomicInteger routingSlipIndex) {
|
||||
|
||||
if (routingSlipIndex.get() >= routingSlip.size()) {
|
||||
return null;
|
||||
}
|
||||
@@ -365,7 +364,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
}
|
||||
|
||||
protected Message<?> createOutputMessage(Object output, MessageHeaders requestHeaders) {
|
||||
AbstractIntegrationMessageBuilder<?> builder = null;
|
||||
AbstractIntegrationMessageBuilder<?> builder;
|
||||
if (output instanceof Message<?>) {
|
||||
if (this.noHeadersPropagation || !shouldCopyRequestHeaders()) {
|
||||
return (Message<?>) output;
|
||||
@@ -449,7 +448,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
}
|
||||
catch (Exception e) {
|
||||
Exception exceptionToLog =
|
||||
IntegrationUtils.wrapInHandlingExceptionIfNecessary(requestMessage, () -> null, e);
|
||||
IntegrationUtils.wrapInHandlingExceptionIfNecessary(requestMessage, () -> null, e);
|
||||
logger.error("Failed to send async reply", exceptionToLog);
|
||||
}
|
||||
}
|
||||
@@ -459,7 +458,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
Object errorChannel = requestHeaders.getErrorChannel();
|
||||
if (errorChannel == null) {
|
||||
try {
|
||||
errorChannel = getChannelResolver().resolveDestination("errorChannel");
|
||||
errorChannel = getChannelResolver().resolveDestination(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
|
||||
}
|
||||
catch (DestinationResolutionException e) {
|
||||
// ignore
|
||||
|
||||
@@ -87,6 +87,9 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
protected ClassLoader getBeanClassLoader() {
|
||||
return this.beanClassLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onInit() {
|
||||
|
||||
Reference in New Issue
Block a user