Fix deprecations around ListenableFuture (#3865)

* Fix deprecations around ListenableFuture

SF has deprecated a `ListenableFuture` and API around it

* Migrate to `CompletableFuture` everywhere a `ListenableFuture` has been used
* Suppress a deprecation for `ListenableFuture` keeping the functionality until the next version
* Resolve deprecations nad removals from the latest Spring for Apache Kafka
* Fix documentation for the `ListenableFuture` in favor of `CompletableFuture`

NOTE: the AMQP module is left as is until `ListenableFuture` deprecation is resolved in Spring AMQP

* * Restore some `ListenableFuture` test for messaging gateway
This commit is contained in:
Artem Bilan
2022-07-28 09:32:01 -04:00
committed by GitHub
parent 2e9beada0b
commit 5572c2161d
23 changed files with 196 additions and 259 deletions

View File

@@ -20,10 +20,12 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -46,7 +48,6 @@ import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
/**
* Base {@link StompSessionManager} implementation to manage a single {@link StompSession}
@@ -103,7 +104,7 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
private volatile boolean connected;
private volatile ListenableFuture<StompSession> stompSessionListenableFuture;
private volatile CompletableFuture<StompSession> stompSessionFuture;
private volatile ScheduledFuture<?> reconnectFuture;
@@ -187,7 +188,7 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
this.logger.debug("Connecting " + this);
}
try {
this.stompSessionListenableFuture = doConnect(this.compositeStompSessionHandler);
this.stompSessionFuture = doConnect(this.compositeStompSessionHandler);
}
catch (Exception e) {
if (currentEpoch == this.epoch.get()) {
@@ -216,29 +217,30 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
private CountDownLatch addStompSessionCallback(int currentEpoch) {
CountDownLatch connectLatch = new CountDownLatch(1);
this.stompSessionListenableFuture.addCallback(
stompSession -> {
AbstractStompSessionManager.this.logger.debug("onSuccess");
AbstractStompSessionManager.this.connected = true;
AbstractStompSessionManager.this.connecting = false;
if (stompSession != null) {
stompSession.setAutoReceipt(isAutoReceiptEnabled());
this.stompSessionFuture.whenComplete((stompSession, throwable) -> {
if (throwable == null) {
AbstractStompSessionManager.this.logger.debug("onSuccess");
AbstractStompSessionManager.this.connected = true;
AbstractStompSessionManager.this.connecting = false;
if (stompSession != null) {
stompSession.setAutoReceipt(isAutoReceiptEnabled());
}
if (AbstractStompSessionManager.this.applicationEventPublisher != null) {
AbstractStompSessionManager.this.applicationEventPublisher.publishEvent(
new StompSessionConnectedEvent(this));
}
AbstractStompSessionManager.this.reconnectFuture = null;
connectLatch.countDown();
}
if (AbstractStompSessionManager.this.applicationEventPublisher != null) {
AbstractStompSessionManager.this.applicationEventPublisher.publishEvent(
new StompSessionConnectedEvent(this));
else {
AbstractStompSessionManager.this.logger.debug("onFailure", throwable);
connectLatch.countDown();
if (currentEpoch == AbstractStompSessionManager.this.epoch.get()) {
scheduleReconnect(throwable);
}
}
AbstractStompSessionManager.this.reconnectFuture = null;
connectLatch.countDown();
},
e -> {
AbstractStompSessionManager.this.logger.debug("onFailure", e);
connectLatch.countDown();
if (currentEpoch == AbstractStompSessionManager.this.epoch.get()) {
scheduleReconnect(e);
}
});
}
);
return connectLatch;
}
@@ -271,29 +273,21 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
@Override
public void destroy() {
if (this.stompSessionListenableFuture != null) {
if (this.stompSessionFuture != null) {
if (this.reconnectFuture != null) {
this.reconnectFuture.cancel(false);
this.reconnectFuture = null;
}
this.stompSessionListenableFuture.addCallback(
new ListenableFutureCallback<>() {
this.stompSessionFuture.whenComplete(new BiConsumer<StompSession, Throwable>() {
@Override
public void onFailure(Throwable ex) {
AbstractStompSessionManager.this.connected = false;
}
@Override
public void onSuccess(StompSession session) {
if (session != null) {
session.disconnect();
}
AbstractStompSessionManager.this.connected = false;
}
});
this.stompSessionListenableFuture = null;
@Override public void accept(StompSession session, Throwable throwable) {
if (session != null) {
session.disconnect();
}
AbstractStompSessionManager.this.connected = false;
}
});
this.stompSessionFuture = null;
}
}
@@ -353,7 +347,7 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
'}';
}
protected abstract ListenableFuture<StompSession> doConnect(StompSessionHandler handler);
protected abstract CompletableFuture<StompSession> doConnect(StompSessionHandler handler);
private class CompositeStompSessionHandler extends StompSessionHandlerAdapter {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-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,10 +16,11 @@
package org.springframework.integration.stomp;
import java.util.concurrent.CompletableFuture;
import org.springframework.messaging.simp.stomp.ReactorNettyTcpStompClient;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandler;
import org.springframework.util.concurrent.ListenableFuture;
/**
* The {@link ReactorNettyTcpStompClient} based {@link AbstractStompSessionManager} implementation.
@@ -37,8 +38,8 @@ public class ReactorNettyTcpStompSessionManager extends AbstractStompSessionMana
}
@Override
protected ListenableFuture<StompSession> doConnect(StompSessionHandler handler) {
return ((ReactorNettyTcpStompClient) this.stompClient).connect(getConnectHeaders(), handler);
protected CompletableFuture<StompSession> doConnect(StompSessionHandler handler) {
return ((ReactorNettyTcpStompClient) this.stompClient).connectAsync(getConnectHeaders(), handler);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-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,11 +17,11 @@
package org.springframework.integration.stomp;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandler;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.messaging.WebSocketStompClient;
@@ -55,9 +55,9 @@ public class WebSocketStompSessionManager extends AbstractStompSessionManager {
}
@Override
protected ListenableFuture<StompSession> doConnect(StompSessionHandler handler) {
protected CompletableFuture<StompSession> doConnect(StompSessionHandler handler) {
return ((WebSocketStompClient) this.stompClient)
.connect(this.url, this.handshakeHeaders, getConnectHeaders(), handler, this.uriVariables);
.connectAsync(this.url, this.handshakeHeaders, getConnectHeaders(), handler, this.uriVariables);
}
}