Update to latest reactor 2.0.1 snapshot

This commit is contained in:
Stephane Maldini 2015-04-27 02:27:04 +01:00 committed by Rossen Stoyanchev
parent a2a105918c
commit 5ebc1a8b60
5 changed files with 96 additions and 98 deletions

View File

@ -18,13 +18,13 @@ package org.springframework.messaging.simp.stomp;
import org.springframework.messaging.Message;
import org.springframework.messaging.tcp.TcpOperations;
import org.springframework.messaging.tcp.reactor.Reactor2TcpClient;
import org.springframework.messaging.tcp.reactor.Reactor2TcpClient.TcpClientSpecFactory;
import org.springframework.util.concurrent.ListenableFuture;
import reactor.Environment;
import reactor.core.config.ConfigurationReader;
import reactor.core.config.DispatcherConfiguration;
import reactor.core.config.DispatcherType;
import reactor.core.config.ReactorConfiguration;
import reactor.io.net.NetStreams;
import reactor.io.net.Spec.TcpClientSpec;
import java.util.Arrays;
@ -33,8 +33,7 @@ import java.util.Properties;
/**
* A STOMP over TCP client that uses
* {@link Reactor2TcpClient
* Reactor11TcpClient}.
* {@link Reactor2TcpClient}.
*
* @author Rossen Stoyanchev
* @since 4.2
@ -121,7 +120,7 @@ public class Reactor2TcpStompClient extends StompClientSupport {
}
private static class StompTcpClientSpecFactory
implements TcpClientSpecFactory<Message<byte[]>, Message<byte[]>> {
implements NetStreams.TcpClientFactory<Message<byte[]>, Message<byte[]>> {
private final Environment environment;

View File

@ -49,6 +49,6 @@ public interface TcpOperations<P> {
* @return a ListenableFuture that can be used to determine when and if the
* connection is successfully closed
*/
ListenableFuture<Boolean> shutdown();
ListenableFuture<Void> shutdown();
}

View File

