Example usage for org.springframework.util.concurrent SettableListenableFuture SettableListenableFuture

List of usage examples for org.springframework.util.concurrent SettableListenableFuture SettableListenableFuture

Introduction

In this page you can find the example usage for org.springframework.util.concurrent SettableListenableFuture SettableListenableFuture.

Prototype

SettableListenableFuture

Source Link

Usage

From source file:zipkin.server.ZipkinHttpCollector.java

ListenableFuture<ResponseEntity<?>> validateAndStoreSpans(String encoding, Codec codec, byte[] body) {
    SettableListenableFuture<ResponseEntity<?>> result = new SettableListenableFuture<>();
    metrics.incrementMessages();/* w  ww.  j  a va  2s . c  o m*/
    if (encoding != null && encoding.contains("gzip")) {
        try {
            body = gunzip(body);
        } catch (IOException e) {
            metrics.incrementMessagesDropped();
            result.set(ResponseEntity.badRequest().body("Cannot gunzip spans: " + e.getMessage() + "\n"));
        }
    }
    collector.acceptSpans(body, codec, new Callback<Void>() {
        @Override
        public void onSuccess(@Nullable Void value) {
            result.set(SUCCESS);
        }

        @Override
        public void onError(Throwable t) {
            String message = t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage();
            result.set(t.getMessage() == null || message.startsWith("Cannot store")
                    ? ResponseEntity.status(500).body(message + "\n")
                    : ResponseEntity.status(400).body(message + "\n"));
        }
    });
    return result;
}

From source file:org.springframework.amqp.rabbit.AsyncRabbitTemplate.java

@Override
public RabbitMessageFuture sendAndReceive(String exchange, String routingKey, Message message) {
    String correlationId = getOrSetCorrelationIdAndSetReplyTo(message);
    RabbitMessageFuture future = new RabbitMessageFuture(correlationId, message);
    CorrelationData correlationData = null;
    if (this.enableConfirms) {
        correlationData = new CorrelationData(correlationId);
        future.setConfirm(new SettableListenableFuture<Boolean>());
    }//w  w w .  jav  a2  s  .c o  m
    this.pending.put(correlationId, future);
    if (this.container != null) {
        this.template.send(exchange, routingKey, message, correlationData);
    } else {
        ChannelHolder channelHolder = this.directReplyToContainer.getChannelHolder();
        future.setChannelHolder(channelHolder);
        sendDirect(channelHolder.getChannel(), exchange, routingKey, message, correlationData);
    }
    future.startTimer();
    return future;
}

From source file:org.springframework.amqp.rabbit.core.AsyncRabbitTemplate.java

/**
 * Send a message to the supplied exchange and routing key. If the message
 * contains a correlationId property, it must be unique.
 * @param exchange the exchange.//from   w w w  .j a  va  2s  .co m
 * @param routingKey the routing key.
 * @param message the message.
 * @return the {@link RabbitMessageFuture}.
 */
public RabbitMessageFuture sendAndReceive(String exchange, String routingKey, Message message) {
    String correlationId = getOrSetCorrelationIdAndSetReplyTo(message);
    RabbitMessageFuture future = new RabbitMessageFuture(correlationId);
    CorrelationData correlationData = null;
    if (this.enableConfirms) {
        correlationData = new CorrelationData(correlationId);
        future.setConfirm(new SettableListenableFuture<Boolean>());
    }
    this.pending.put(correlationId, future);
    this.template.send(exchange, routingKey, message, correlationData);
    return future;
}

From source file:org.springframework.cloud.dataflow.yarn.container.ContainerApplication.java

