@Test
  public void testContainerWithDestNameNoCorrelation() throws Exception {
    BeanFactory beanFactory = mock(BeanFactory.class);
    when(beanFactory.containsBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME))
        .thenReturn(true);
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.initialize();
    when(beanFactory.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class))
        .thenReturn(scheduler);
    final JmsOutboundGateway gateway = new JmsOutboundGateway();
    gateway.setBeanFactory(beanFactory);
    gateway.setConnectionFactory(getConnectionFactory());
    gateway.setRequestDestination(requestQueue4);
    gateway.setReplyDestinationName("reply4");
    gateway.setUseReplyContainer(true);
    gateway.afterPropertiesSet();
    gateway.start();
    final AtomicReference<Object> reply = new AtomicReference<Object>();
    final CountDownLatch latch1 = new CountDownLatch(1);
    final CountDownLatch latch2 = new CountDownLatch(1);
    Executors.newSingleThreadExecutor()
        .execute(
            () -> {
              latch1.countDown();
              try {
                reply.set(gateway.handleRequestMessage(new GenericMessage<String>("foo")));
              } finally {
                latch2.countDown();
              }
            });
    assertTrue(latch1.await(10, TimeUnit.SECONDS));
    JmsTemplate template = new JmsTemplate();
    template.setConnectionFactory(getConnectionFactory());
    template.setReceiveTimeout(10000);
    javax.jms.Message request = template.receive(requestQueue4);
    assertNotNull(request);
    final javax.jms.Message jmsReply = request;
    template.send(
        request.getJMSReplyTo(),
        (MessageCreator)
            session -> {
              jmsReply.setJMSCorrelationID(jmsReply.getJMSMessageID());
              return jmsReply;
            });
    assertTrue(latch2.await(10, TimeUnit.SECONDS));
    assertNotNull(reply.get());

    gateway.stop();
    scheduler.destroy();
  }
 @Test
 public void testContainerBeanNameWhenNoGatewayBeanName() {
   JmsOutboundGateway gateway = new JmsOutboundGateway();
   gateway.setConnectionFactory(mock(ConnectionFactory.class));
   gateway.setRequestDestinationName("foo");
   gateway.setUseReplyContainer(true);
   gateway.setReplyContainerProperties(new ReplyContainerProperties());
   gateway.afterPropertiesSet();
   assertEquals(
       "JMS_OutboundGateway@" + ObjectUtils.getIdentityHexString(gateway) + ".replyListener",
       TestUtils.getPropertyValue(gateway, "replyContainer.beanName"));
 }
  @Test
  public void testReplyContainerRecovery() throws Exception {
    JmsOutboundGateway gateway = new JmsOutboundGateway();
    ConnectionFactory connectionFactory = mock(ConnectionFactory.class);
    gateway.setConnectionFactory(connectionFactory);
    gateway.setRequestDestinationName("foo");
    gateway.setUseReplyContainer(true);
    ReplyContainerProperties replyContainerProperties = new ReplyContainerProperties();
    final List<Throwable> errors = new ArrayList<Throwable>();
    ErrorHandlingTaskExecutor errorHandlingTaskExecutor =
        new ErrorHandlingTaskExecutor(
            Executors.newFixedThreadPool(10),
            new ErrorHandler() {

              @Override
              public void handleError(Throwable t) {
                logger.info("Error:", t);
                errors.add(t);
                throw new RuntimeException(t);
              }
            });
    replyContainerProperties.setTaskExecutor(errorHandlingTaskExecutor);
    replyContainerProperties.setRecoveryInterval(100L);
    gateway.setReplyContainerProperties(replyContainerProperties);
    final Connection connection = mock(Connection.class);
    final AtomicInteger connectionAttempts = new AtomicInteger();
    doAnswer(
            new Answer<Connection>() {

              @SuppressWarnings("serial")
              @Override
              public Connection answer(InvocationOnMock invocation) throws Throwable {
                int theCount = connectionAttempts.incrementAndGet();
                if (theCount > 1 && theCount < 4) {
                  throw new JmsException("bar") {};
                }
                return connection;
              }
            })
        .when(connectionFactory)
        .createConnection();
    Session session = mock(Session.class);
    when(connection.createSession(false, 1)).thenReturn(session);
    MessageConsumer consumer = mock(MessageConsumer.class);
    when(session.createConsumer(any(Destination.class), anyString())).thenReturn(consumer);
    when(session.createTemporaryQueue()).thenReturn(mock(TemporaryQueue.class));
    final Message message = mock(Message.class);
    final AtomicInteger count = new AtomicInteger();
    doAnswer(
            new Answer<Message>() {

              @SuppressWarnings("serial")
              @Override
              public Message answer(InvocationOnMock invocation) throws Throwable {
                int theCount = count.incrementAndGet();
                if (theCount > 1 && theCount < 4) {
                  throw new JmsException("foo") {};
                }
                if (theCount > 4) {
                  Thread.sleep(100);
                  return null;
                }
                return message;
              }
            })
        .when(consumer)
        .receive(anyLong());
    when(message.getJMSCorrelationID()).thenReturn("foo");
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.initialize();
    beanFactory.registerSingleton("taskScheduler", taskScheduler);
    gateway.setBeanFactory(beanFactory);
    gateway.afterPropertiesSet();
    gateway.start();
    try {
      int n = 0;
      while (n++ < 100 && count.get() < 5) {
        Thread.sleep(100);
      }
      assertTrue(count.get() > 4);
      assertEquals(0, errors.size());
    } finally {
      gateway.stop();
    }
  }
  @Test
  public void testLazyContainerWithDest() throws Exception {
    BeanFactory beanFactory = mock(BeanFactory.class);
    when(beanFactory.containsBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME))
        .thenReturn(true);
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.initialize();
    when(beanFactory.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class))
        .thenReturn(scheduler);
    final JmsOutboundGateway gateway = new JmsOutboundGateway();
    gateway.setBeanFactory(beanFactory);
    gateway.setConnectionFactory(getConnectionFactory());
    gateway.setRequestDestination(requestQueue7);
    gateway.setReplyDestination(replyQueue7);
    gateway.setCorrelationKey("JMSCorrelationID");
    gateway.setUseReplyContainer(true);
    gateway.setIdleReplyContainerTimeout(1, TimeUnit.SECONDS);
    gateway.setRequiresReply(true);
    gateway.setReceiveTimeout(20000);
    gateway.afterPropertiesSet();
    gateway.start();
    Executors.newSingleThreadExecutor()
        .execute(
            () -> {
              JmsTemplate template = new JmsTemplate();
              template.setConnectionFactory(getConnectionFactory());
              template.setReceiveTimeout(20000);
              receiveAndSend(template);
              receiveAndSend(template);
            });

    assertNotNull(gateway.handleRequestMessage(new GenericMessage<String>("foo")));
    DefaultMessageListenerContainer container =
        TestUtils.getPropertyValue(
            gateway, "replyContainer", DefaultMessageListenerContainer.class);
    int n = 0;
    while (n++ < 100 && container.isRunning()) {
      Thread.sleep(100);
    }
    assertFalse(container.isRunning());
    assertNotNull(gateway.handleRequestMessage(new GenericMessage<String>("foo")));
    assertTrue(container.isRunning());

    gateway.stop();
    assertFalse(container.isRunning());
    scheduler.destroy();
  }