Deprecate ListenableFuture in favor of CompletableFuture
This commit deprecates ListenableFuture in favor of CompletableFuture. ListenableFuture was introduced in Spring Framework 4.0, when CompletableFuture was not yet available. Spring now requires JDK 17, so having our own type no longer seems necessary. Major changes in this commit include: - Deprecation of ListenableFuture and related types (ListenableFutureCallback, SettableListenableFuture, etc.) - Deprecation of AsyncListenableTaskExecutor in favor of default methods in AsyncTaskExecutor (submitCompletable). - AsyncHandlerMethodReturnValueHandler now has toCompletableFuture instead of toListenableFuture. - WebSocketClient now has execute methods, which do the same as doHandshake, but return CompletableFutures (cf. the reactive WebSocketClient). All other changes - add an overloaded method that takes a CompletableFuture parameter instead of ListenableFuture, and/or - add a method with a 'Async' suffix that returns a CompletableFuture instead of a ListenableFuture (connectAsync, sendAsync). Closes gh-27780
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,9 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -54,8 +56,6 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
/**
|
||||
* Abstract base class for HandlerMethod-based message handling. Provides most of
|
||||
@@ -571,9 +571,9 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
return;
|
||||
}
|
||||
if (returnValue != null && this.returnValueHandlers.isAsyncReturnValue(returnValue, returnType)) {
|
||||
ListenableFuture<?> future = this.returnValueHandlers.toListenableFuture(returnValue, returnType);
|
||||
CompletableFuture<?> future = this.returnValueHandlers.toCompletableFuture(returnValue, returnType);
|
||||
if (future != null) {
|
||||
future.addCallback(new ReturnValueListenableFutureCallback(invocable, message));
|
||||
future.whenComplete(new ReturnValueListenableFutureCallback(invocable, message));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -704,7 +704,7 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
}
|
||||
|
||||
|
||||
private class ReturnValueListenableFutureCallback implements ListenableFutureCallback<Object> {
|
||||
private class ReturnValueListenableFutureCallback implements BiConsumer<Object, Throwable> {
|
||||
|
||||
private final InvocableHandlerMethod handlerMethod;
|
||||
|
||||
@@ -716,21 +716,21 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@Nullable Object result) {
|
||||
try {
|
||||
MethodParameter returnType = this.handlerMethod.getAsyncReturnValueType(result);
|
||||
returnValueHandlers.handleReturnValue(result, returnType, this.message);
|
||||
public void accept(@Nullable Object result, @Nullable Throwable ex) {
|
||||
if (result != null) {
|
||||
try {
|
||||
MethodParameter returnType = this.handlerMethod.getAsyncReturnValueType(result);
|
||||
returnValueHandlers.handleReturnValue(result, returnType, this.message);
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
handleFailure(throwable);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
else if (ex != null) {
|
||||
handleFailure(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
handleFailure(ex);
|
||||
}
|
||||
|
||||
private void handleFailure(Throwable ex) {
|
||||
Exception cause = (ex instanceof Exception ? (Exception) ex : new IllegalStateException(ex));
|
||||
processHandlerMethodException(this.handlerMethod, cause, this.message);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package org.springframework.messaging.handler.invocation;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
@@ -37,7 +40,7 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
|
||||
/**
|
||||
* Whether the return value represents an asynchronous, Future-like type
|
||||
* with success and error callbacks. If this method returns {@code true},
|
||||
* then {@link #toListenableFuture} is invoked next. If it returns
|
||||
* then {@link #toCompletableFuture} is invoked next. If it returns
|
||||
* {@code false}, then {@link #handleReturnValue} is called.
|
||||
* <p><strong>Note:</strong> this method will only be invoked after
|
||||
* {@link #supportsReturnType(org.springframework.core.MethodParameter)}
|
||||
@@ -61,8 +64,30 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
|
||||
* @param returnType the type of the return value
|
||||
* @return the resulting ListenableFuture, or {@code null} in which case
|
||||
* no further handling will be performed
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link #toCompletableFuture(Object, MethodParameter)}
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
default ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType) {
|
||||
CompletableFuture<?> result = toCompletableFuture(returnValue, returnType);
|
||||
return (result != null) ? new CompletableToListenableFutureAdapter<>(result) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the asynchronous return value to a {@link CompletableFuture}.
|
||||
* Return value handling will then continue when
|
||||
* the CompletableFuture is completed with either success or error.
|
||||
* <p><strong>Note:</strong> this method will only be invoked after
|
||||
* {@link #supportsReturnType(org.springframework.core.MethodParameter)}
|
||||
* is called and it returns {@code true}.
|
||||
* @param returnValue the value returned from the handler method
|
||||
* @param returnType the type of the return value
|
||||
* @return the resulting CompletableFuture, or {@code null} in which case
|
||||
* no further handling will be performed
|
||||
* @since 6.0
|
||||
*/
|
||||
@Nullable
|
||||
ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType);
|
||||
CompletableFuture<?> toCompletableFuture(Object returnValue, MethodParameter returnType);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,8 +20,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Support for {@link CompletableFuture} (and as of 4.3.7 also {@link CompletionStage})
|
||||
@@ -39,9 +37,7 @@ public class CompletableFutureReturnValueHandler extends AbstractAsyncReturnValu
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType) {
|
||||
return new CompletableToListenableFutureAdapter<>((CompletionStage<Object>) returnValue);
|
||||
public CompletableFuture<?> toCompletableFuture(Object returnValue, MethodParameter returnType) {
|
||||
return ((CompletionStage<?>) returnValue).toCompletableFuture();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.messaging.handler.invocation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -26,7 +27,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* A HandlerMethodReturnValueHandler that wraps and delegates to others.
|
||||
@@ -135,12 +135,11 @@ public class HandlerMethodReturnValueHandlerComposite implements AsyncHandlerMet
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType) {
|
||||
public CompletableFuture<?> toCompletableFuture(Object returnValue, MethodParameter returnType) {
|
||||
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
|
||||
if (handler instanceof AsyncHandlerMethodReturnValueHandler) {
|
||||
return ((AsyncHandlerMethodReturnValueHandler) handler).toListenableFuture(returnValue, returnType);
|
||||
return ((AsyncHandlerMethodReturnValueHandler) handler).toCompletableFuture(returnValue, returnType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.messaging.handler.invocation;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
@@ -24,7 +26,9 @@ import org.springframework.util.concurrent.ListenableFuture;
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.2
|
||||
* @deprecated as of 6.0, in favor of {@link CompletableFutureReturnValueHandler}
|
||||
*/
|
||||
@Deprecated
|
||||
public class ListenableFutureReturnValueHandler extends AbstractAsyncReturnValueHandler {
|
||||
|
||||
@Override
|
||||
@@ -38,4 +42,8 @@ public class ListenableFutureReturnValueHandler extends AbstractAsyncReturnValue
|
||||
return (ListenableFuture<?>) returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> toCompletableFuture(Object returnValue, MethodParameter returnType) {
|
||||
return ((ListenableFuture<?>) returnValue).completable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.springframework.messaging.handler.invocation;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.MonoToListenableFutureAdapter;
|
||||
|
||||
/**
|
||||
* Support for single-value reactive types (like {@code Mono} or {@code Single})
|
||||
@@ -57,12 +57,11 @@ public class ReactiveReturnValueHandler extends AbstractAsyncReturnValueHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType) {
|
||||
public CompletableFuture<?> toCompletableFuture(Object returnValue, MethodParameter returnType) {
|
||||
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(returnType.getParameterType(), returnValue);
|
||||
if (adapter != null) {
|
||||
return new MonoToListenableFutureAdapter<>(Mono.from(adapter.toPublisher(returnValue)));
|
||||
return Mono.from(adapter.toPublisher(returnValue)).toFuture();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -326,6 +326,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected List<? extends HandlerMethodReturnValueHandler> initReturnValueHandlers() {
|
||||
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.messaging.simp.stomp;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
@@ -33,7 +36,17 @@ public interface ConnectionHandlingStompSession extends StompSession, StompTcpCo
|
||||
|
||||
/**
|
||||
* Return a future that will complete when the session is ready for use.
|
||||
* @deprecated as of 6.0, in favor of {@link #getSession()}
|
||||
*/
|
||||
ListenableFuture<StompSession> getSessionFuture();
|
||||
@Deprecated
|
||||
default ListenableFuture<StompSession> getSessionFuture() {
|
||||
return new CompletableToListenableFutureAdapter<>(getSession());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a future that will complete when the session is ready for use.
|
||||
* @since 6.0
|
||||
*/
|
||||
CompletableFuture<StompSession> getSession();
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -47,9 +48,6 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.IdGenerator;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ConnectionHandlingStompSession}.
|
||||
@@ -85,7 +83,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
|
||||
private final StompHeaders connectHeaders;
|
||||
|
||||
private final SettableListenableFuture<StompSession> sessionFuture = new SettableListenableFuture<>();
|
||||
private final CompletableFuture<StompSession> sessionFuture = new CompletableFuture<>();
|
||||
|
||||
private MessageConverter converter = new SimpleMessageConverter();
|
||||
|
||||
@@ -149,7 +147,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<StompSession> getSessionFuture() {
|
||||
public CompletableFuture<StompSession> getSession() {
|
||||
return this.sessionFuture;
|
||||
}
|
||||
|
||||
@@ -289,7 +287,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
TcpConnection<byte[]> conn = this.connection;
|
||||
Assert.state(conn != null, "Connection closed");
|
||||
try {
|
||||
conn.send(message).get();
|
||||
conn.sendAsync(message).get();
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
throw new MessageDeliveryException(message, ex.getCause());
|
||||
@@ -407,7 +405,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to connect session id=" + this.sessionId, ex);
|
||||
}
|
||||
this.sessionFuture.setException(ex);
|
||||
this.sessionFuture.completeExceptionally(ex);
|
||||
this.sessionHandler.handleTransportError(this, ex);
|
||||
}
|
||||
|
||||
@@ -450,7 +448,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
else if (StompCommand.CONNECTED.equals(command)) {
|
||||
initHeartbeatTasks(headers);
|
||||
this.version = headers.getFirst("version");
|
||||
this.sessionFuture.set(this);
|
||||
this.sessionFuture.complete(this);
|
||||
this.sessionHandler.afterConnected(this, headers);
|
||||
}
|
||||
else if (StompCommand.ERROR.equals(command)) {
|
||||
@@ -506,7 +504,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
@Override
|
||||
public void handleFailure(Throwable ex) {
|
||||
try {
|
||||
this.sessionFuture.setException(ex); // no-op if already set
|
||||
this.sessionFuture.completeExceptionally(ex); // no-op if already set
|
||||
this.sessionHandler.handleTransportError(this, ex);
|
||||
}
|
||||
catch (Throwable ex2) {
|
||||
@@ -698,16 +696,11 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||
public void run() {
|
||||
TcpConnection<byte[]> conn = connection;
|
||||
if (conn != null) {
|
||||
conn.send(HEARTBEAT).addCallback(
|
||||
new ListenableFutureCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void result) {
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
handleFailure(ex);
|
||||
}
|
||||
});
|
||||
conn.sendAsync(HEARTBEAT).whenComplete((unused, throwable) -> {
|
||||
if (throwable != null) {
|
||||
handleFailure(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,11 +16,14 @@
|
||||
|
||||
package org.springframework.messaging.simp.stomp;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.simp.SimpLogging;
|
||||
import org.springframework.messaging.tcp.TcpOperations;
|
||||
import org.springframework.messaging.tcp.reactor.ReactorNettyTcpClient;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
@@ -71,9 +74,22 @@ public class ReactorNettyTcpStompClient extends StompClientSupport {
|
||||
* on the STOMP level.
|
||||
* @param handler the handler for the STOMP session
|
||||
* @return a ListenableFuture for access to the session when ready for use
|
||||
* @deprecated as of 6.0, in favor of {@link #connectAsync(StompSessionHandler)}
|
||||
*/
|
||||
@Deprecated
|
||||
public ListenableFuture<StompSession> connect(StompSessionHandler handler) {
|
||||
return connect(null, handler);
|
||||
return new CompletableToListenableFutureAdapter<>(connectAsync(handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and notify the given {@link StompSessionHandler} when connected
|
||||
* on the STOMP level.
|
||||
* @param handler the handler for the STOMP session
|
||||
* @return a ListenableFuture for access to the session when ready for use
|
||||
* @since 6.0
|
||||
*/
|
||||
public CompletableFuture<StompSession> connectAsync(StompSessionHandler handler) {
|
||||
return connectAsync(null, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,18 +98,33 @@ public class ReactorNettyTcpStompClient extends StompClientSupport {
|
||||
* @param connectHeaders headers to add to the CONNECT frame
|
||||
* @param handler the handler for the STOMP session
|
||||
* @return a ListenableFuture for access to the session when ready for use
|
||||
* @deprecated as of 6.0, in favor of {@link #connectAsync(StompHeaders, StompSessionHandler)}
|
||||
*/
|
||||
@Deprecated
|
||||
public ListenableFuture<StompSession> connect(@Nullable StompHeaders connectHeaders, StompSessionHandler handler) {
|
||||
ConnectionHandlingStompSession session = createSession(connectHeaders, handler);
|
||||
this.tcpClient.connect(session);
|
||||
this.tcpClient.connectAsync(session);
|
||||
return session.getSessionFuture();
|
||||
}
|
||||
|
||||
/**
|
||||
* An overloaded version of {@link #connectAsync(StompSessionHandler)} that
|
||||
* accepts headers to use for the STOMP CONNECT frame.
|
||||
* @param connectHeaders headers to add to the CONNECT frame
|
||||
* @param handler the handler for the STOMP session
|
||||
* @return a CompletableFuture for access to the session when ready for use
|
||||
*/
|
||||
public CompletableFuture<StompSession> connectAsync(@Nullable StompHeaders connectHeaders, StompSessionHandler handler) {
|
||||
ConnectionHandlingStompSession session = createSession(connectHeaders, handler);
|
||||
this.tcpClient.connectAsync(session);
|
||||
return session.getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down the client and release resources.
|
||||
*/
|
||||
public void shutdown() {
|
||||
this.tcpClient.shutdown();
|
||||
this.tcpClient.shutdownAsync();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -47,9 +48,6 @@ import org.springframework.messaging.tcp.reactor.ReactorNettyCodec;
|
||||
import org.springframework.messaging.tcp.reactor.ReactorNettyTcpClient;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* A {@link org.springframework.messaging.MessageHandler} that handles messages by
|
||||
@@ -98,14 +96,13 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
|
||||
private static final byte[] EMPTY_PAYLOAD = new byte[0];
|
||||
|
||||
private static final ListenableFutureTask<Void> EMPTY_TASK = new ListenableFutureTask<>(new VoidCallable());
|
||||
private static final CompletableFuture<Void> EMPTY_TASK = CompletableFuture.completedFuture(null);
|
||||
|
||||
private static final StompHeaderAccessor HEART_BEAT_ACCESSOR;
|
||||
|
||||
private static final Message<byte[]> HEARTBEAT_MESSAGE;
|
||||
|
||||
static {
|
||||
EMPTY_TASK.run();
|
||||
HEART_BEAT_ACCESSOR = StompHeaderAccessor.createForHeartbeat();
|
||||
HEARTBEAT_MESSAGE = MessageBuilder.createMessage(
|
||||
StompDecoder.HEARTBEAT_PAYLOAD, HEART_BEAT_ACCESSOR.getMessageHeaders());
|
||||
@@ -455,7 +452,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
this.connectionHandlers.put(handler.getSessionId(), handler);
|
||||
|
||||
this.stats.incrementConnectCount();
|
||||
this.tcpClient.connect(handler, new FixedIntervalReconnectStrategy(5000));
|
||||
this.tcpClient.connectAsync(handler, new FixedIntervalReconnectStrategy(5000));
|
||||
|
||||
if (this.taskScheduler != null) {
|
||||
this.taskScheduler.scheduleWithFixedDelay(new ClientSendMessageCountTask(), Duration.ofMillis(5000));
|
||||
@@ -478,7 +475,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
publishBrokerUnavailableEvent();
|
||||
if (this.tcpClient != null) {
|
||||
try {
|
||||
this.tcpClient.shutdown().get(5000, TimeUnit.MILLISECONDS);
|
||||
this.tcpClient.shutdownAsync().get(5000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("Error in shutdown of TCP client", ex);
|
||||
@@ -572,7 +569,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
this.connectionHandlers.put(sessionId, handler);
|
||||
this.stats.incrementConnectCount();
|
||||
Assert.state(this.tcpClient != null, "No TCP client available");
|
||||
this.tcpClient.connect(handler);
|
||||
this.tcpClient.connectAsync(handler);
|
||||
}
|
||||
else if (StompCommand.DISCONNECT.equals(command)) {
|
||||
RelayConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
||||
@@ -691,7 +688,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
MAX_TIME_TO_CONNECTED_FRAME + " ms.", null);
|
||||
}
|
||||
}, MAX_TIME_TO_CONNECTED_FRAME);
|
||||
connection.send(MessageBuilder.createMessage(EMPTY_PAYLOAD, this.connectHeaders.getMessageHeaders()));
|
||||
connection.sendAsync(MessageBuilder.createMessage(EMPTY_PAYLOAD, this.connectHeaders.getMessageHeaders()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -865,7 +862,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
* @return a future to wait for the result
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public ListenableFuture<Void> forward(final Message<?> message, final StompHeaderAccessor accessor) {
|
||||
public CompletableFuture<Void> forward(final Message<?> message, final StompHeaderAccessor accessor) {
|
||||
TcpConnection<byte[]> conn = this.tcpConnection;
|
||||
|
||||
if (!this.isStompConnected || conn == null) {
|
||||
@@ -901,19 +898,17 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
logger.trace("Forwarding " + accessor.getDetailedLogMessage(message.getPayload()));
|
||||
}
|
||||
|
||||
ListenableFuture<Void> future = conn.send((Message<byte[]>) messageToSend);
|
||||
future.addCallback(new ListenableFutureCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void result) {
|
||||
CompletableFuture<Void> future = conn.sendAsync((Message<byte[]>) messageToSend);
|
||||
future.whenComplete((unused, throwable) -> {
|
||||
if (throwable == null) {
|
||||
if (accessor.getCommand() == StompCommand.DISCONNECT) {
|
||||
afterDisconnectSent(accessor);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
if (tcpConnection != null) {
|
||||
else {
|
||||
if (this.tcpConnection != null) {
|
||||
handleTcpConnectionFailure("failed to forward " +
|
||||
accessor.getShortLogMessage(message.getPayload()), ex);
|
||||
accessor.getShortLogMessage(message.getPayload()), throwable);
|
||||
}
|
||||
else if (logger.isErrorEnabled()) {
|
||||
logger.error("Failed to forward " + accessor.getShortLogMessage(message.getPayload()));
|
||||
@@ -1005,10 +1000,11 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
if (clientSendInterval > 0 && serverReceiveInterval > 0) {
|
||||
long interval = Math.max(clientSendInterval, serverReceiveInterval);
|
||||
con.onWriteInactivity(() ->
|
||||
con.send(HEARTBEAT_MESSAGE).addCallback(
|
||||
result -> {},
|
||||
ex -> handleTcpConnectionFailure(
|
||||
"Failed to forward heartbeat: " + ex.getMessage(), ex)), interval);
|
||||
con.sendAsync(HEARTBEAT_MESSAGE).whenComplete((unused, ex) -> {
|
||||
if (ex != null) {
|
||||
handleTcpConnectionFailure("Failed to forward heartbeat: " + ex.getMessage(), ex);
|
||||
}
|
||||
}), interval);
|
||||
}
|
||||
if (clientReceiveInterval > 0 && serverSendInterval > 0) {
|
||||
final long interval = Math.max(clientReceiveInterval, serverSendInterval) * HEARTBEAT_MULTIPLIER;
|
||||
@@ -1029,12 +1025,11 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
TcpConnection<byte[]> conn = getTcpConnection();
|
||||
if (conn != null) {
|
||||
MessageHeaders headers = accessor.getMessageHeaders();
|
||||
conn.send(MessageBuilder.createMessage(EMPTY_PAYLOAD, headers)).addCallback(
|
||||
result -> {},
|
||||
ex -> {
|
||||
String error = "Failed to subscribe in \"system\" session.";
|
||||
handleTcpConnectionFailure(error, ex);
|
||||
});
|
||||
conn.sendAsync(MessageBuilder.createMessage(EMPTY_PAYLOAD, headers)).whenComplete((unused, ex) -> {
|
||||
if (ex != null) {
|
||||
handleTcpConnectionFailure("Failed to subscribe in \"system\" session.", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1083,9 +1078,9 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> forward(Message<?> message, StompHeaderAccessor accessor) {
|
||||
public CompletableFuture<Void> forward(Message<?> message, StompHeaderAccessor accessor) {
|
||||
try {
|
||||
ListenableFuture<Void> future = super.forward(message, accessor);
|
||||
CompletableFuture<Void> future = super.forward(message, accessor);
|
||||
if (message.getHeaders().get(SimpMessageHeaderAccessor.IGNORE_ERROR) == null) {
|
||||
future.get();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,10 @@
|
||||
package org.springframework.messaging.tcp;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
@@ -35,8 +37,21 @@ public interface TcpConnection<P> extends Closeable {
|
||||
* @param message the message
|
||||
* @return a ListenableFuture that can be used to determine when and if the
|
||||
* message was successfully sent
|
||||
* @deprecated as of 6.0, in favor of {@link #sendAsync(Message)}
|
||||
*/
|
||||
ListenableFuture<Void> send(Message<P> message);
|
||||
@Deprecated
|
||||
default ListenableFuture<Void> send(Message<P> message) {
|
||||
return new CompletableToListenableFutureAdapter<>(sendAsync(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given message.
|
||||
* @param message the message
|
||||
* @return a CompletableFuture that can be used to determine when and if the
|
||||
* message was successfully sent
|
||||
* @since 6.0
|
||||
*/
|
||||
CompletableFuture<Void> sendAsync(Message<P> message);
|
||||
|
||||
/**
|
||||
* Register a task to invoke after a period of read inactivity.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.messaging.tcp;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
@@ -32,8 +35,21 @@ public interface TcpOperations<P> {
|
||||
* @param connectionHandler a handler to manage the connection
|
||||
* @return a ListenableFuture that can be used to determine when and if the
|
||||
* connection is successfully established
|
||||
* @deprecated as of 6.0, in favor of {@link #connectAsync(TcpConnectionHandler)}
|
||||
*/
|
||||
ListenableFuture<Void> connect(TcpConnectionHandler<P> connectionHandler);
|
||||
@Deprecated
|
||||
default ListenableFuture<Void> connect(TcpConnectionHandler<P> connectionHandler) {
|
||||
return new CompletableToListenableFutureAdapter<>(connectAsync(connectionHandler));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a new connection.
|
||||
* @param connectionHandler a handler to manage the connection
|
||||
* @return a CompletableFuture that can be used to determine when and if the
|
||||
* connection is successfully established
|
||||
* @since 6.0
|
||||
*/
|
||||
CompletableFuture<Void> connectAsync(TcpConnectionHandler<P> connectionHandler);
|
||||
|
||||
/**
|
||||
* Open a new connection and a strategy for reconnecting if the connection fails.
|
||||
@@ -41,14 +57,40 @@ public interface TcpOperations<P> {
|
||||
* @param reconnectStrategy a strategy for reconnecting
|
||||
* @return a ListenableFuture that can be used to determine when and if the
|
||||
* initial connection is successfully established
|
||||
* @deprecated as of 6.0, in favor of {@link #connectAsync(TcpConnectionHandler, ReconnectStrategy)}
|
||||
*/
|
||||
ListenableFuture<Void> connect(TcpConnectionHandler<P> connectionHandler, ReconnectStrategy reconnectStrategy);
|
||||
@Deprecated
|
||||
default ListenableFuture<Void> connect(TcpConnectionHandler<P> connectionHandler, ReconnectStrategy reconnectStrategy) {
|
||||
return new CompletableToListenableFutureAdapter<>(connectAsync(connectionHandler, reconnectStrategy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a new connection and a strategy for reconnecting if the connection fails.
|
||||
* @param connectionHandler a handler to manage the connection
|
||||
* @param reconnectStrategy a strategy for reconnecting
|
||||
* @return a CompletableFuture that can be used to determine when and if the
|
||||
* initial connection is successfully established
|
||||
* @since 6.0
|
||||
*/
|
||||
CompletableFuture<Void> connectAsync(TcpConnectionHandler<P> connectionHandler, ReconnectStrategy reconnectStrategy);
|
||||
|
||||
/**
|
||||
* Shut down and close any open connections.
|
||||
* @return a ListenableFuture that can be used to determine when and if the
|
||||
* connection is successfully closed
|
||||
* @deprecated as of 6.0, in favor of {@link #shutdownAsync()}
|
||||
*/
|
||||
ListenableFuture<Void> shutdown();
|
||||
@Deprecated
|
||||
default ListenableFuture<Void> shutdown() {
|
||||
return new CompletableToListenableFutureAdapter<>(shutdownAsync());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down and close any open connections.
|
||||
* @return a ListenableFuture that can be used to determine when and if the
|
||||
* connection is successfully closed
|
||||
* @since 6.0
|
||||
*/
|
||||
CompletableFuture<Void> shutdownAsync();
|
||||
|
||||
}
|
||||
|
||||
@@ -52,10 +52,6 @@ import org.springframework.messaging.tcp.TcpConnection;
|
||||
import org.springframework.messaging.tcp.TcpConnectionHandler;
|
||||
import org.springframework.messaging.tcp.TcpOperations;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.MonoToListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* Reactor Netty based implementation of {@link TcpOperations}.
|
||||
@@ -179,20 +175,18 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> connect(final TcpConnectionHandler<P> handler) {
|
||||
public CompletableFuture<Void> connectAsync(TcpConnectionHandler<P> handler) {
|
||||
Assert.notNull(handler, "TcpConnectionHandler is required");
|
||||
|
||||
if (this.stopping) {
|
||||
return handleShuttingDownConnectFailure(handler);
|
||||
}
|
||||
|
||||
Mono<Void> connectMono = extendTcpClient(this.tcpClient, handler)
|
||||
return extendTcpClient(this.tcpClient, handler)
|
||||
.handle(new ReactorNettyHandler(handler))
|
||||
.connect()
|
||||
.doOnError(handler::afterConnectFailure)
|
||||
.then();
|
||||
|
||||
return new MonoToListenableFutureAdapter<>(connectMono);
|
||||
.then().toFuture();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +203,7 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> connect(TcpConnectionHandler<P> handler, ReconnectStrategy strategy) {
|
||||
public CompletableFuture<Void> connectAsync(TcpConnectionHandler<P> handler, ReconnectStrategy strategy) {
|
||||
Assert.notNull(handler, "TcpConnectionHandler is required");
|
||||
Assert.notNull(strategy, "ReconnectStrategy is required");
|
||||
|
||||
@@ -234,14 +228,13 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||
.scan(1, (count, element) -> count++)
|
||||
.flatMap(attempt -> reconnect(attempt, strategy)))
|
||||
.subscribe();
|
||||
|
||||
return new CompletableToListenableFutureAdapter<>(connectFuture);
|
||||
return connectFuture;
|
||||
}
|
||||
|
||||
private ListenableFuture<Void> handleShuttingDownConnectFailure(TcpConnectionHandler<P> handler) {
|
||||
private CompletableFuture<Void> handleShuttingDownConnectFailure(TcpConnectionHandler<P> handler) {
|
||||
IllegalStateException ex = new IllegalStateException("Shutting down.");
|
||||
handler.afterConnectFailure(ex);
|
||||
return new MonoToListenableFutureAdapter<>(Mono.error(ex));
|
||||
return Mono.<Void>error(ex).toFuture();
|
||||
}
|
||||
|
||||
private Publisher<? extends Long> reconnect(Integer attempt, ReconnectStrategy reconnectStrategy) {
|
||||
@@ -250,11 +243,9 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> shutdown() {
|
||||
public CompletableFuture<Void> shutdownAsync() {
|
||||
if (this.stopping) {
|
||||
SettableListenableFuture<Void> future = new SettableListenableFuture<>();
|
||||
future.set(null);
|
||||
return future;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
this.stopping = true;
|
||||
@@ -274,7 +265,7 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||
result = stopScheduler();
|
||||
}
|
||||
|
||||
return new MonoToListenableFutureAdapter<>(result);
|
||||
return result.toFuture();
|
||||
}
|
||||
|
||||
private Mono<Void> stopScheduler() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.messaging.tcp.reactor;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
@@ -24,8 +26,6 @@ import reactor.netty.NettyOutbound;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.tcp.TcpConnection;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.MonoToListenableFutureAdapter;
|
||||
|
||||
/**
|
||||
* Reactor Netty based implementation of {@link TcpConnection}.
|
||||
@@ -56,11 +56,12 @@ public class ReactorNettyTcpConnection<P> implements TcpConnection<P> {
|
||||
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> send(Message<P> message) {
|
||||
public CompletableFuture<Void> sendAsync(Message<P> message) {
|
||||
ByteBuf byteBuf = this.outbound.alloc().buffer();
|
||||
this.codec.encode(message, byteBuf);
|
||||
Mono<Void> sendCompletion = this.outbound.send(Mono.just(byteBuf)).then();
|
||||
return new MonoToListenableFutureAdapter<>(sendCompletion);
|
||||
return this.outbound.send(Mono.just(byteBuf))
|
||||
.then()
|
||||
.toFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -535,6 +535,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
|
||||
@Controller
|
||||
@MessageMapping("listenable-future")
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class ListenableFutureController {
|
||||
|
||||
private ListenableFutureTask<String> future;
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -45,7 +46,6 @@ import org.springframework.messaging.tcp.TcpConnection;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -90,9 +90,9 @@ public class DefaultStompSessionTests {
|
||||
new CompositeMessageConverter(
|
||||
Arrays.asList(new StringMessageConverter(), new ByteArrayMessageConverter())));
|
||||
|
||||
SettableListenableFuture<Void> future = new SettableListenableFuture<>();
|
||||
future.set(null);
|
||||
given(this.connection.send(this.messageCaptor.capture())).willReturn(future);
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.complete(null);
|
||||
given(this.connection.sendAsync(this.messageCaptor.capture())).willReturn(future);
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ public class DefaultStompSessionTests {
|
||||
@Test
|
||||
public void heartbeatNotSupportedByServer() {
|
||||
this.session.afterConnected(this.connection);
|
||||
verify(this.connection).send(any());
|
||||
verify(this.connection).sendAsync(any());
|
||||
|
||||
this.connectHeaders.setHeartbeat(new long[] {10000, 10000});
|
||||
|
||||
@@ -193,7 +193,7 @@ public class DefaultStompSessionTests {
|
||||
@Test
|
||||
public void heartbeatTasks() {
|
||||
this.session.afterConnected(this.connection);
|
||||
verify(this.connection).send(any());
|
||||
verify(this.connection).sendAsync(any());
|
||||
|
||||
this.connectHeaders.setHeartbeat(new long[] {10000, 10000});
|
||||
|
||||
@@ -216,7 +216,7 @@ public class DefaultStompSessionTests {
|
||||
writeTask.run();
|
||||
StompHeaderAccessor accessor = StompHeaderAccessor.createForHeartbeat();
|
||||
Message<byte[]> message = MessageBuilder.createMessage(new byte[] {'\n'}, accessor.getMessageHeaders());
|
||||
verify(this.connection).send(eq(message));
|
||||
verify(this.connection).sendAsync(eq(message));
|
||||
verifyNoMoreInteractions(this.connection);
|
||||
|
||||
reset(this.sessionHandler);
|
||||
@@ -435,10 +435,9 @@ public class DefaultStompSessionTests {
|
||||
assertThat(this.session.isConnected()).isTrue();
|
||||
|
||||
IllegalStateException exception = new IllegalStateException("simulated exception");
|
||||
SettableListenableFuture<Void> future = new SettableListenableFuture<>();
|
||||
future.setException(exception);
|
||||
CompletableFuture<Void> future = CompletableFuture.failedFuture(exception);
|
||||
|
||||
given(this.connection.send(any())).willReturn(future);
|
||||
given(this.connection.sendAsync(any())).willReturn(future);
|
||||
assertThatExceptionOfType(MessageDeliveryException.class).isThrownBy(() ->
|
||||
this.session.send("/topic/foo", "sample payload".getBytes(StandardCharsets.UTF_8)))
|
||||
.withCause(exception);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -38,7 +39,6 @@ import org.springframework.messaging.converter.StringMessageConverter;
|
||||
import org.springframework.messaging.simp.stomp.StompSession.Subscription;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -107,10 +107,10 @@ public class ReactorNettyTcpStompClientTests {
|
||||
public void publishSubscribe() throws Exception {
|
||||
String destination = "/topic/foo";
|
||||
ConsumingHandler consumingHandler1 = new ConsumingHandler(destination);
|
||||
ListenableFuture<StompSession> consumerFuture1 = this.client.connect(consumingHandler1);
|
||||
CompletableFuture<StompSession> consumerFuture1 = this.client.connectAsync(consumingHandler1);
|
||||
|
||||
ConsumingHandler consumingHandler2 = new ConsumingHandler(destination);
|
||||
ListenableFuture<StompSession> consumerFuture2 = this.client.connect(consumingHandler2);
|
||||
CompletableFuture<StompSession> consumerFuture2 = this.client.connectAsync(consumingHandler2);
|
||||
|
||||
assertThat(consumingHandler1.awaitForSubscriptions(5000)).isTrue();
|
||||
assertThat(consumingHandler2.awaitForSubscriptions(5000)).isTrue();
|
||||
@@ -118,7 +118,7 @@ public class ReactorNettyTcpStompClientTests {
|
||||
ProducingHandler producingHandler = new ProducingHandler();
|
||||
producingHandler.addToSend(destination, "foo1");
|
||||
producingHandler.addToSend(destination, "foo2");
|
||||
ListenableFuture<StompSession> producerFuture = this.client.connect(producingHandler);
|
||||
CompletableFuture<StompSession> producerFuture = this.client.connectAsync(producingHandler);
|
||||
|
||||
assertThat(consumingHandler1.awaitForMessageCount(2, 5000)).isTrue();
|
||||
assertThat(consumingHandler1.getReceived()).containsExactly("foo1", "foo2");
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -39,8 +40,6 @@ import org.springframework.messaging.tcp.TcpConnection;
|
||||
import org.springframework.messaging.tcp.TcpConnectionHandler;
|
||||
import org.springframework.messaging.tcp.TcpOperations;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -309,10 +308,8 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
}
|
||||
|
||||
|
||||
private static ListenableFutureTask<Void> getVoidFuture() {
|
||||
ListenableFutureTask<Void> futureTask = new ListenableFutureTask<>(() -> null);
|
||||
futureTask.run();
|
||||
return futureTask;
|
||||
private static CompletableFuture<Void> getVoidFuture() {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -336,21 +333,22 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> connect(TcpConnectionHandler<byte[]> handler) {
|
||||
public CompletableFuture<Void> connectAsync(TcpConnectionHandler<byte[]> handler) {
|
||||
this.connectionHandler = handler;
|
||||
handler.afterConnected(this.connection);
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> connect(TcpConnectionHandler<byte[]> handler, ReconnectStrategy strategy) {
|
||||
public CompletableFuture<Void> connectAsync(TcpConnectionHandler<byte[]> handler,
|
||||
ReconnectStrategy reconnectStrategy) {
|
||||
this.connectionHandler = handler;
|
||||
handler.afterConnected(this.connection);
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> shutdown() {
|
||||
public CompletableFuture<Void> shutdownAsync() {
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
@@ -371,7 +369,7 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> send(Message<byte[]> message) {
|
||||
public CompletableFuture<Void> sendAsync(Message<byte[]> message) {
|
||||
this.messages.add(message);
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user