@OnContainerStart
public Future<Boolean> runModule(@YarnParameters Properties properties,
        @YarnParameter("containerModules") String module) {
    log.info("runModule module=" + module);
    log.info("runModule properties=" + properties);
    log.info("moduleLauncher=" + moduleLauncher);

    Map<String, String> args = new HashMap<String, String>();

    for (Entry<Object, Object> entry : properties.entrySet()) {
        String key = entry.getKey().toString();
        String value = entry.getValue().toString();
        if (!key.startsWith("containerModules")) {
            args.put(key, value);/*ww  w .j a  v  a2  s.c o  m*/
        }
    }

    log.info("Passing args to moduleLauncher: " + args);

    // we should somehow get status back from module
    // launcher when it fails or finishes to set future
    // indicating we're done. Naturally exception will
    // terminate execution chain and container will exit.
    SettableListenableFuture<Boolean> status = new SettableListenableFuture<Boolean>();
    moduleLauncher.launch(Arrays.asList(new ModuleLaunchRequest(module, args)));
    return status;
}

From source file:org.springframework.cloud.dataflow.yarn.streamcontainer.StreamContainerApplication.java

@OnContainerStart
public Future<Boolean> runModule(@YarnParameters Properties properties,
        @YarnParameter("containerModules") String module) {

    if (log.isInfoEnabled()) {
        log.info("runModule module=" + module);
        log.info("runModule properties=" + properties);
        log.info("moduleLauncher=" + moduleLauncher);
    }//from   w w  w. j a v  a  2  s .com

    Map<String, String> args = new HashMap<>();

    for (Entry<Object, Object> entry : properties.entrySet()) {
        String key = entry.getKey().toString();
        String value = entry.getValue().toString();
        if (!key.startsWith("containerModules")) {
            args.put(key, value);
        }
    }

    if (log.isInfoEnabled()) {
        log.info("Passing args to moduleLauncher: " + args);
    }

    // we should somehow get status back from module
    // launcher when it fails or finishes to set future
    // indicating we're done. Naturally exception will
    // terminate execution chain and container will exit.
    SettableListenableFuture<Boolean> status = new SettableListenableFuture<>();
    moduleLauncher.launch(Arrays.asList(new ModuleLaunchRequest(module, args)));
    return status;
}

From source file:org.springframework.cloud.deployer.spi.yarn.YarnAppDeployer.java

