|
|
|
@ -19,7 +19,6 @@ package org.springframework.messaging.simp.stomp; |
|
|
|
import java.lang.reflect.Type; |
|
|
|
import java.lang.reflect.Type; |
|
|
|
import java.time.Instant; |
|
|
|
import java.time.Instant; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Collections; |
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.concurrent.CompletableFuture; |
|
|
|
import java.util.concurrent.CompletableFuture; |
|
|
|
@ -28,6 +27,7 @@ import java.util.concurrent.ExecutionException; |
|
|
|
import java.util.concurrent.ScheduledFuture; |
|
|
|
import java.util.concurrent.ScheduledFuture; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
import java.util.concurrent.atomic.AtomicInteger; |
|
|
|
import java.util.concurrent.atomic.AtomicInteger; |
|
|
|
|
|
|
|
import java.util.function.Consumer; |
|
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.logging.Log; |
|
|
|
import org.apache.commons.logging.Log; |
|
|
|
|
|
|
|
|
|
|
|
@ -439,7 +439,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { |
|
|
|
String receiptId = headers.getReceiptId(); |
|
|
|
String receiptId = headers.getReceiptId(); |
|
|
|
ReceiptHandler handler = this.receiptHandlers.get(receiptId); |
|
|
|
ReceiptHandler handler = this.receiptHandlers.get(receiptId); |
|
|
|
if (handler != null) { |
|
|
|
if (handler != null) { |
|
|
|
handler.handleReceiptReceived(); |
|
|
|
handler.handleReceiptReceived(headers); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (logger.isDebugEnabled()) { |
|
|
|
else if (logger.isDebugEnabled()) { |
|
|
|
logger.debug("No matching receipt: " + accessor.getDetailedLogMessage(message.getPayload())); |
|
|
|
logger.debug("No matching receipt: " + accessor.getDetailedLogMessage(message.getPayload())); |
|
|
|
@ -544,7 +544,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
private final String receiptId; |
|
|
|
private final String receiptId; |
|
|
|
|
|
|
|
|
|
|
|
private final List<Runnable> receiptCallbacks = new ArrayList<>(2); |
|
|
|
private final List<Consumer<StompHeaders>> receiptCallbacks = new ArrayList<>(2); |
|
|
|
|
|
|
|
|
|
|
|
private final List<Runnable> receiptLostCallbacks = new ArrayList<>(2); |
|
|
|
private final List<Runnable> receiptLostCallbacks = new ArrayList<>(2); |
|
|
|
|
|
|
|
|
|
|
|
@ -554,6 +554,9 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
private Boolean result; |
|
|
|
private Boolean result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
|
|
|
private StompHeaders receiptHeaders; |
|
|
|
|
|
|
|
|
|
|
|
public ReceiptHandler(@Nullable String receiptId) { |
|
|
|
public ReceiptHandler(@Nullable String receiptId) { |
|
|
|
this.receiptId = receiptId; |
|
|
|
this.receiptId = receiptId; |
|
|
|
if (receiptId != null) { |
|
|
|
if (receiptId != null) { |
|
|
|
@ -576,64 +579,80 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void addReceiptTask(Runnable task) { |
|
|
|
public void addReceiptTask(Runnable task) { |
|
|
|
addTask(task, true); |
|
|
|
addReceiptTask(headers -> task.run()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void addReceiptLostTask(Runnable task) { |
|
|
|
public void addReceiptTask(Consumer<StompHeaders> task) { |
|
|
|
addTask(task, false); |
|
|
|
Assert.notNull(this.receiptId, "Set autoReceiptEnabled to track receipts or add a 'receiptId' header"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void addTask(Runnable task, boolean successTask) { |
|
|
|
|
|
|
|
Assert.notNull(this.receiptId, |
|
|
|
|
|
|
|
"To track receipts, set autoReceiptEnabled=true or add 'receiptId' header"); |
|
|
|
|
|
|
|
synchronized (this) { |
|
|
|
synchronized (this) { |
|
|
|
if (this.result != null && this.result == successTask) { |
|
|
|
if (this.result != null) { |
|
|
|
invoke(Collections.singletonList(task)); |
|
|
|
if (this.result) { |
|
|
|
|
|
|
|
task.accept(this.receiptHeaders); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
if (successTask) { |
|
|
|
this.receiptCallbacks.add(task); |
|
|
|
this.receiptCallbacks.add(task); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
this.receiptLostCallbacks.add(task); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void invoke(List<Runnable> callbacks) { |
|
|
|
@Override |
|
|
|
for (Runnable runnable : callbacks) { |
|
|
|
public void addReceiptLostTask(Runnable task) { |
|
|
|
try { |
|
|
|
synchronized (this) { |
|
|
|
runnable.run(); |
|
|
|
if (this.result != null) { |
|
|
|
|
|
|
|
if (!this.result) { |
|
|
|
|
|
|
|
task.run(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Throwable ex) { |
|
|
|
else { |
|
|
|
// ignore
|
|
|
|
this.receiptLostCallbacks.add(task); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void handleReceiptReceived() { |
|
|
|
public void handleReceiptReceived(StompHeaders receiptHeaders) { |
|
|
|
handleInternal(true); |
|
|
|
handleInternal(true, receiptHeaders); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void handleReceiptNotReceived() { |
|
|
|
public void handleReceiptNotReceived() { |
|
|
|
handleInternal(false); |
|
|
|
handleInternal(false, null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void handleInternal(boolean result) { |
|
|
|
private void handleInternal(boolean result, @Nullable StompHeaders receiptHeaders) { |
|
|
|
synchronized (this) { |
|
|
|
synchronized (this) { |
|
|
|
if (this.result != null) { |
|
|
|
if (this.result != null) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
this.result = result; |
|
|
|
this.result = result; |
|
|
|
invoke(result ? this.receiptCallbacks : this.receiptLostCallbacks); |
|
|
|
this.receiptHeaders = receiptHeaders; |
|
|
|
|
|
|
|
if (result) { |
|
|
|
|
|
|
|
this.receiptCallbacks.forEach(consumer -> { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
consumer.accept(this.receiptHeaders); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (Throwable ex) { |
|
|
|
|
|
|
|
// ignore
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
this.receiptLostCallbacks.forEach(task -> { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
task.run(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (Throwable ex) { |
|
|
|
|
|
|
|
// ignore
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
DefaultStompSession.this.receiptHandlers.remove(this.receiptId); |
|
|
|
DefaultStompSession.this.receiptHandlers.remove(this.receiptId); |
|
|
|
if (this.future != null) { |
|
|
|
if (this.future != null) { |
|
|
|
this.future.cancel(true); |
|
|
|
this.future.cancel(true); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|