use of org.springframework.util.concurrent.SettableListenableFuture in project spring-framework by spring-projects.
the class DeferredResultReturnValueHandlerTests method listenableFuture.
@Test
public void listenableFuture() throws Exception {
MethodParameter returnType = returnType("handleListenableFuture");
SettableListenableFuture<String> future = new SettableListenableFuture<>();
handleReturnValue(future, returnType);
assertTrue(this.request.isAsyncStarted());
assertFalse(WebAsyncUtils.getAsyncManager(this.webRequest).hasConcurrentResult());
future.set("foo");
assertTrue(WebAsyncUtils.getAsyncManager(this.webRequest).hasConcurrentResult());
assertEquals("foo", WebAsyncUtils.getAsyncManager(this.webRequest).getConcurrentResult());
}
use of org.springframework.util.concurrent.SettableListenableFuture in project spring-integration by spring-projects.
the class AsyncAmqpGatewayTests method testConfirmsAndReturns.
@Test
public void testConfirmsAndReturns() throws Exception {
CachingConnectionFactory ccf = new CachingConnectionFactory("localhost");
ccf.setPublisherConfirms(true);
ccf.setPublisherReturns(true);
RabbitTemplate template = new RabbitTemplate(ccf);
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(ccf);
container.setBeanName("replyContainer");
container.setQueueNames("asyncRQ1");
container.afterPropertiesSet();
container.start();
AsyncRabbitTemplate asyncTemplate = new AsyncRabbitTemplate(template, container);
asyncTemplate.setEnableConfirms(true);
asyncTemplate.setMandatory(true);
SimpleMessageListenerContainer receiver = new SimpleMessageListenerContainer(ccf);
receiver.setBeanName("receiver");
receiver.setQueueNames("asyncQ1");
final CountDownLatch waitForAckBeforeReplying = new CountDownLatch(1);
MessageListenerAdapter messageListener = new MessageListenerAdapter((ReplyingMessageListener<String, String>) foo -> {
try {
waitForAckBeforeReplying.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return foo.toUpperCase();
});
receiver.setMessageListener(messageListener);
receiver.afterPropertiesSet();
receiver.start();
AsyncAmqpOutboundGateway gateway = new AsyncAmqpOutboundGateway(asyncTemplate);
Log logger = spy(TestUtils.getPropertyValue(gateway, "logger", Log.class));
given(logger.isDebugEnabled()).willReturn(true);
final CountDownLatch replyTimeoutLatch = new CountDownLatch(1);
willAnswer(invocation -> {
invocation.callRealMethod();
replyTimeoutLatch.countDown();
return null;
}).given(logger).debug(startsWith("Reply not required and async timeout for"));
new DirectFieldAccessor(gateway).setPropertyValue("logger", logger);
QueueChannel outputChannel = new QueueChannel();
outputChannel.setBeanName("output");
QueueChannel returnChannel = new QueueChannel();
returnChannel.setBeanName("returns");
QueueChannel ackChannel = new QueueChannel();
ackChannel.setBeanName("acks");
QueueChannel errorChannel = new QueueChannel();
errorChannel.setBeanName("errors");
gateway.setOutputChannel(outputChannel);
gateway.setReturnChannel(returnChannel);
gateway.setConfirmAckChannel(ackChannel);
gateway.setConfirmNackChannel(ackChannel);
gateway.setConfirmCorrelationExpressionString("#this");
gateway.setExchangeName("");
gateway.setRoutingKey("asyncQ1");
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.afterPropertiesSet();
gateway.start();
Message<?> message = MessageBuilder.withPayload("foo").setErrorChannel(errorChannel).build();
gateway.handleMessage(message);
Message<?> ack = ackChannel.receive(10000);
assertNotNull(ack);
assertEquals("foo", ack.getPayload());
assertEquals(true, ack.getHeaders().get(AmqpHeaders.PUBLISH_CONFIRM));
waitForAckBeforeReplying.countDown();
Message<?> received = outputChannel.receive(10000);
assertNotNull(received);
assertEquals("FOO", received.getPayload());
// timeout tests
asyncTemplate.setReceiveTimeout(10);
receiver.setMessageListener(message1 -> {
});
// reply timeout with no requiresReply
message = MessageBuilder.withPayload("bar").setErrorChannel(errorChannel).build();
gateway.handleMessage(message);
assertTrue(replyTimeoutLatch.await(10, TimeUnit.SECONDS));
// reply timeout with requiresReply
gateway.setRequiresReply(true);
message = MessageBuilder.withPayload("baz").setErrorChannel(errorChannel).build();
gateway.handleMessage(message);
received = errorChannel.receive(10000);
assertThat(received, instanceOf(ErrorMessage.class));
ErrorMessage error = (ErrorMessage) received;
assertThat(error.getPayload(), instanceOf(MessagingException.class));
assertThat(error.getPayload().getCause(), instanceOf(AmqpReplyTimeoutException.class));
asyncTemplate.setReceiveTimeout(30000);
receiver.setMessageListener(messageListener);
// error on sending result
DirectChannel errorForce = new DirectChannel();
errorForce.setBeanName("errorForce");
errorForce.subscribe(message1 -> {
throw new RuntimeException("intentional");
});
gateway.setOutputChannel(errorForce);
message = MessageBuilder.withPayload("qux").setErrorChannel(errorChannel).build();
gateway.handleMessage(message);
received = errorChannel.receive(10000);
assertThat(received, instanceOf(ErrorMessage.class));
error = (ErrorMessage) received;
assertThat(error.getPayload(), instanceOf(MessagingException.class));
assertEquals("QUX", ((MessagingException) error.getPayload()).getFailedMessage().getPayload());
gateway.setRoutingKey(UUID.randomUUID().toString());
message = MessageBuilder.withPayload("fiz").setErrorChannel(errorChannel).build();
gateway.handleMessage(message);
Message<?> returned = returnChannel.receive(10000);
assertNotNull(returned);
assertThat(returned, instanceOf(ErrorMessage.class));
assertThat(returned.getPayload(), instanceOf(ReturnedAmqpMessageException.class));
ReturnedAmqpMessageException payload = (ReturnedAmqpMessageException) returned.getPayload();
assertEquals("fiz", payload.getFailedMessage().getPayload());
ackChannel.receive(10000);
ackChannel.purge(null);
asyncTemplate = mock(AsyncRabbitTemplate.class);
RabbitMessageFuture future = asyncTemplate.new RabbitMessageFuture(null, null);
willReturn(future).given(asyncTemplate).sendAndReceive(anyString(), anyString(), any(org.springframework.amqp.core.Message.class));
DirectFieldAccessor dfa = new DirectFieldAccessor(future);
dfa.setPropertyValue("nackCause", "nacknack");
SettableListenableFuture<Boolean> confirmFuture = new SettableListenableFuture<Boolean>();
confirmFuture.set(false);
dfa.setPropertyValue("confirm", confirmFuture);
new DirectFieldAccessor(gateway).setPropertyValue("template", asyncTemplate);
message = MessageBuilder.withPayload("buz").setErrorChannel(errorChannel).build();
gateway.handleMessage(message);
ack = ackChannel.receive(10000);
assertNotNull(ack);
assertThat(returned, instanceOf(ErrorMessage.class));
assertThat(returned.getPayload(), instanceOf(ReturnedAmqpMessageException.class));
NackedAmqpMessageException nack = (NackedAmqpMessageException) ack.getPayload();
assertEquals("buz", nack.getFailedMessage().getPayload());
assertEquals("nacknack", nack.getNackReason());
asyncTemplate.stop();
receiver.stop();
ccf.destroy();
}
use of org.springframework.util.concurrent.SettableListenableFuture in project spring-integration by spring-projects.
the class AbstractMessageProducingHandler method produceOutput.
protected void produceOutput(Object reply, final Message<?> requestMessage) {
final MessageHeaders requestHeaders = requestMessage.getHeaders();
Object replyChannel = null;
if (getOutputChannel() == null) {
Map<?, ?> routingSlipHeader = requestHeaders.get(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Map.class);
if (routingSlipHeader != null) {
Assert.isTrue(routingSlipHeader.size() == 1, "The RoutingSlip header value must be a SingletonMap");
Object key = routingSlipHeader.keySet().iterator().next();
Object value = routingSlipHeader.values().iterator().next();
Assert.isInstanceOf(List.class, key, "The RoutingSlip key must be List");
Assert.isInstanceOf(Integer.class, value, "The RoutingSlip value must be Integer");
List<?> routingSlip = (List<?>) key;
AtomicInteger routingSlipIndex = new AtomicInteger((Integer) value);
replyChannel = getOutputChannelFromRoutingSlip(reply, requestMessage, routingSlip, routingSlipIndex);
if (replyChannel != null) {
// TODO Migrate to the SF MessageBuilder
AbstractIntegrationMessageBuilder<?> builder = null;
if (reply instanceof Message) {
builder = this.getMessageBuilderFactory().fromMessage((Message<?>) reply);
} else if (reply instanceof AbstractIntegrationMessageBuilder) {
builder = (AbstractIntegrationMessageBuilder<?>) reply;
} else {
builder = this.getMessageBuilderFactory().withPayload(reply);
}
builder.setHeader(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Collections.singletonMap(routingSlip, routingSlipIndex.get()));
reply = builder;
}
}
if (replyChannel == null) {
replyChannel = requestHeaders.getReplyChannel();
if (replyChannel == null && reply instanceof Message) {
replyChannel = ((Message<?>) reply).getHeaders().getReplyChannel();
}
}
}
if (this.async && (reply instanceof ListenableFuture<?> || reply instanceof Publisher<?>)) {
if (reply instanceof ListenableFuture<?> || !(getOutputChannel() instanceof ReactiveStreamsSubscribableChannel)) {
ListenableFuture<?> future;
if (reply instanceof ListenableFuture<?>) {
future = (ListenableFuture<?>) reply;
} else {
SettableListenableFuture<Object> settableListenableFuture = new SettableListenableFuture<>();
Mono.from((Publisher<?>) reply).subscribe(settableListenableFuture::set, settableListenableFuture::setException);
future = settableListenableFuture;
}
Object theReplyChannel = replyChannel;
future.addCallback(new ListenableFutureCallback<Object>() {
@Override
public void onSuccess(Object result) {
Message<?> replyMessage = null;
try {
replyMessage = createOutputMessage(result, requestHeaders);
sendOutput(replyMessage, theReplyChannel, false);
} catch (Exception e) {
Exception exceptionToLogAndSend = e;
if (!(e instanceof MessagingException)) {
exceptionToLogAndSend = new MessageHandlingException(requestMessage, e);
if (replyMessage != null) {
exceptionToLogAndSend = new MessagingException(replyMessage, exceptionToLogAndSend);
}
}
logger.error("Failed to send async reply: " + result.toString(), exceptionToLogAndSend);
onFailure(exceptionToLogAndSend);
}
}
@Override
public void onFailure(Throwable ex) {
sendErrorMessage(requestMessage, ex);
}
});
} else {
((ReactiveStreamsSubscribableChannel) getOutputChannel()).subscribeTo(Flux.from((Publisher<?>) reply).map(result -> createOutputMessage(result, requestHeaders)));
}
} else {
sendOutput(createOutputMessage(reply, requestHeaders), replyChannel, false);
}
}
use of org.springframework.util.concurrent.SettableListenableFuture in project spring-framework by spring-projects.
the class WebSocketTransport method connect.
@Override
public ListenableFuture<WebSocketSession> connect(TransportRequest request, WebSocketHandler handler) {
final SettableListenableFuture<WebSocketSession> future = new SettableListenableFuture<>();
WebSocketClientSockJsSession session = new WebSocketClientSockJsSession(request, handler, future);
handler = new ClientSockJsWebSocketHandler(session);
request.addTimeoutTask(session.getTimeoutTask());
URI url = request.getTransportUrl();
WebSocketHttpHeaders headers = new WebSocketHttpHeaders(request.getHandshakeHeaders());
if (logger.isDebugEnabled()) {
logger.debug("Starting WebSocket session on " + url);
}
this.webSocketClient.doHandshake(handler, headers, url).addCallback(new ListenableFutureCallback<WebSocketSession>() {
@Override
public void onSuccess(@Nullable WebSocketSession webSocketSession) {
// WebSocket session ready, SockJS Session not yet
}
@Override
public void onFailure(Throwable ex) {
future.setException(ex);
}
});
return future;
}
use of org.springframework.util.concurrent.SettableListenableFuture in project spring-framework by spring-projects.
the class AbstractXhrTransport method connect.
// Transport methods
@Override
public ListenableFuture<WebSocketSession> connect(TransportRequest request, WebSocketHandler handler) {
SettableListenableFuture<WebSocketSession> connectFuture = new SettableListenableFuture<>();
XhrClientSockJsSession session = new XhrClientSockJsSession(request, handler, this, connectFuture);
request.addTimeoutTask(session.getTimeoutTask());
URI receiveUrl = request.getTransportUrl();
if (logger.isDebugEnabled()) {
logger.debug("Starting XHR " + (isXhrStreamingDisabled() ? "Polling" : "Streaming") + "session url=" + receiveUrl);
}
HttpHeaders handshakeHeaders = new HttpHeaders();
handshakeHeaders.putAll(request.getHandshakeHeaders());
connectInternal(request, handler, receiveUrl, handshakeHeaders, session, connectFuture);
return connectFuture;
}
Aggregations