@Override
public String deploy(AppDeploymentRequest request) {
    logger.info("Deploy request for {}", request);
    final AppDefinition definition = request.getDefinition();
    Map<String, String> definitionParameters = definition.getProperties();
    Map<String, String> deploymentProperties = request.getDeploymentProperties();
    logger.info("Deploying request for definition {}", definition);
    logger.info("Parameters for definition {}", definitionParameters);
    logger.info("Deployment properties for request {}", deploymentProperties);

    int count = 1;
    String countString = request.getDeploymentProperties().get(AppDeployer.COUNT_PROPERTY_KEY);
    if (StringUtils.hasText(countString)) {
        count = Integer.parseInt(countString);
    }/*from   www. jav a2 s .co  m*/
    final String group = request.getDeploymentProperties().get(AppDeployer.GROUP_PROPERTY_KEY);
    Resource resource = request.getResource();
    final String clusterId = group + ":" + definition.getName();

    // contextRunArgs are passed to boot app ran to control yarn apps
    ArrayList<String> contextRunArgs = new ArrayList<String>();
    contextRunArgs.add("--spring.yarn.appName=scdstream:app:" + group);

    // deployment properties override servers.yml which overrides application.yml
    for (Entry<String, String> entry : deploymentProperties.entrySet()) {
        if (entry.getKey().startsWith("spring.cloud.deployer.yarn.app.streamappmaster")) {
            contextRunArgs.add("--" + entry.getKey() + "=" + entry.getValue());
        } else if (entry.getKey().startsWith("spring.cloud.deployer.yarn.app.streamcontainer")) {
            // weird format with '--' is just straight pass to appmaster
            contextRunArgs.add("--spring.yarn.client.launchcontext.arguments.--" + entry.getKey() + "='"
                    + entry.getValue() + "'");
        }
    }

    String baseDir = yarnDeployerProperties.getBaseDir();
    if (!baseDir.endsWith("/")) {
        baseDir = baseDir + "/";
    }

    String artifactPath = isHdfsResource(resource) ? getHdfsArtifactPath(resource)
            : baseDir + "/artifacts/cache/";
    contextRunArgs
            .add("--spring.yarn.client.launchcontext.arguments.--spring.cloud.deployer.yarn.appmaster.artifact="
                    + artifactPath);

    // TODO: using default app name "app" until we start to customise
    //       via deploymentProperties
    final Message<String> message = MessageBuilder.withPayload(AppDeployerStateMachine.EVENT_DEPLOY)
            .setHeader(AppDeployerStateMachine.HEADER_APP_VERSION, "app")
            .setHeader(AppDeployerStateMachine.HEADER_CLUSTER_ID, clusterId)
            .setHeader(AppDeployerStateMachine.HEADER_GROUP_ID, group)
            .setHeader(AppDeployerStateMachine.HEADER_COUNT, count)
            .setHeader(AppDeployerStateMachine.HEADER_ARTIFACT, resource)
            .setHeader(AppDeployerStateMachine.HEADER_ARTIFACT_DIR, artifactPath)
            .setHeader(AppDeployerStateMachine.HEADER_DEFINITION_PARAMETERS, definitionParameters)
            .setHeader(AppDeployerStateMachine.HEADER_CONTEXT_RUN_ARGS, contextRunArgs).build();

    // Use of future here is to set id when it becomes available from machine
    final SettableListenableFuture<String> id = new SettableListenableFuture<>();
    final StateMachineListener<String, String> listener = new StateMachineListenerAdapter<String, String>() {

        @Override
        public void stateContext(StateContext<String, String> stateContext) {
            if (stateContext.getStage() == Stage.STATE_ENTRY
                    && stateContext.getTarget().getId().equals(AppDeployerStateMachine.STATE_READY)) {
                if (ObjectUtils.nullSafeEquals(message.getHeaders().getId().toString(), stateContext
                        .getExtendedState().get(AppDeployerStateMachine.VAR_MESSAGE_ID, String.class))) {
                    Exception exception = stateContext.getExtendedState().get(AppDeployerStateMachine.VAR_ERROR,
                            Exception.class);
                    if (exception != null) {
                        id.setException(exception);
                    } else {
                        String applicationId = stateContext.getStateMachine().getExtendedState()
                                .get(AppDeployerStateMachine.VAR_APPLICATION_ID, String.class);
                        DeploymentKey key = new DeploymentKey(group, definition.getName(), applicationId);
                        id.set(key.toString());
                    }
                }
            }
        }
    };
    stateMachine.addStateListener(listener);
    id.addCallback(new ListenableFutureCallback<String>() {

        @Override
        public void onSuccess(String result) {
            stateMachine.removeStateListener(listener);
        }

        @Override
        public void onFailure(Throwable ex) {
            stateMachine.removeStateListener(listener);
        }
    });

    stateMachine.sendEvent(message);
    // we need to block here until SPI supports
    // returning id asynchronously
    try {
        return id.get(2, TimeUnit.MINUTES);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

From source file:org.springframework.cloud.deployer.spi.yarn.YarnTaskLauncher.java

@Override
public String launch(AppDeploymentRequest request) {
    logger.info("Deploy request for {}", request);
    logger.info("Deploy request deployment properties {}", request.getDeploymentProperties());
    logger.info("Deploy definition {}", request.getDefinition());
    Resource resource = request.getResource();
    AppDefinition definition = request.getDefinition();

    String artifact = resource.getFilename();

    final String name = definition.getName();
    Map<String, String> definitionParameters = definition.getProperties();
    Map<String, String> deploymentProperties = request.getDeploymentProperties();
    List<String> commandlineArguments = request.getCommandlineArguments();
    String appName = "scdtask:" + name;

    // contextRunArgs are passed to boot app ran to control yarn apps
    // we pass needed args to control module coordinates and params,
    // weird format with '--' is just straight pass to container
    ArrayList<String> contextRunArgs = new ArrayList<String>();

    contextRunArgs.add("--spring.yarn.appName=" + appName);
    for (Entry<String, String> entry : definitionParameters.entrySet()) {
        if (StringUtils.hasText(entry.getValue())) {
            contextRunArgs.add(/*from   w  w w  .ja v  a 2  s.  c  o m*/
                    "--spring.yarn.client.launchcontext.arguments.--spring.cloud.deployer.yarn.appmaster.parameters."
                            + entry.getKey() + ".='" + entry.getValue() + "'");
        }
    }

    int index = 0;
    for (String commandlineArgument : commandlineArguments) {
        contextRunArgs.add("--spring.yarn.client.launchcontext.argumentsList[" + index
                + "]='--spring.cloud.deployer.yarn.appmaster.commandlineArguments[" + index + "]="
                + commandlineArgument + "'");
        index++;
    }

    String baseDir = yarnDeployerProperties.getBaseDir();
    if (!baseDir.endsWith("/")) {
        baseDir = baseDir + "/";
    }
    String artifactPath = isHdfsResource(resource) ? getHdfsArtifactPath(resource)
            : baseDir + "/artifacts/cache/";

    contextRunArgs.add(
            "--spring.yarn.client.launchcontext.arguments.--spring.yarn.appmaster.launchcontext.archiveFile="
                    + artifact);
    contextRunArgs
            .add("--spring.yarn.client.launchcontext.arguments.--spring.cloud.deployer.yarn.appmaster.artifact="
                    + artifactPath + artifact);

    // deployment properties override servers.yml which overrides application.yml
    for (Entry<String, String> entry : deploymentProperties.entrySet()) {
        if (StringUtils.hasText(entry.getValue())) {
            if (entry.getKey().startsWith("spring.cloud.deployer.yarn.app.taskcontainer")) {
                contextRunArgs.add("--spring.yarn.client.launchcontext.arguments.--" + entry.getKey() + "='"
                        + entry.getValue() + "'");
            } else if (entry.getKey().startsWith("spring.cloud.deployer.yarn.app.taskappmaster")) {
                contextRunArgs.add("--" + entry.getKey() + "=" + entry.getValue());
            }
        }
    }

    final Message<String> message = MessageBuilder.withPayload(TaskLauncherStateMachine.EVENT_LAUNCH)
            .setHeader(TaskLauncherStateMachine.HEADER_APP_VERSION, "app")
            .setHeader(TaskLauncherStateMachine.HEADER_ARTIFACT, resource)
            .setHeader(TaskLauncherStateMachine.HEADER_ARTIFACT_DIR, artifactPath)
            .setHeader(TaskLauncherStateMachine.HEADER_DEFINITION_PARAMETERS, definitionParameters)
            .setHeader(TaskLauncherStateMachine.HEADER_CONTEXT_RUN_ARGS, contextRunArgs).build();

    // setup future, listen event from machine and finally unregister listener,
    // and set future value
    final SettableListenableFuture<String> id = new SettableListenableFuture<>();
    final StateMachineListener<String, String> listener = new StateMachineListenerAdapter<String, String>() {

        @Override
        public void stateContext(StateContext<String, String> stateContext) {
            if (stateContext.getStage() == Stage.STATE_ENTRY
                    && stateContext.getTarget().getId().equals(TaskLauncherStateMachine.STATE_READY)) {
                if (ObjectUtils.nullSafeEquals(message.getHeaders().getId().toString(), stateContext
                        .getExtendedState().get(TaskLauncherStateMachine.VAR_MESSAGE_ID, String.class))) {
                    Exception exception = stateContext.getExtendedState()
                            .get(TaskLauncherStateMachine.VAR_ERROR, Exception.class);
                    if (exception != null) {
                        id.setException(exception);
                    } else {
                        String applicationId = stateContext.getStateMachine().getExtendedState()
                                .get(TaskLauncherStateMachine.VAR_APPLICATION_ID, String.class);
                        DeploymentKey key = new DeploymentKey(name, applicationId);
                        id.set(key.toString());
                    }
                }
            }
        }
    };

    stateMachine.addStateListener(listener);
    id.addCallback(new ListenableFutureCallback<String>() {

        @Override
        public void onSuccess(String result) {
            stateMachine.removeStateListener(listener);
        }

        @Override
        public void onFailure(Throwable ex) {
            stateMachine.removeStateListener(listener);
        }
    });

    stateMachine.sendEvent(message);
    // we need to block here until SPI supports
    // returning id asynchronously
    try {
        return id.get(2, TimeUnit.MINUTES);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

From source file:org.springframework.cloud.gcp.pubsub.core.publisher.PubSubPublisherTemplate.java

@Override
public ListenableFuture<String> publish(final String topic, PubsubMessage pubsubMessage) {
    Assert.hasText(topic, "The topic can't be null or empty.");
    Assert.notNull(pubsubMessage, "The pubsubMessage can't be null.");

    ApiFuture<String> publishFuture = this.publisherFactory.createPublisher(topic).publish(pubsubMessage);

    final SettableListenableFuture<String> settableFuture = new SettableListenableFuture<>();
    ApiFutures.addCallback(publishFuture, new ApiFutureCallback<String>() {

        @Override//from w w  w.  ja  v a  2s.  co  m
        public void onFailure(Throwable throwable) {
            LOGGER.warn("Publishing to " + topic + " topic failed.", throwable);
            settableFuture.setException(throwable);
        }

        @Override
        public void onSuccess(String result) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Publishing to " + topic + " was successful. Message ID: " + result);
            }
            settableFuture.set(result);
        }

    });

    return settableFuture;
}

From source file:org.springframework.integration.amqp.outbound.AsyncAmqpGatewayTests.java

@Test
public void testConfirmsAndReturns() throws Exception {
    CachingConnectionFactory ccf = new CachingConnectionFactory("localhost");
    ccf.setPublisherConfirms(true);//from ww w .ja  v a 2s  .c om
    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);
    assertEquals("fiz", returned.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);
    assertEquals("buz", ack.getPayload());
    assertEquals("nacknack", ack.getHeaders().get(AmqpHeaders.PUBLISH_CONFIRM_NACK_CAUSE));
    assertEquals(false, ack.getHeaders().get(AmqpHeaders.PUBLISH_CONFIRM));

    asyncTemplate.stop();
    receiver.stop();
    ccf.destroy();
}

From source file:org.springframework.integration.handler.AsyncHandlerTests.java

@Before
public void setup() {
    this.handler = new AbstractReplyProducingMessageHandler() {

        @Override//w  w  w  .  j  a  va2  s.  c o  m
        protected Object handleRequestMessage(Message<?> requestMessage) {
            final SettableListenableFuture<String> future = new SettableListenableFuture<String>();
            Executors.newSingleThreadExecutor().execute(() -> {
                try {
                    latch.await(10, TimeUnit.SECONDS);
                    switch (whichTest) {
                    case 0:
                        future.set("reply");
                        break;
                    case 1:
                        future.setException(new RuntimeException("foo"));
                        break;
                    case 2:
                        future.setException(new MessagingException(requestMessage));
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
            return future;
        }

    };
    this.handler.setAsync(true);
    this.handler.setOutputChannel(this.output);
    this.handler.setBeanFactory(mock(BeanFactory.class));
    this.latch = new CountDownLatch(1);
    Log logger = spy(TestUtils.getPropertyValue(this.handler, "logger", Log.class));
    new DirectFieldAccessor(this.handler).setPropertyValue("logger", logger);
    doAnswer(invocation -> {
        failedCallbackMessage = invocation.getArgument(0);
        failedCallbackException = invocation.getArgument(1);
        exceptionLatch.countDown();
        return null;
    }).when(logger).error(anyString(), any(Throwable.class));
}