@ -23,6 +23,7 @@ import java.util.List;
import java.util.Properties;
import io.netty.channel.nio.NioEventLoopGroup;
import org.reactivestreams.Publisher;
import reactor.Environment;
import reactor.core.config.ConfigurationReader;
import reactor.core.config.DispatcherConfiguration;
@ -35,14 +36,13 @@ import reactor.fn.tuple.Tuple;
import reactor.fn.tuple.Tuple2;
import reactor.io.buffer.Buffer;
import reactor.io.codec.Codec;
import reactor.io.net.ChannelStream;
import reactor.io.net.NetStreams;
import reactor.io.net.Reconnect;
import reactor.io.net.*;
import reactor.io.net.Spec.TcpClientSpec;
import reactor.io.net.impl.netty.NettyClientSocketOptions;
import reactor.io.net.impl.netty.tcp.NettyTcpClient;
import reactor.io.net.tcp.TcpClient;
import reactor.rx.Promise;
import reactor.rx.Promises;
import reactor.rx.Stream;
import reactor.rx.Streams;
import reactor.rx.action.Signal;
@ -58,7 +58,7 @@ import org.springframework.util.concurrent.ListenableFuture;
/**
* An implementation of {@link org.springframework.messaging.tcp.TcpOperations}
* based on the TCP client support of the Reactor project.
*
* <p>
* <p>This implementation wraps N (Reactor) clients for N {@link #connect} calls,
* i.e. a separate (Reactor) client instance for each connection.
*
@ -71,7 +71,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
@SuppressWarnings("rawtypes")
public static final Class<NettyTcpClient> REACTOR_TCP_CLIENT_TYPE = NettyTcpClient.class;
private final TcpClientSpecFactory<Message<P>, Message<P>> tcpClientSpecFactory;
private final NetStreams.TcpClientFactory<Message<P>, Message<P>> tcpClientSpecFactory;
private final List<TcpClient<Message<P>, Message<P>>> tcpClients =
new ArrayList<TcpClient<Message<P>, Message<P>>>();
@ -85,6 +85,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
* threads will be shared amongst the active clients.
* <p>Also see the constructor accepting a ready Reactor
* {@link TcpClientSpec} {@link Function} factory.
*
* @param host the host to connect to
* @param port the port to connect to
* @param codec the codec to use for encoding and decoding the TCP stream
@ -93,7 +94,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
final NioEventLoopGroup eventLoopGroup = initEventLoopGroup();
this.tcpClientSpecFactory = new TcpClientSpecFactory<Message<P>, Message<P>>() {
this.tcpClientSpecFactory = new NetStreams.TcpClientFactory<Message<P>, Message<P>>() {
@Override
public TcpClientSpec<Message<P>, Message<P>> apply(TcpClientSpec<Message<P>, Message<P>> spec) {
@ -110,8 +111,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
int ioThreadCount;
try {
ioThreadCount = Integer.parseInt(System.getProperty("reactor.tcp.ioThreadCount"));
}
catch (Exception i) {
} catch (Exception i) {
ioThreadCount = -1;
}
if (ioThreadCount <= 0l) {
@ -132,7 +132,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
*
* @param tcpClientSpecFactory the TcpClientSpec {@link Function} to use for each client creation.
*/
public Reactor2TcpClient(TcpClientSpecFactory<Message<P>, Message<P>> tcpClientSpecFactory) {
public Reactor2TcpClient(NetStreams.TcpClientFactory<Message<P>, Message<P>> tcpClientSpecFactory) {
Assert.notNull(tcpClientSpecFactory, "'tcpClientClientFactory' must not be null");
this.tcpClientSpecFactory = tcpClientSpecFactory;
}
@ -141,73 +141,80 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
@Override
public ListenableFuture<Void> connect(TcpConnectionHandler<P> connectionHandler) {
Class<NettyTcpClient> type = REACTOR_TCP_CLIENT_TYPE;
TcpClient<Message<P>, Message<P>> tcpClient = NetStreams.tcpClient(type, this.tcpClientSpecFactory);
composeConnectionHandling(tcpClient, connectionHandler);
Promise<Boolean> promise = tcpClient.open();
return new BooleanToVoidAdapter(promise);
Promise<Void> promise = tcpClient.start(composeConnectionHandling(tcpClient, connectionHandler));
return new PassThroughPromiseToListenableFutureAdapter<Void>(
promise.onError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
connectionHandler.afterConnectFailure(throwable);
}
})
);
}
@Override
public ListenableFuture<Void> connect(TcpConnectionHandler<P> handler, ReconnectStrategy strategy) {
Assert.notNull(strategy, "ReconnectStrategy must not be null");
Class<NettyTcpClient> type = REACTOR_TCP_CLIENT_TYPE;
TcpClient<Message<P>, Message<P>> tcpClient = NetStreams.tcpClient(type, this.tcpClientSpecFactory);
composeConnectionHandling(tcpClient, handler);
Stream<Boolean> stream = tcpClient.open(new ReactorRectonnectAdapter(strategy));
return new BooleanToVoidAdapter(stream.next());
Stream<Tuple2<InetSocketAddress, Integer>> stream = tcpClient.start(
composeConnectionHandling(tcpClient, handler),
new ReactorRectonnectAdapter(strategy)
);
return new PassThroughPromiseToListenableFutureAdapter<Void>(stream.next().after());
}
private void composeConnectionHandling(final TcpClient<Message<P>, Message<P>> tcpClient,
final TcpConnectionHandler<P> connectionHandler) {
private MessageHandler<P> composeConnectionHandling(
final TcpClient<Message<P>, Message<P>> tcpClient,
final TcpConnectionHandler<P> connectionHandler
) {
synchronized (this.tcpClients){
synchronized (this.tcpClients) {
this.tcpClients.add(tcpClient);
}
tcpClient
.finallyDo(new Consumer<Signal<ChannelStream<Message<P>, Message<P>>>>() {
return new MessageHandler<P>() {
@Override
public Publisher<Void> apply(ChannelStream<Message<P>, Message<P>> connection) {
@Override
public void accept(Signal<ChannelStream<Message<P>, Message<P>>> signal) {
synchronized (tcpClients) {
tcpClients.remove(tcpClient);
}
if (signal.isOnError()) {
connectionHandler.afterConnectFailure(signal.getThrowable());
}
}
})
.consume(new Consumer<ChannelStream<Message<P>, Message<P>>>() {
Promise<Void> closePromise = Promises.prepare();
@Override
public void accept(ChannelStream<Message<P>, Message<P>> connection) {
connection
.finallyDo(new Consumer<Signal<Message<P>>>() {
connectionHandler.afterConnected(new Reactor2TcpConnection<P>(connection, closePromise));
@Override
public void accept(Signal<Message<P>> signal) {
if (signal.isOnError()) {
connectionHandler.handleFailure(signal.getThrowable());
}
else if (signal.isOnComplete()) {
connectionHandler.afterConnectionClosed();
}
}
})
.consume(new Consumer<Message<P>>() {
connection
.finallyDo(new Consumer<Signal<Message<P>>>() {
@Override
public void accept(Message<P> message) {
connectionHandler.handleMessage(message);
}
});
connectionHandler.afterConnected(new Reactor2TcpConnection<P>(connection));
}
});
@Override
public void accept(Signal<Message<P>> signal) {
if (signal.isOnError()) {
connectionHandler.handleFailure(signal.getThrowable());
} else if (signal.isOnComplete()) {
connectionHandler.afterConnectionClosed();
}
}
})
.consume(new Consumer<Message<P>>() {
@Override
public void accept(Message<P> message) {
connectionHandler.handleMessage(message);
}
});
return closePromise;
}
};
}
@Override
public ListenableFuture<Boolean> shutdown() {
public ListenableFuture<Void> shutdown() {
final List<TcpClient<Message<P>, Message<P>>> clients;
@ -215,26 +222,23 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
clients = new ArrayList<TcpClient<Message<P>, Message<P>>>(this.tcpClients);
}
Promise<Boolean> promise = Streams.from(clients)
.flatMap(new Function<TcpClient<Message<P>, Message<P>>, Promise<Boolean>>() {
Promise<Void> promise = Streams.from(clients)
.flatMap(new Function<TcpClient<Message<P>, Message<P>>, Promise<Void>>() {
@Override
public Promise<Boolean> apply(TcpClient<Message<P>, Message<P>> client) {
return client.close();
}
})
.reduce(new BiFunction<Boolean, Boolean, Boolean>() {
@Override
public Boolean apply(Boolean prev, Boolean next) {
return prev && next;
public Promise<Void> apply(final TcpClient<Message<P>, Message<P>> client) {
return client.shutdown().onComplete(new Consumer<Promise<Void>>() {
@Override
public void accept(Promise<Void> voidPromise) {
synchronized (tcpClients) {
tcpClients.remove(client);
}
}
});
}
})
.next();
return new PassThroughPromiseToListenableFutureAdapter<Boolean>(promise);
}
public interface TcpClientSpecFactory<I, O> extends Function<TcpClientSpec<I, O>, TcpClientSpec<I, O>> {
return new PassThroughPromiseToListenableFutureAdapter<Void>(promise);
}
private static class SynchronousDispatcherConfigReader implements ConfigurationReader {
@ -257,18 +261,11 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
public Tuple2<InetSocketAddress, Long> reconnect(InetSocketAddress address, int attempt) {
return Tuple.of(address, strategy.getTimeToNextAttempt(attempt));
}
}
private static class BooleanToVoidAdapter extends AbstractPromiseToListenableFutureAdapter<Boolean, Void> {
public BooleanToVoidAdapter(Promise<Boolean> promise) {
super(promise);
}
@Override
protected Void adapt(Boolean result) {
return null;
}
private interface MessageHandler<P>
extends ReactorChannelHandler<Message<P>, Message<P>, ChannelStream<Message<P>, Message<P>>>{
}
}
}

View File

@ -16,9 +16,14 @@
package org.springframework.messaging.tcp.reactor;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.util.concurrent.ListenableFutureAdapter;
import reactor.fn.Functions;
import reactor.io.net.ChannelStream;
import reactor.rx.Promise;
import reactor.rx.Promises;
import reactor.rx.Streams;
import reactor.rx.broadcast.Broadcaster;
import org.springframework.messaging.Message;
@ -37,21 +42,19 @@ import org.springframework.util.concurrent.ListenableFuture;
public class Reactor2TcpConnection<P> implements TcpConnection<P> {
private final ChannelStream<Message<P>, Message<P>> channelStream;
private final Promise<Void> closePromise;
private final Broadcaster<Message<P>> sink;
public Reactor2TcpConnection(ChannelStream<Message<P>, Message<P>> channelStream) {
public Reactor2TcpConnection(ChannelStream<Message<P>, Message<P>> channelStream, Promise<Void> closePromise) {
this.channelStream = channelStream;
this.sink = Broadcaster.create();
this.channelStream.sink(this.sink);
this.closePromise = closePromise;
}
@Override
public ListenableFuture<Void> send(Message<P> message) {
this.sink.onNext(message);
return new PassThroughPromiseToListenableFutureAdapter<Void>(Promises.<Void>success(null));
Promise<Void> afterWrite = Promises.prepare();
this.channelStream.writeWith(Streams.just(message)).subscribe(afterWrite);
return new PassThroughPromiseToListenableFutureAdapter<Void>(afterWrite);
}
@Override
@ -66,7 +69,6 @@ public class Reactor2TcpConnection<P> implements TcpConnection<P> {
@Override
public void close() {
this.sink.onComplete();
this.closePromise.onComplete();
}
}

View File

@ -300,8 +300,8 @@ public class StompBrokerRelayMessageHandlerTests {
}
@Override
public ListenableFuture<Boolean> shutdown() {
return getBooleanFuture();
public ListenableFuture<Void> shutdown() {
return getVoidFuture();
}
public void handleMessage(Message<byte[]> message) {