@Override
  public void bindRequestor(
      String name, MessageChannel requests, MessageChannel replies, Properties properties) {
    if (logger.isInfoEnabled()) {
      logger.info("binding requestor: " + name);
    }
    validateProducerProperties(name, properties, SUPPORTED_REQUESTING_PRODUCER_PROPERTIES);
    Assert.isInstanceOf(SubscribableChannel.class, requests);
    RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
    String queueName = applyRequests(name);
    AmqpOutboundEndpoint queue =
        this.buildOutboundEndpoint(queueName, accessor, this.rabbitTemplate);
    queue.setBeanFactory(this.getBeanFactory());

    String replyQueueName =
        accessor.getPrefix(this.defaultPrefix)
            + name
            + ".replies."
            + this.getIdGenerator().generateId();
    this.doRegisterProducer(name, requests, queue, replyQueueName, accessor);
    Queue replyQueue = new Queue(replyQueueName, false, false, true); // auto-delete
    declareQueueIfNotPresent(replyQueue);
    // register with context so it will be redeclared after a connection failure
    if (!this.autoDeclareContext.containsBean(replyQueueName)) {
      this.autoDeclareContext.getBeanFactory().registerSingleton(replyQueueName, replyQueue);
    }
    this.doRegisterConsumer(name, replies, replyQueue, accessor, false);
  }
 private RabbitTemplate determineRabbitTemplate(RabbitPropertiesAccessor properties) {
   RabbitTemplate rabbitTemplate = null;
   if (properties.isBatchingEnabled(this.defaultBatchingEnabled)) {
     BatchingStrategy batchingStrategy =
         new SimpleBatchingStrategy(
             properties.getBatchSize(this.defaultBatchSize),
             properties.geteBatchBufferLimit(this.defaultBatchBufferLimit),
             properties.getBatchTimeout(this.defaultBatchTimeout));
     rabbitTemplate =
         new BatchingRabbitTemplate(
             batchingStrategy,
             getApplicationContext()
                 .getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class));
     rabbitTemplate.setConnectionFactory(this.connectionFactory);
   }
   if (properties.isCompress(this.defaultCompress)) {
     if (rabbitTemplate == null) {
       rabbitTemplate = new RabbitTemplate(this.connectionFactory);
     }
     rabbitTemplate.setBeforePublishPostProcessors(this.compressingPostProcessor);
     rabbitTemplate.afterPropertiesSet();
   }
   if (rabbitTemplate == null) {
     rabbitTemplate = this.rabbitTemplate;
   }
   return rabbitTemplate;
 }
 private Map<String, Object> queueArgs(RabbitPropertiesAccessor accessor, String queueName) {
   Map<String, Object> args = new HashMap<>();
   if (accessor.getAutoBindDLQ(this.defaultAutoBindDLQ)) {
     args.put(
         "x-dead-letter-exchange", applyPrefix(accessor.getPrefix(this.defaultPrefix), "DLX"));
     args.put("x-dead-letter-routing-key", queueName);
   }
   return args;
 }
 private void configureOutboundHandler(
     AmqpOutboundEndpoint handler, RabbitPropertiesAccessor properties) {
   DefaultAmqpHeaderMapper mapper = new DefaultAmqpHeaderMapper();
   mapper.setRequestHeaderNames(
       properties.getRequestHeaderPattens(this.defaultRequestHeaderPatterns));
   mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns));
   handler.setHeaderMapper(mapper);
   handler.setDefaultDeliveryMode(properties.getDeliveryMode(this.defaultDefaultDeliveryMode));
   handler.setBeanFactory(this.getBeanFactory());
   handler.afterPropertiesSet();
 }
 @Override
 public void bindPubSubProducer(
     String name, MessageChannel moduleOutputChannel, Properties properties) {
   validateProducerProperties(name, properties, SUPPORTED_PUBSUB_PRODUCER_PROPERTIES);
   RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
   String exchangeName = applyPrefix(accessor.getPrefix(this.defaultPrefix), applyPubSub(name));
   declareExchangeIfNotPresent(new FanoutExchange(exchangeName));
   AmqpOutboundEndpoint fanout = new AmqpOutboundEndpoint(determineRabbitTemplate(accessor));
   fanout.setExchangeName(exchangeName);
   configureOutboundHandler(fanout, accessor);
   doRegisterProducer(name, moduleOutputChannel, fanout, accessor);
 }
 private MessageRecoverer determineRecoverer(String name, RabbitPropertiesAccessor properties) {
   if (properties.getRepublishToDLQ(this.defaultRepublishToDLQ)) {
     RabbitTemplate errorTemplate = new RabbitTemplate(this.connectionFactory);
     String prefix = properties.getPrefix(this.defaultPrefix);
     RepublishMessageRecoverer republishMessageRecoverer =
         new RepublishMessageRecoverer(
             errorTemplate, deadLetterExchangeName(prefix), applyPrefix(prefix, name));
     // TODO: Add container id to republished message headers? (Needs AMQP-489).
     return republishMessageRecoverer;
   } else {
     return new RejectAndDontRequeueRecoverer();
   }
 }
 private SendingHandler(
     MessageHandler delegate, String replyTo, RabbitPropertiesAccessor properties) {
   this.delegate = delegate;
   this.replyTo = replyTo;
   this.partitioningMetadata =
       new PartitioningMetadata(properties, properties.getNextModuleCount());
   this.setBeanFactory(RabbitMessageChannelBinder.this.getBeanFactory());
 }
 /**
  * If so requested, declare the DLX/DLQ and bind it. The DLQ is bound to the DLX with a routing
  * key of the original queue name because we use default exchange routing by queue name for the
  * original message.
  *
  * @param name The name.
  * @param properties The properties accessor.
  */
 private void autoBindDLQ(final String name, RabbitPropertiesAccessor properties) {
   if (logger.isDebugEnabled()) {
     logger.debug(
         "autoBindDLQ=" + properties.getAutoBindDLQ(this.defaultAutoBindDLQ) + " for: " + name);
   }
   if (properties.getAutoBindDLQ(this.defaultAutoBindDLQ)) {
     String prefix = properties.getPrefix(this.defaultPrefix);
     String queueName = applyPrefix(prefix, name);
     String dlqName = constructDLQName(queueName);
     Queue dlq = new Queue(dlqName);
     declareQueueIfNotPresent(dlq);
     final String dlxName = deadLetterExchangeName(prefix);
     final DirectExchange dlx = new DirectExchange(dlxName);
     declareExchangeIfNotPresent(dlx);
     this.rabbitAdmin.declareBinding(BindingBuilder.bind(dlq).to(dlx).with(queueName));
   }
 }
  @Override
  public void bindReplier(
      String name, MessageChannel requests, MessageChannel replies, Properties properties) {
    if (logger.isInfoEnabled()) {
      logger.info("binding replier: " + name);
    }
    validateConsumerProperties(name, properties, SUPPORTED_REPLYING_CONSUMER_PROPERTIES);
    RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
    Queue requestQueue =
        new Queue(applyPrefix(accessor.getPrefix(this.defaultPrefix), applyRequests(name)));
    declareQueueIfNotPresent(requestQueue);
    this.doRegisterConsumer(name, requests, requestQueue, accessor, false);

    AmqpOutboundEndpoint replyQueue = new AmqpOutboundEndpoint(rabbitTemplate);
    replyQueue.setExpressionRoutingKey(
        EXPRESSION_PARSER.parseExpression("headers['" + AmqpHeaders.REPLY_TO + "']"));
    configureOutboundHandler(replyQueue, accessor);
    doRegisterProducer(name, replies, replyQueue, accessor);
  }
 private AmqpOutboundEndpoint buildOutboundEndpoint(
     final String name, RabbitPropertiesAccessor properties, RabbitTemplate rabbitTemplate) {
   String queueName = applyPrefix(properties.getPrefix(this.defaultPrefix), name);
   String partitionKeyExtractorClass = properties.getPartitionKeyExtractorClass();
   Expression partitionKeyExpression = properties.getPartitionKeyExpression();
   AmqpOutboundEndpoint queue = new AmqpOutboundEndpoint(rabbitTemplate);
   if (partitionKeyExpression == null && !StringUtils.hasText(partitionKeyExtractorClass)) {
     declareQueueIfNotPresent(new Queue(queueName));
     queue.setRoutingKey(queueName); // uses default exchange
   } else {
     queue.setExpressionRoutingKey(
         EXPRESSION_PARSER.parseExpression(buildPartitionRoutingExpression(queueName)));
     // if the stream is partitioned, create one queue for each target partition
     for (int i = 0; i < properties.getNextModuleCount(); i++) {
       this.rabbitAdmin.declareQueue(new Queue(queueName + "-" + i));
     }
   }
   configureOutboundHandler(queue, properties);
   return queue;
 }
 @Override
 public void bindPubSubConsumer(
     String name, MessageChannel moduleInputChannel, Properties properties) {
   String exchangeName = BinderUtils.removeGroupFromPubSub(name);
   if (logger.isInfoEnabled()) {
     logger.info("declaring pubsub for inbound: " + name + ", bound to: " + exchangeName);
   }
   RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
   validateConsumerProperties(name, properties, SUPPORTED_PUBSUB_CONSUMER_PROPERTIES);
   String prefix = accessor.getPrefix(this.defaultPrefix);
   FanoutExchange exchange = new FanoutExchange(applyPrefix(prefix, applyPubSub(exchangeName)));
   declareExchangeIfNotPresent(exchange);
   Queue queue;
   boolean durable = accessor.isDurable(this.defaultDurableSubscription);
   String queueName = applyPrefix(prefix, name);
   if (durable) {
     Map<String, Object> args = queueArgs(accessor, queueName);
     queue = new Queue(queueName, true, false, false, args);
   } else {
     queue = new Queue(queueName, false, false, true);
   }
   declareQueueIfNotPresent(queue);
   org.springframework.amqp.core.Binding binding = BindingBuilder.bind(queue).to(exchange);
   this.rabbitAdmin.declareBinding(binding);
   // register with context so they will be redeclared after a connection failure
   if (!this.autoDeclareContext.containsBean(applyPubSub(name))) {
     this.autoDeclareContext.getBeanFactory().registerSingleton(applyPubSub(name), queue);
   }
   String bindingBeanName = exchange.getName() + "." + queue.getName() + ".binding";
   if (!this.autoDeclareContext.containsBean(bindingBeanName)) {
     this.autoDeclareContext.getBeanFactory().registerSingleton(bindingBeanName, binding);
   }
   doRegisterConsumer(name, moduleInputChannel, queue, accessor, true);
   if (durable) {
     autoBindDLQ(name, accessor);
   }
 }
 @Override
 public void bindConsumer(
     final String name, MessageChannel moduleInputChannel, Properties properties) {
   if (logger.isInfoEnabled()) {
     logger.info("declaring queue for inbound: " + name);
   }
   if (name.startsWith(P2P_NAMED_CHANNEL_TYPE_PREFIX)) {
     validateConsumerProperties(name, properties, SUPPORTED_NAMED_CONSUMER_PROPERTIES);
   } else {
     validateConsumerProperties(name, properties, SUPPORTED_CONSUMER_PROPERTIES);
   }
   RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
   String queueName = applyPrefix(accessor.getPrefix(this.defaultPrefix), name);
   int partitionIndex = accessor.getPartitionIndex();
   if (partitionIndex >= 0) {
     queueName += "-" + partitionIndex;
   }
   Map<String, Object> args = queueArgs(accessor, queueName);
   Queue queue = new Queue(queueName, true, false, false, args);
   declareQueueIfNotPresent(queue);
   autoBindDLQ(name, accessor);
   doRegisterConsumer(name, moduleInputChannel, queue, accessor, false);
   bindExistingProducerDirectlyIfPossible(name, moduleInputChannel);
 }
 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);
   }
 }