private SimpleMessageListenerContainer verifyContainer(AbstractEndpoint endpoint) {
    SimpleMessageListenerContainer container;
    Advice retry;
    container =
        TestUtils.getPropertyValue(
            endpoint, "messageListenerContainer", SimpleMessageListenerContainer.class);
    assertEquals(AcknowledgeMode.NONE, container.getAcknowledgeMode());
    assertThat(container.getQueueNames()[0], startsWith("foo.props.0"));
    assertFalse(TestUtils.getPropertyValue(container, "transactional", Boolean.class));
    assertEquals(2, TestUtils.getPropertyValue(container, "concurrentConsumers"));
    assertEquals(3, TestUtils.getPropertyValue(container, "maxConcurrentConsumers"));
    assertFalse(TestUtils.getPropertyValue(container, "defaultRequeueRejected", Boolean.class));
    assertEquals(20, TestUtils.getPropertyValue(container, "prefetchCount"));
    assertEquals(10, TestUtils.getPropertyValue(container, "txSize"));
    retry = TestUtils.getPropertyValue(container, "adviceChain", Advice[].class)[0];
    assertEquals(23, TestUtils.getPropertyValue(retry, "retryOperations.retryPolicy.maxAttempts"));
    assertEquals(
        2000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.initialInterval"));
    assertEquals(
        20000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.maxInterval"));
    assertEquals(
        5.0, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.multiplier"));

    List<?> requestMatchers =
        TestUtils.getPropertyValue(
            endpoint, "headerMapper.requestHeaderMatcher.strategies", List.class);
    assertEquals(1, requestMatchers.size());
    assertEquals(
        "foo",
        TestUtils.getPropertyValue(requestMatchers.get(0), "patterns", Collection.class)
            .iterator()
            .next());

    return container;
  }
 @Test
 public void testParseWithTx() throws Exception {
   SimpleMessageListenerContainer container =
       beanFactory.getBean("container6", SimpleMessageListenerContainer.class);
   assertTrue(container.isChannelTransacted());
   assertEquals(5, ReflectionTestUtils.getField(container, "txSize"));
 }
Example #3
0
 private HeartBeatListener() {
   setAlive(false);
   RabbitAdmin rabbitAdmin = RabbitConfiguration.getRabbitAdmin();
   Queue queue = rabbitAdmin.declareQueue();
   FanoutExchange exchange = new FanoutExchange(HEART_BEAT_EXCHANGE);
   rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange));
   HeartBeatMessageListener heartBeatMessageListener = new HeartBeatMessageListener();
   SimpleMessageListenerContainer messageListenerContainer = new SimpleMessageListenerContainer();
   messageListenerContainer.setQueues(queue);
   messageListenerContainer.setConnectionFactory(RabbitConfiguration.getConnectionFactory());
   messageListenerContainer.setMessageListener(heartBeatMessageListener);
   messageListenerContainer.start();
   Thread thread =
       new Thread(
           new Runnable() {
             @Override
             public void run() {
               while (true) {
                 try {
                   Message result;
                   result = heartBeats.poll(TIMEOUT, TimeUnit.MILLISECONDS);
                   if (result == null) {
                     setAlive(false);
                   } else {
                     setAlive(true);
                   }
                 } catch (InterruptedException e) {
                   setAlive(false);
                 }
               }
             }
           },
           "server-heart-beat-listener");
   thread.start();
 }
 @Test
 public void testParseWithDefaultQueueRejectedFalse() throws Exception {
   SimpleMessageListenerContainer container =
       beanFactory.getBean("container5", SimpleMessageListenerContainer.class);
   assertEquals(1, ReflectionTestUtils.getField(container, "concurrentConsumers"));
   assertEquals(false, ReflectionTestUtils.getField(container, "defaultRequeueRejected"));
   assertFalse(container.isChannelTransacted());
 }
 @Test
 public void testParseWithQueues() throws Exception {
   SimpleMessageListenerContainer container =
       beanFactory.getBean("container2", SimpleMessageListenerContainer.class);
   Queue queue = beanFactory.getBean("bar", Queue.class);
   assertEquals(
       "[foo, " + queue.getName() + "]", Arrays.asList(container.getQueueNames()).toString());
   assertTrue(TestUtils.getPropertyValue(container, "missingQueuesFatal", Boolean.class));
   assertFalse(TestUtils.getPropertyValue(container, "autoDeclare", Boolean.class));
 }
  @Bean
  SimpleMessageListenerContainer container(
      ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setQueueNames(MAIL_MESSAGE_CMD_QUEUE);
    container.setMessageListener(listenerAdapter);

    return container;
  }
 @Bean
 public SimpleMessageListenerContainer messageListenerContainer(AmqpAdmin amqpAdmin) {
   SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
   container.setConnectionFactory(rabbitConnectionFactory());
   container.setQueueNames(clientQueue(amqpAdmin).getName());
   container.setMessageListener(
       new MessageListenerAdapter(serviceMessageReceiver, messageConverter));
   // No acks will be sent (incompatible with channelTransacted=true). RabbitMQ calls this
   // "autoack" because the broker assumes all messages are acked without any action from the
   // consumer.
   container.setAcknowledgeMode(AcknowledgeMode.NONE);
   return container;
 }
 private SimpleMessageListenerContainer createContainer(Object listener) {
   SimpleMessageListenerContainer container =
       new SimpleMessageListenerContainer(template.getConnectionFactory());
   container.setMessageListener(new MessageListenerAdapter(listener));
   container.setQueueNames(queue.getName());
   container.setTxSize(txSize);
   container.setPrefetchCount(txSize);
   container.setConcurrentConsumers(concurrentConsumers);
   container.setChannelTransacted(transactional);
   container.setAcknowledgeMode(AcknowledgeMode.AUTO);
   container.afterPropertiesSet();
   container.start();
   return container;
 }
 private void doListenerWithExceptionTest(CountDownLatch latch, Object listener) throws Exception {
   container = createContainer(listener);
   if (acknowledgeMode.isTransactionAllowed()) {
     // Should only need one message if it is going to fail
     for (int i = 0; i < concurrentConsumers; i++) {
       template.convertAndSend(queue.getName(), i + "foo");
     }
   } else {
     for (int i = 0; i < messageCount; i++) {
       template.convertAndSend(queue.getName(), i + "foo");
     }
   }
   try {
     boolean waited = latch.await(10 + Math.max(1, messageCount / 10), TimeUnit.SECONDS);
     assertTrue("Timed out waiting for message", waited);
   } finally {
     // Wait for broker communication to finish before trying to stop
     // container
     Thread.sleep(300L);
     container.shutdown();
     Thread.sleep(300L);
   }
   if (acknowledgeMode.isTransactionAllowed()) {
     assertNotNull(template.receiveAndConvert(queue.getName()));
   } else {
     assertNull(template.receiveAndConvert(queue.getName()));
   }
 }
  private void doTest(int concurrentConsumers, ContainerConfigurer configurer) {
    int messageCount = 10;
    RabbitTemplate template = new RabbitTemplate();
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setHost("localhost");
    connectionFactory.setChannelCacheSize(concurrentConsumers);
    connectionFactory.setPort(BrokerTestUtils.getPort());
    template.setConnectionFactory(connectionFactory);
    SimpleMessageConverter messageConverter = new SimpleMessageConverter();
    messageConverter.setCreateMessageIds(true);
    template.setMessageConverter(messageConverter);
    for (int i = 0; i < messageCount; i++) {
      template.convertAndSend(queue1.getName(), new Integer(i));
      template.convertAndSend(queue2.getName(), new Integer(i));
    }
    final SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(connectionFactory);
    final CountDownLatch latch = new CountDownLatch(messageCount * 2);
    PojoListener listener = new PojoListener(latch);
    container.setMessageListener(new MessageListenerAdapter(listener));
    container.setAcknowledgeMode(AcknowledgeMode.AUTO);
    container.setChannelTransacted(true);
    container.setConcurrentConsumers(concurrentConsumers);
    configurer.configure(container);
    container.afterPropertiesSet();
    container.start();
    try {
      int timeout = Math.min(1 + messageCount / concurrentConsumers, 30);
      boolean waited = latch.await(timeout, TimeUnit.SECONDS);
      logger.info("All messages recovered: " + waited);
      assertEquals(concurrentConsumers, container.getActiveConsumerCount());
      assertTrue("Timed out waiting for messages", waited);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new IllegalStateException("unexpected interruption");
    } finally {
      container.shutdown();
      assertEquals(0, container.getActiveConsumerCount());
    }
    assertNull(template.receiveAndConvert(queue1.getName()));
    assertNull(template.receiveAndConvert(queue2.getName()));

    connectionFactory.destroy();
  }
  @After
  public void clear() throws Exception {
    // Wait for broker communication to finish before trying to stop container
    Thread.sleep(300L);
    logger.debug("Shutting down at end of test");
    if (container != null) {
      container.shutdown();
    }

    ((DisposableBean) template.getConnectionFactory()).destroy();
  }
  @Test
  public void testPublisherConfirmWithSendAndReceive() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicReference<CorrelationData> confirmCD = new AtomicReference<CorrelationData>();
    templateWithConfirmsEnabled.setConfirmCallback(
        new ConfirmCallback() {

          @Override
          public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            confirmCD.set(correlationData);
            latch.countDown();
          }
        });
    SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(this.connectionFactoryWithConfirmsEnabled);
    container.setQueueNames(ROUTE);
    container.setMessageListener(
        new MessageListenerAdapter(
            new Object() {

              @SuppressWarnings("unused")
              public String handleMessage(String in) {
                return in.toUpperCase();
              }
            }));
    container.start();
    CorrelationData correlationData = new CorrelationData("abc");
    String result =
        (String)
            this.templateWithConfirmsEnabled.convertSendAndReceive(
                ROUTE, (Object) "message", correlationData);
    container.stop();
    assertEquals("MESSAGE", result);
    assertTrue(latch.await(10, TimeUnit.SECONDS));
    assertEquals(correlationData, confirmCD.get());
  }
 @Test
 public void testListenerSunnyDay() throws Exception {
   CountDownLatch latch = new CountDownLatch(messageCount);
   for (int i = 0; i < messageCount; i++) {
     template.convertAndSend(queue.getName(), i + "foo");
   }
   SimpleMessageListenerContainer container =
       new SimpleMessageListenerContainer(template.getConnectionFactory());
   container.setMessageListener(new MessageListenerAdapter(new PojoListener(latch)));
   container.setChannelTransacted(transactional);
   container.setConcurrentConsumers(concurrentConsumers);
   container.setQueueName(queue.getName());
   container.afterPropertiesSet();
   container.start();
   try {
     boolean waited = latch.await(50, TimeUnit.MILLISECONDS);
     assertFalse("Expected time out waiting for message", waited);
     container.stop();
     Thread.sleep(500L);
     container.start();
     if (transactional) {
       waited = latch.await(5, TimeUnit.SECONDS);
       assertTrue("Timed out waiting for message", waited);
     } else {
       waited = latch.await(500, TimeUnit.MILLISECONDS);
       // If non-transactional we half expect to lose messages
       assertFalse("Expected time out waiting for message", waited);
     }
   } finally {
     // Wait for broker communication to finish before trying to stop
     // container
     Thread.sleep(300L);
     container.shutdown();
   }
   assertNull(template.receiveAndConvert(queue.getName()));
 }
 @Test
 public void testParseWithQueueNames() throws Exception {
   SimpleMessageListenerContainer container =
       beanFactory.getBean("container1", SimpleMessageListenerContainer.class);
   assertEquals(AcknowledgeMode.MANUAL, container.getAcknowledgeMode());
   assertEquals(beanFactory.getBean(ConnectionFactory.class), container.getConnectionFactory());
   assertEquals(MessageListenerAdapter.class, container.getMessageListener().getClass());
   DirectFieldAccessor listenerAccessor = new DirectFieldAccessor(container.getMessageListener());
   assertEquals(
       beanFactory.getBean(TestBean.class), listenerAccessor.getPropertyValue("delegate"));
   assertEquals("handle", listenerAccessor.getPropertyValue("defaultListenerMethod"));
   Queue queue = beanFactory.getBean("bar", Queue.class);
   assertEquals(
       "[foo, " + queue.getName() + "]", Arrays.asList(container.getQueueNames()).toString());
   assertEquals(5, ReflectionTestUtils.getField(container, "concurrentConsumers"));
   assertEquals(6, ReflectionTestUtils.getField(container, "maxConcurrentConsumers"));
   assertEquals(1234L, ReflectionTestUtils.getField(container, "startConsumerMinInterval"));
   assertEquals(2345L, ReflectionTestUtils.getField(container, "stopConsumerMinInterval"));
   assertEquals(12, ReflectionTestUtils.getField(container, "consecutiveActiveTrigger"));
   assertEquals(34, ReflectionTestUtils.getField(container, "consecutiveIdleTrigger"));
   assertEquals(9876L, ReflectionTestUtils.getField(container, "receiveTimeout"));
   Map<?, ?> consumerArgs = TestUtils.getPropertyValue(container, "consumerArgs", Map.class);
   assertEquals(1, consumerArgs.size());
   Object xPriority = consumerArgs.get("x-priority");
   assertNotNull(xPriority);
   assertEquals(10, xPriority);
   assertEquals(
       Long.valueOf(5555),
       TestUtils.getPropertyValue(container, "recoveryBackOff.interval", Long.class));
   assertFalse(TestUtils.getPropertyValue(container, "exclusive", Boolean.class));
   assertFalse(TestUtils.getPropertyValue(container, "missingQueuesFatal", Boolean.class));
   assertTrue(TestUtils.getPropertyValue(container, "autoDeclare", Boolean.class));
   assertEquals(5, TestUtils.getPropertyValue(container, "declarationRetries"));
   assertEquals(1000L, TestUtils.getPropertyValue(container, "failedDeclarationRetryInterval"));
   assertEquals(30000L, TestUtils.getPropertyValue(container, "retryDeclarationInterval"));
   assertEquals(
       beanFactory.getBean("tagger"),
       TestUtils.getPropertyValue(container, "consumerTagStrategy"));
   Collection<?> group = beanFactory.getBean("containerGroup", Collection.class);
   assertEquals(3, group.size());
   assertThat(
       group,
       Matchers.contains(
           beanFactory.getBean("container1"),
           beanFactory.getBean("testListener1"),
           beanFactory.getBean("testListener2")));
   assertEquals(1235L, ReflectionTestUtils.getField(container, "idleEventInterval"));
   assertEquals("container1", container.getListenerId());
 }
 @Test
 public void testParseWithQueueNames() throws Exception {
   SimpleMessageListenerContainer container =
       this.context.getBean("testListener", SimpleMessageListenerContainer.class);
   assertEquals(AcknowledgeMode.MANUAL, container.getAcknowledgeMode());
   assertEquals(this.context.getBean(ConnectionFactory.class), container.getConnectionFactory());
   assertEquals(MessageListenerAdapter.class, container.getMessageListener().getClass());
   DirectFieldAccessor listenerAccessor = new DirectFieldAccessor(container.getMessageListener());
   assertEquals(
       this.context.getBean(TestBean.class), listenerAccessor.getPropertyValue("delegate"));
   assertEquals("handle", listenerAccessor.getPropertyValue("defaultListenerMethod"));
   Queue queue = this.context.getBean("bar", Queue.class);
   assertEquals(
       "[foo, " + queue.getName() + "]", Arrays.asList(container.getQueueNames()).toString());
 }
 @Override
 protected void executeListener(Channel channel, Message message) throws Throwable {
   super.executeListener(channel, message);
   channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
   if (log.isDebugEnabled()) log.debug("Acknowledging message: " + new String(message.getBody()));
 }
 private SimpleMessageListenerContainer createContainer(Object listener) {
   SimpleMessageListenerContainer container =
       new SimpleMessageListenerContainer(template.getConnectionFactory());
   container.setMessageListener(listener);
   container.setQueueNames(queue.getName());
   container.setTxSize(txSize);
   container.setPrefetchCount(txSize);
   container.setConcurrentConsumers(concurrentConsumers);
   container.setChannelTransacted(transactional);
   container.setAcknowledgeMode(acknowledgeMode);
   // requires RabbitMQ 3.2.x
   //		container.setConsumerArguments(Collections. <String, Object> singletonMap("x-priority",
   // Integer.valueOf(10)));
   if (externalTransaction) {
     container.setTransactionManager(new TestTransactionManager());
   }
   container.afterPropertiesSet();
   container.start();
   return container;
 }
 public void invokeListener(Channel channel, Message message) throws Exception {
   SimpleMessageListenerContainer.super.invokeListener(channel, message);
 }
 private void doRegisterConsumer(
     String name,
     MessageChannel moduleInputChannel,
     Queue queue,
     RabbitPropertiesAccessor properties,
     boolean isPubSub) {
   // Fix for XD-2503
   // Temporarily overrides the thread context classloader with the one where the
   // SimpleMessageListenerContainer
   // is defined
   // This allows for the proxying that happens while initializing the
   // SimpleMessageListenerContainer to work
   // correctly
   ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader();
   try {
     ClassUtils.overrideThreadContextClassLoader(
         SimpleMessageListenerContainer.class.getClassLoader());
     SimpleMessageListenerContainer listenerContainer =
         new SimpleMessageListenerContainer(this.connectionFactory);
     listenerContainer.setAcknowledgeMode(
         properties.getAcknowledgeMode(this.defaultAcknowledgeMode));
     listenerContainer.setChannelTransacted(
         properties.getTransacted(this.defaultChannelTransacted));
     listenerContainer.setDefaultRequeueRejected(
         properties.getRequeueRejected(this.defaultDefaultRequeueRejected));
     if (!isPubSub) {
       int concurrency = properties.getConcurrency(this.defaultConcurrency);
       concurrency = concurrency > 0 ? concurrency : 1;
       listenerContainer.setConcurrentConsumers(concurrency);
       int maxConcurrency = properties.getMaxConcurrency(this.defaultMaxConcurrency);
       if (maxConcurrency > concurrency) {
         listenerContainer.setMaxConcurrentConsumers(maxConcurrency);
       }
     }
     listenerContainer.setPrefetchCount(properties.getPrefetchCount(this.defaultPrefetchCount));
     listenerContainer.setTxSize(properties.getTxSize(this.defaultTxSize));
     listenerContainer.setTaskExecutor(new SimpleAsyncTaskExecutor(queue.getName() + "-"));
     listenerContainer.setQueues(queue);
     int maxAttempts = properties.getMaxAttempts(this.defaultMaxAttempts);
     if (maxAttempts > 1 || properties.getRepublishToDLQ(this.defaultRepublishToDLQ)) {
       RetryOperationsInterceptor retryInterceptor =
           RetryInterceptorBuilder.stateless()
               .maxAttempts(maxAttempts)
               .backOffOptions(
                   properties.getBackOffInitialInterval(this.defaultBackOffInitialInterval),
                   properties.getBackOffMultiplier(this.defaultBackOffMultiplier),
                   properties.getBackOffMaxInterval(this.defaultBackOffMaxInterval))
               .recoverer(determineRecoverer(name, properties))
               .build();
       listenerContainer.setAdviceChain(new Advice[] {retryInterceptor});
     }
     listenerContainer.setAfterReceivePostProcessors(this.decompressingPostProcessor);
     listenerContainer.setMessagePropertiesConverter(
         RabbitMessageChannelBinder.inboundMessagePropertiesConverter);
     listenerContainer.afterPropertiesSet();
     AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer);
     adapter.setBeanFactory(this.getBeanFactory());
     DirectChannel bridgeToModuleChannel = new DirectChannel();
     bridgeToModuleChannel.setBeanFactory(this.getBeanFactory());
     bridgeToModuleChannel.setBeanName(name + ".bridge");
     adapter.setOutputChannel(bridgeToModuleChannel);
     adapter.setBeanName("inbound." + name);
     DefaultAmqpHeaderMapper mapper = new DefaultAmqpHeaderMapper();
     mapper.setRequestHeaderNames(
         properties.getRequestHeaderPattens(this.defaultRequestHeaderPatterns));
     mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns));
     adapter.setHeaderMapper(mapper);
     adapter.afterPropertiesSet();
     Binding consumerBinding = Binding.forConsumer(name, adapter, moduleInputChannel, properties);
     addBinding(consumerBinding);
     ReceivingHandler convertingBridge = new ReceivingHandler();
     convertingBridge.setOutputChannel(moduleInputChannel);
     convertingBridge.setBeanName(name + ".convert.bridge");
     convertingBridge.afterPropertiesSet();
     bridgeToModuleChannel.subscribe(convertingBridge);
     consumerBinding.start();
   } finally {
     Thread.currentThread().setContextClassLoader(originalClassloader);
   }
 }
  /** Verifies that an up-stack RabbitTemplate uses the listener's channel (MessageListener). */
  @SuppressWarnings("unchecked")
  @Test
  public void testMessageListener() throws Exception {
    ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class);
    Connection mockConnection = mock(Connection.class);
    final Channel onlyChannel = mock(Channel.class);
    when(onlyChannel.isOpen()).thenReturn(true);

    final CachingConnectionFactory cachingConnectionFactory =
        new CachingConnectionFactory(mockConnectionFactory);

    when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection);
    when(mockConnection.isOpen()).thenReturn(true);

    final AtomicReference<Exception> tooManyChannels = new AtomicReference<Exception>();

    doAnswer(
            new Answer<Channel>() {
              boolean done;

              @Override
              public Channel answer(InvocationOnMock invocation) throws Throwable {
                if (!done) {
                  done = true;
                  return onlyChannel;
                }
                tooManyChannels.set(new Exception("More than one channel requested"));
                Channel channel = mock(Channel.class);
                when(channel.isOpen()).thenReturn(true);
                return channel;
              }
            })
        .when(mockConnection)
        .createChannel();

    final AtomicReference<Consumer> consumer = new AtomicReference<Consumer>();

    doAnswer(
            new Answer<String>() {

              @Override
              public String answer(InvocationOnMock invocation) throws Throwable {
                consumer.set((Consumer) invocation.getArguments()[6]);
                return null;
              }
            })
        .when(onlyChannel)
        .basicConsume(
            anyString(),
            anyBoolean(),
            anyString(),
            anyBoolean(),
            anyBoolean(),
            anyMap(),
            any(Consumer.class));

    final CountDownLatch commitLatch = new CountDownLatch(1);
    doAnswer(
            new Answer<String>() {

              @Override
              public String answer(InvocationOnMock invocation) throws Throwable {
                commitLatch.countDown();
                return null;
              }
            })
        .when(onlyChannel)
        .txCommit();

    final CountDownLatch latch = new CountDownLatch(1);
    SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(cachingConnectionFactory);
    container.setMessageListener(
        new MessageListener() {
          @Override
          public void onMessage(Message message) {
            RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
            rabbitTemplate.setChannelTransacted(true);
            // should use same channel as container
            rabbitTemplate.convertAndSend("foo", "bar", "baz");
            latch.countDown();
          }
        });
    container.setQueueNames("queue");
    container.setChannelTransacted(true);
    container.setShutdownTimeout(100);
    container.afterPropertiesSet();
    container.start();

    consumer
        .get()
        .handleDelivery(
            "qux", new Envelope(1, false, "foo", "bar"), new BasicProperties(), new byte[] {0});

    assertTrue(latch.await(10, TimeUnit.SECONDS));

    Exception e = tooManyChannels.get();
    if (e != null) {
      throw e;
    }

    verify(mockConnection, Mockito.times(1)).createChannel();
    assertTrue(commitLatch.await(10, TimeUnit.SECONDS));
    verify(onlyChannel).txCommit();
    verify(onlyChannel)
        .basicPublish(
            Mockito.anyString(),
            Mockito.anyString(),
            Mockito.anyBoolean(),
            Mockito.any(BasicProperties.class),
            Mockito.any(byte[].class));

    // verify close() was never called on the channel
    DirectFieldAccessor dfa = new DirectFieldAccessor(cachingConnectionFactory);
    List<?> channels = (List<?>) dfa.getPropertyValue("cachedChannelsTransactional");
    assertEquals(0, channels.size());

    container.stop();
  }
  /**
   * Verifies that the listener channel is not exposed when so configured and up-stack
   * RabbitTemplate uses the additional channel. created when exposeListenerChannel is false
   * (ChannelAwareMessageListener).
   */
  @SuppressWarnings("unchecked")
  @Test
  public void testChannelAwareMessageListenerDontExpose() throws Exception {
    ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class);
    Connection mockConnection = mock(Connection.class);
    final Channel firstChannel = mock(Channel.class);
    when(firstChannel.isOpen()).thenReturn(true);
    final Channel secondChannel = mock(Channel.class);
    when(secondChannel.isOpen()).thenReturn(true);

    final SingleConnectionFactory singleConnectionFactory =
        new SingleConnectionFactory(mockConnectionFactory);

    when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection);
    when(mockConnection.isOpen()).thenReturn(true);

    final AtomicReference<Exception> tooManyChannels = new AtomicReference<Exception>();

    doAnswer(
            new Answer<Channel>() {
              boolean done;

              @Override
              public Channel answer(InvocationOnMock invocation) throws Throwable {
                if (!done) {
                  done = true;
                  return firstChannel;
                }
                return secondChannel;
              }
            })
        .when(mockConnection)
        .createChannel();

    final AtomicReference<Consumer> consumer = new AtomicReference<Consumer>();

    doAnswer(
            new Answer<String>() {

              @Override
              public String answer(InvocationOnMock invocation) throws Throwable {
                consumer.set((Consumer) invocation.getArguments()[6]);
                return null;
              }
            })
        .when(firstChannel)
        .basicConsume(
            anyString(),
            anyBoolean(),
            anyString(),
            anyBoolean(),
            anyBoolean(),
            anyMap(),
            any(Consumer.class));

    final CountDownLatch commitLatch = new CountDownLatch(1);
    doAnswer(
            new Answer<String>() {

              @Override
              public String answer(InvocationOnMock invocation) throws Throwable {
                commitLatch.countDown();
                return null;
              }
            })
        .when(firstChannel)
        .txCommit();

    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicReference<Channel> exposed = new AtomicReference<Channel>();
    SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(singleConnectionFactory);
    container.setMessageListener(
        new ChannelAwareMessageListener() {
          @Override
          public void onMessage(Message message, Channel channel) {
            exposed.set(channel);
            RabbitTemplate rabbitTemplate = new RabbitTemplate(singleConnectionFactory);
            rabbitTemplate.setChannelTransacted(true);
            // should use same channel as container
            rabbitTemplate.convertAndSend("foo", "bar", "baz");
            latch.countDown();
          }
        });
    container.setQueueNames("queue");
    container.setChannelTransacted(true);
    container.setExposeListenerChannel(false);
    container.setShutdownTimeout(100);
    container.afterPropertiesSet();
    container.start();

    consumer
        .get()
        .handleDelivery(
            "qux", new Envelope(1, false, "foo", "bar"), new BasicProperties(), new byte[] {0});

    assertTrue(latch.await(10, TimeUnit.SECONDS));

    Exception e = tooManyChannels.get();
    if (e != null) {
      throw e;
    }

    // once for listener, once for exposed + 0 for template (used bound)
    verify(mockConnection, Mockito.times(2)).createChannel();
    assertTrue(commitLatch.await(10, TimeUnit.SECONDS));
    verify(firstChannel).txCommit();
    verify(secondChannel).txCommit();
    verify(secondChannel)
        .basicPublish(
            Mockito.anyString(),
            Mockito.anyString(),
            Mockito.anyBoolean(),
            Mockito.any(BasicProperties.class),
            Mockito.any(byte[].class));

    assertSame(secondChannel, exposed.get());

    verify(firstChannel, Mockito.never()).close();
    verify(secondChannel, Mockito.times(1)).close();
    container.stop();
  }
 private SimpleMessageListenerContainer createContainer() throws Exception {
   // if (!messageDriven) TODO: no container attributes would apply if not message-driven
   SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
   if (this.acknowledgeMode != null) {
     container.setAcknowledgeMode(this.acknowledgeMode);
   }
   if (!ObjectUtils.isEmpty(this.adviceChain)) {
     container.setAdviceChain(this.adviceChain);
   }
   container.setAutoStartup(this.autoStartup);
   container.setChannelTransacted(this.channelTransacted);
   if (this.concurrentConsumers != null) {
     container.setConcurrentConsumers(this.concurrentConsumers);
   }
   container.setConnectionFactory(this.connectionFactory);
   if (this.errorHandler != null) {
     container.setErrorHandler(this.errorHandler);
   }
   if (this.exposeListenerChannel != null) {
     container.setExposeListenerChannel(this.exposeListenerChannel);
   }
   if (this.messagePropertiesConverter != null) {
     container.setMessagePropertiesConverter(this.messagePropertiesConverter);
   }
   if (this.phase != null) {
     container.setPhase(this.phase);
   }
   if (this.prefetchCount != null) {
     container.setPrefetchCount(this.prefetchCount);
   }
   if (this.receiveTimeout != null) {
     container.setReceiveTimeout(this.receiveTimeout);
   }
   if (this.recoveryInterval != null) {
     container.setRecoveryInterval(this.recoveryInterval);
   }
   if (this.shutdownTimeout != null) {
     container.setShutdownTimeout(this.shutdownTimeout);
   }
   if (this.taskExecutor != null) {
     container.setTaskExecutor(this.taskExecutor);
   }
   if (this.transactionAttribute != null) {
     container.setTransactionAttribute(this.transactionAttribute);
   }
   if (this.transactionManager != null) {
     container.setTransactionManager(this.transactionManager);
   }
   if (this.txSize != null) {
     container.setTxSize(this.txSize);
   }
   if (this.missingQueuesFatal != null) {
     container.setMissingQueuesFatal(this.missingQueuesFatal);
   }
   return container;
 }
  @Test
  public void testConsumerProperties() throws Exception {
    MessageBus bus = getMessageBus();
    Properties properties = new Properties();
    properties.put(
        "transacted", "true"); // test transacted with defaults; not allowed with ackmode NONE
    bus.bindConsumer("props.0", new DirectChannel(), properties);
    @SuppressWarnings("unchecked")
    List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
    assertEquals(1, bindings.size());
    AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
    SimpleMessageListenerContainer container =
        TestUtils.getPropertyValue(
            endpoint, "messageListenerContainer", SimpleMessageListenerContainer.class);
    assertEquals(AcknowledgeMode.AUTO, container.getAcknowledgeMode());
    assertEquals("xdbus.props.0", container.getQueueNames()[0]);
    assertTrue(TestUtils.getPropertyValue(container, "transactional", Boolean.class));
    assertEquals(1, TestUtils.getPropertyValue(container, "concurrentConsumers"));
    assertNull(TestUtils.getPropertyValue(container, "maxConcurrentConsumers"));
    assertTrue(TestUtils.getPropertyValue(container, "defaultRequeueRejected", Boolean.class));
    assertEquals(1, TestUtils.getPropertyValue(container, "prefetchCount"));
    assertEquals(1, TestUtils.getPropertyValue(container, "txSize"));
    Advice retry = TestUtils.getPropertyValue(container, "adviceChain", Advice[].class)[0];
    assertEquals(3, TestUtils.getPropertyValue(retry, "retryOperations.retryPolicy.maxAttempts"));
    assertEquals(
        1000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.initialInterval"));
    assertEquals(
        10000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.maxInterval"));
    assertEquals(
        2.0, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.multiplier"));
    bus.unbindConsumers("props.0");
    assertEquals(0, bindings.size());

    properties = new Properties();
    properties.put("ackMode", "NONE");
    properties.put("backOffInitialInterval", "2000");
    properties.put("backOffMaxInterval", "20000");
    properties.put("backOffMultiplier", "5.0");
    properties.put("concurrency", "2");
    properties.put("maxAttempts", "23");
    properties.put("maxConcurrency", "3");
    properties.put("prefix", "foo.");
    properties.put("prefetch", "20");
    properties.put("requestHeaderPatterns", "foo");
    properties.put("requeue", "false");
    properties.put("txSize", "10");
    properties.put("partitionIndex", 0);
    bus.bindConsumer("props.0", new DirectChannel(), properties);

    @SuppressWarnings("unchecked")
    List<Binding> bindingsNow = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
    assertEquals(1, bindingsNow.size());
    endpoint = bindingsNow.get(0).getEndpoint();
    container = verifyContainer(endpoint);

    assertEquals("foo.props.0", container.getQueueNames()[0]);

    try {
      bus.bindPubSubConsumer("dummy", null, properties);
      fail("Expected exception");
    } catch (IllegalArgumentException e) {
      assertThat(
          e.getMessage(),
          allOf(
              containsString("RabbitMessageBus does not support consumer properties: "),
              containsString("partitionIndex"),
              containsString("concurrency"),
              containsString(" for dummy.")));
    }
    try {
      bus.bindConsumer("queue:dummy", null, properties);
      fail("Expected exception");
    } catch (IllegalArgumentException e) {
      assertEquals(
          "RabbitMessageBus does not support consumer property: partitionIndex for queue:dummy.",
          e.getMessage());
    }

    bus.unbindConsumers("props.0");
    assertEquals(0, bindingsNow.size());
  }
  @Override
  protected void invokeListener(Channel channel, Message message) throws Exception {
    super.invokeListener(channel, message);
    // channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

  }
  private void doTestRetry(
      int messageCount, int txSize, int failFrequency, int concurrentConsumers, boolean stateful)
      throws Exception {

    int failedMessageCount =
        messageCount / failFrequency + (messageCount % failFrequency == 0 ? 0 : 1);

    RabbitTemplate template = createTemplate(concurrentConsumers);
    for (int i = 0; i < messageCount; i++) {
      template.convertAndSend(queue.getName(), i);
    }

    final SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(template.getConnectionFactory());
    PojoListener listener = new PojoListener(failFrequency);
    container.setMessageListener(new MessageListenerAdapter(listener));
    container.setAcknowledgeMode(AcknowledgeMode.AUTO);
    container.setChannelTransacted(true);
    container.setTxSize(txSize);
    container.setConcurrentConsumers(concurrentConsumers);

    final CountDownLatch latch = new CountDownLatch(failedMessageCount);
    container.setAdviceChain(new Advice[] {createRetryInterceptor(latch, stateful)});

    container.setQueueNames(queue.getName());
    container.afterPropertiesSet();
    container.start();

    try {

      int timeout = Math.min(1 + 2 * messageCount / concurrentConsumers, 30);

      final int count = messageCount;
      logger.debug("Waiting for messages with timeout = " + timeout + " (s)");
      Executors.newSingleThreadExecutor()
          .execute(
              () -> {
                while (container.getActiveConsumerCount() > 0) {
                  try {
                    Thread.sleep(100L);
                  } catch (InterruptedException e) {
                    latch.countDown();
                    Thread.currentThread().interrupt();
                    return;
                  }
                }
                for (int i = 0; i < count; i++) {
                  latch.countDown();
                }
              });
      boolean waited = latch.await(timeout, TimeUnit.SECONDS);
      logger.info("All messages recovered: " + waited);
      assertEquals(concurrentConsumers, container.getActiveConsumerCount());
      assertTrue("Timed out waiting for messages", waited);

      // Retried each failure 3 times (default retry policy)...
      assertEquals(3 * failedMessageCount, listener.getCount());

      // All failed messages recovered
      assertEquals(null, template.receiveAndConvert(queue.getName()));

    } finally {
      container.shutdown();
      ((DisposableBean) template.getConnectionFactory()).destroy();

      assertEquals(0, container.getActiveConsumerCount());
    }
  }