Upgrade to Reactor 3.1

Polishing

- remove catch from test
- update netty for stomp

Add reactiveErrorHandler to AbstractMessageHandler
This commit is contained in:
Gary Russell
2017-04-14 17:30:05 -04:00
parent da1b635d99
commit effca79f3f
7 changed files with 70 additions and 35 deletions

View File

@@ -124,8 +124,8 @@ subprojects { subproject ->
mysqlVersion = '5.1.34'
pahoMqttClientVersion = '1.0.2'
postgresVersion = '9.1-901-1.jdbc4'
reactorNettyVersion = '0.6.2.RELEASE'
reactorVersion = '3.0.6.RELEASE'
reactorNettyVersion = '0.6.3.BUILD-SNAPSHOT'
reactorVersion = '3.1.0.BUILD-SNAPSHOT'
romeToolsVersion = '1.7.0'
servletApiVersion = '3.1.0'
slf4jVersion = "1.7.21"

View File

@@ -20,19 +20,20 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.reactivestreams.Processor;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
import reactor.core.publisher.BlockingSink;
import reactor.core.publisher.DirectProcessor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxProcessor;
import reactor.core.publisher.FluxSink;
/**
* @author Artem Bilan
* @author Gary Russell
*
* @since 5.0
*/
@@ -43,11 +44,11 @@ public class ReactiveChannel extends AbstractMessageChannel
private final List<Publisher<Message<?>>> publishers = new CopyOnWriteArrayList<>();
private final Processor<Message<?>, Message<?>> processor;
private final FluxProcessor<Message<?>, Message<?>> processor;
private final Flux<Message<?>> flux;
private final BlockingSink<Message<?>> sink;
private final FluxSink<Message<?>> sink;
private volatile boolean upstreamSubscribed;
@@ -55,16 +56,17 @@ public class ReactiveChannel extends AbstractMessageChannel
this(DirectProcessor.create());
}
public ReactiveChannel(Processor<Message<?>, Message<?>> processor) {
public ReactiveChannel(FluxProcessor<Message<?>, Message<?>> processor) {
Assert.notNull(processor, "'processor' must not be null");
this.processor = processor;
this.flux = Flux.from(processor);
this.sink = BlockingSink.create(this.processor);
this.sink = processor.sink();
}
@Override
protected boolean doSend(Message<?> message, long timeout) {
return this.sink.submit(message, timeout) > -1;
this.sink.next(message);
return true;
}
@Override

View File

@@ -19,8 +19,6 @@ package org.springframework.integration.dsl;
import java.util.Queue;
import java.util.concurrent.Executor;
import org.reactivestreams.Processor;
import org.springframework.integration.dsl.channel.DirectChannelSpec;
import org.springframework.integration.dsl.channel.ExecutorChannelSpec;
import org.springframework.integration.dsl.channel.MessageChannels;
@@ -33,6 +31,8 @@ import org.springframework.integration.store.ChannelMessageStore;
import org.springframework.integration.store.PriorityCapableChannelMessageStore;
import org.springframework.messaging.Message;
import reactor.core.publisher.FluxProcessor;
/**
* @author Artem Bilan
* @author Gary Russell
@@ -140,11 +140,11 @@ public class Channels {
return MessageChannels.reactive(id);
}
public ReactiveChannelSpec reactive(Processor<Message<?>, Message<?>> processor) {
public ReactiveChannelSpec reactive(FluxProcessor<Message<?>, Message<?>> processor) {
return MessageChannels.reactive(processor);
}
public ReactiveChannelSpec reactive(String id, Processor<Message<?>, Message<?>> processor) {
public ReactiveChannelSpec reactive(String id, FluxProcessor<Message<?>, Message<?>> processor) {
return MessageChannels.reactive(id, processor);
}

View File

@@ -19,14 +19,15 @@ package org.springframework.integration.dsl.channel;
import java.util.Queue;
import java.util.concurrent.Executor;
import org.reactivestreams.Processor;
import org.springframework.integration.store.ChannelMessageStore;
import org.springframework.integration.store.PriorityCapableChannelMessageStore;
import org.springframework.messaging.Message;
import reactor.core.publisher.FluxProcessor;
/**
* @author Artem Bilan
* @author Gary Russell
*
* @since 5.0
*/
@@ -133,11 +134,11 @@ public final class MessageChannels {
return reactive().id(id);
}
public static ReactiveChannelSpec reactive(Processor<Message<?>, Message<?>> processor) {
public static ReactiveChannelSpec reactive(FluxProcessor<Message<?>, Message<?>> processor) {
return new ReactiveChannelSpec(processor);
}
public static ReactiveChannelSpec reactive(String id, Processor<Message<?>, Message<?>> processor) {
public static ReactiveChannelSpec reactive(String id, FluxProcessor<Message<?>, Message<?>> processor) {
return reactive(processor).id(id);
}

View File

@@ -16,13 +16,14 @@
package org.springframework.integration.dsl.channel;
import org.reactivestreams.Processor;
import org.springframework.integration.channel.ReactiveChannel;
import org.springframework.messaging.Message;
import reactor.core.publisher.FluxProcessor;
/**
* @author Artem Bilan
* @author Gary Russell
*
* @since 5.0
*/
@@ -32,7 +33,7 @@ public class ReactiveChannelSpec extends MessageChannelSpec<ReactiveChannelSpec,
this.channel = new ReactiveChannel();
}
ReactiveChannelSpec(Processor<Message<?>, Message<?>> processor) {
ReactiveChannelSpec(FluxProcessor<Message<?>, Message<?>> processor) {
this.channel = new ReactiveChannel(processor);
}

View File

@@ -20,6 +20,7 @@ import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.core.Ordered;
import org.springframework.integration.channel.MessagePublishingErrorHandler;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.Orderable;
import org.springframework.integration.history.MessageHistory;
@@ -36,6 +37,7 @@ import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;
import org.springframework.util.ErrorHandler;
import reactor.core.publisher.Operators;
@@ -70,6 +72,8 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
private volatile boolean loggingEnabled = true;
private ErrorHandler reactiveErrorHandler;
@Override
public boolean isLoggingEnabled() {
return this.loggingEnabled;
@@ -100,6 +104,16 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
this.shouldTrack = shouldTrack;
}
/**
* Set the error handler to use when an exception occurs when this handler
* is invoked as a reactive {@link Subscriber}.
* @param reactiveErrorHandler the error handler.
* @since 5.0
*/
public void setReactiveErrorHandler(ErrorHandler reactiveErrorHandler) {
this.reactiveErrorHandler = reactiveErrorHandler;
}
@Override
public void configureMetrics(AbstractMessageHandlerMetrics metrics) {
Assert.notNull(metrics, "'metrics' must not be null");
@@ -111,6 +125,14 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
if (this.statsEnabled) {
this.handlerMetrics.setFullStatsEnabled(true);
}
if (this.reactiveErrorHandler == null) {
if (getBeanFactory() != null) {
this.reactiveErrorHandler = new MessagePublishingErrorHandler(getChannelResolver());
}
else {
this.reactiveErrorHandler = new MessagePublishingErrorHandler();
}
}
}
@Override
@@ -154,7 +176,12 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
@Override
public void onNext(Message<?> message) {
handleMessage(message);
try {
handleMessage(message);
}
catch (MessagingException e) {
this.reactiveErrorHandler.handleError(e);
}
}
@Override

View File

@@ -17,10 +17,10 @@
package org.springframework.integration.channel.reactive;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.isOneOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -42,8 +42,8 @@ import org.springframework.integration.channel.ReactiveChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.annotation.DirtiesContext;
@@ -65,21 +65,15 @@ public class ReactiveChannelTests {
@Autowired
private MessageChannel queueChannel;
@Autowired
private PollableChannel errorChannel;
@Test
@SuppressWarnings("unchecked")
public void testReactiveMessageChannel() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
for (int i = 0; i < 10; i++) {
try {
this.reactiveChannel.send(MessageBuilder.withPayload(i).setReplyChannel(replyChannel).build());
}
catch (Exception e) {
assertThat(e, instanceOf(MessageDeliveryException.class));
assertThat(e.getCause().getCause(), instanceOf(MessageHandlingException.class));
assertThat(e.getCause().getCause().getCause(), instanceOf(IllegalStateException.class));
assertThat(e.getMessage(), containsString("intentional"));
}
this.reactiveChannel.send(MessageBuilder.withPayload(i).setReplyChannel(replyChannel).build());
}
for (int i = 0; i < 9; i++) {
@@ -87,6 +81,11 @@ public class ReactiveChannelTests {
assertNotNull(receive);
assertThat(receive.getPayload(), isOneOf("0", "1", "2", "3", "4", "6", "7", "8", "9"));
}
assertNull(replyChannel.receive(0));
Message<?> error = this.errorChannel.receive(0);
assertNotNull(error);
assertEquals(5, ((MessagingException) error.getPayload()).getFailedMessage().getPayload());
}
@Test
@@ -111,6 +110,11 @@ public class ReactiveChannelTests {
@EnableIntegration
public static class TestConfiguration {
@Bean
public QueueChannel errorChannel() {
return new QueueChannel();
}
@Bean
public MessageChannel reactiveChannel() {
return new ReactiveChannel();