Binder simplification

* removed pub/sub methods from binder
* consumer group is now a parameter of the remaining bindConsumer method

* remove DynamicProducer from Binder
* Move logic to create the dynamic channel to the channel resolver.
* Return bindings from bind methods and use them for unbinding
* Suffix for dlq

Move All Rabbit Binder CleanUp to Test Bindera

More RabbitMQ Binder Test Cleanup

Clean up declarations for remaining tests.

removed BinderUtils

use Redis ZSET for consumer groups

copyright dates

AutoBindDLQ: Single DLQ Per Group When Partitioned

Configure a single DLQ for each group for all partitions.

Add DLX Exchange binding for each original queue routing key, including the partition.

Fix DLQ Binding (Producer Side)

Option was not allowed and the routing key was wrong.

Add test to verify producers can be bound before consumers.

`autoBindDLQ` must be set (or reset) on both sides for success.
This commit is contained in:
Mark Fisher
2015-12-21 15:48:48 -05:00
committed by Marius Bogoevici
parent 60e44b530d
commit c3758b9dc0
46 changed files with 1052 additions and 2758 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.stream.binder.BinderUtils;
import org.springframework.cloud.stream.binder.BindingCleaner;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.web.client.RestTemplate;
@@ -42,7 +41,9 @@ public class RabbitBindingCleaner implements BindingCleaner {
private final static Logger logger = LoggerFactory.getLogger(RabbitBindingCleaner.class);
public static final String BINDER_PREFIX = "binder.";
private static final String PREFIX_DELIMITER = ".";
public static final String BINDER_PREFIX = "binder" + PREFIX_DELIMITER;
@Override
public Map<String, List<String>> clean(String entity, boolean isJob) {
@@ -128,7 +129,7 @@ public class RabbitBindingCleaner implements BindingCleaner {
return prefix.substring(0, prefix.length() - 1);
}
else {
return prefix + BinderUtils.GROUP_INDEX_DELIMITER;
return prefix + PREFIX_DELIMITER;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,7 +62,6 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cloud.stream.binder.AbstractBindingPropertiesAccessor;
import org.springframework.cloud.stream.binder.BinderPropertyKeys;
import org.springframework.cloud.stream.binder.BinderUtils;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.cloud.stream.binder.MessageValues;
@@ -98,6 +97,7 @@ import com.rabbitmq.client.Envelope;
/**
* A {@link org.springframework.cloud.stream.binder.Binder} implementation backed by RabbitMQ.
*
* @author Mark Fisher
* @author Gary Russell
* @author Jennifer Hickey
@@ -150,40 +150,16 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
.addAll(RABBIT_CONSUMER_PROPERTIES)
.build();
private static final Set<Object> SUPPORTED_PUBSUB_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BinderPropertyKeys.DURABLE)
.build();
/**
* Basic + concurrency.
*/
private static final Set<Object> SUPPORTED_NAMED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BinderPropertyKeys.CONCURRENCY)
.build();
/**
* Basic + concurrency + partitioning.
* Basic + durable + concurrency + partitioning.
*/
private static final Set<Object> SUPPORTED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BinderPropertyKeys.DURABLE)
.add(BinderPropertyKeys.CONCURRENCY)
.add(BinderPropertyKeys.PARTITION_INDEX)
.build();
/**
* Basic + concurrency + reply headers + delivery mode (reply).
*/
private static final Set<Object> SUPPORTED_REPLYING_CONSUMER_PROPERTIES = new SetBuilder()
// request
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BinderPropertyKeys.CONCURRENCY)
// reply
.add(RabbitPropertiesAccessor.REPLY_HEADER_PATTERNS)
.add(RabbitPropertiesAccessor.DELIVERY_MODE)
.build();
/**
* Rabbit producer properties.
*/
@@ -195,39 +171,15 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
.add(BinderPropertyKeys.COMPRESS)
.build();
private static final Set<Object> SUPPORTED_PUBSUB_PRODUCER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_PRODUCER_PROPERTIES)
.addAll(PRODUCER_BATCHING_BASIC_PROPERTIES)
.addAll(PRODUCER_BATCHING_ADVANCED_PROPERTIES)
.build();
private static final Set<Object> SUPPORTED_NAMED_PRODUCER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_PRODUCER_PROPERTIES)
.addAll(PRODUCER_BATCHING_BASIC_PROPERTIES)
.addAll(PRODUCER_BATCHING_ADVANCED_PROPERTIES)
.build();
/**
* Partitioning + rabbit producer properties.
*/
private static final Set<Object> SUPPORTED_PRODUCER_PROPERTIES = new SetBuilder()
.addAll(PRODUCER_PARTITIONING_PROPERTIES)
.addAll(SUPPORTED_BASIC_PRODUCER_PROPERTIES)
.add(BinderPropertyKeys.DIRECT_BINDING_ALLOWED)
.addAll(PRODUCER_BATCHING_BASIC_PROPERTIES)
.addAll(PRODUCER_BATCHING_ADVANCED_PROPERTIES)
.build();
/**
* Basic producer + basic consumer + concurrency + reply headers.
*/
private static final Set<Object> SUPPORTED_REQUESTING_PRODUCER_PROPERTIES = new SetBuilder()
// request
.addAll(SUPPORTED_BASIC_PRODUCER_PROPERTIES)
// reply
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BinderPropertyKeys.CONCURRENCY)
.add(RabbitPropertiesAccessor.REPLY_HEADER_PATTERNS)
.add(RabbitPropertiesAccessor.AUTO_BIND_DLQ)
.build();
private static final MessagePropertiesConverter inboundMessagePropertiesConverter =
@@ -436,51 +388,27 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
}
@Override
public void bindConsumer(final String name, MessageChannel moduleInputChannel, Properties properties) {
public Binding<MessageChannel> doBindConsumer(String name, String group, MessageChannel inputChannel, Properties properties) {
String baseQueueName = groupedName(name, group);
if (this.logger.isInfoEnabled()) {
this.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);
this.logger.info("declaring queue for inbound: " + baseQueueName + ", bound to: " + name);
}
RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
String queueName = applyPrefix(accessor.getPrefix(this.defaultPrefix), name);
TopicExchange exchange = new TopicExchange(queueName);
declareExchange(queueName, exchange);
validateConsumerProperties(baseQueueName, properties, SUPPORTED_CONSUMER_PROPERTIES);
String prefix = accessor.getPrefix(this.defaultPrefix);
String exchangeName = applyPrefix(prefix, name);
TopicExchange exchange = new TopicExchange(exchangeName);
declareExchange(exchangeName, exchange);
String queueName = applyPrefix(prefix, baseQueueName);
int partitionIndex = accessor.getPartitionIndex();
String dlqNameRoot = name;
if (partitionIndex >= 0) {
String partitionSuffix = "-" + partitionIndex;
queueName += partitionSuffix;
dlqNameRoot += partitionSuffix;
}
Queue queue = new Queue(queueName, true, false, false, queueArgs(accessor, queueName));
declareQueue(queueName, queue);
autoBindDLQ(dlqNameRoot, accessor);
org.springframework.amqp.core.Binding binding = BindingBuilder.bind(queue).to(exchange).with(queueName);
declareBinding(queueName, binding);
doRegisterConsumer(name, moduleInputChannel, queue, accessor, false);
bindExistingProducerDirectlyIfPossible(name, moduleInputChannel);
}
@Override
public void bindPubSubConsumer(String exchangeName, MessageChannel moduleInputChannel, String group,
Properties properties) {
String name = BinderUtils.groupedName(exchangeName, group);
if (this.logger.isInfoEnabled()) {
this.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);
TopicExchange exchange = new TopicExchange(applyPrefix(prefix, exchangeName));
declareExchange(exchange.getName(), exchange);
Queue queue;
boolean durable = accessor.isDurable(this.defaultDurableSubscription);
String queueName = applyPrefix(prefix, name);
if (durable) {
queue = new Queue(queueName, true, false, false, queueArgs(accessor, queueName));
}
@@ -488,11 +416,18 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
queue = new Queue(queueName, false, false, true);
}
declareQueue(queueName, queue);
declareBinding(queue.getName(), BindingBuilder.bind(queue).to(exchange).with("#"));
doRegisterConsumer(name, moduleInputChannel, queue, accessor, true);
if (durable) {
autoBindDLQ(name, accessor);
if (partitionIndex >= 0) {
String bindingKey = String.format("%s-%d", name, partitionIndex);
declareBinding(queue.getName(), BindingBuilder.bind(queue).to(exchange).with(bindingKey));
}
else {
declareBinding(queue.getName(), BindingBuilder.bind(queue).to(exchange).with("#"));
}
Binding<MessageChannel> binding = doRegisterConsumer(baseQueueName, group, inputChannel, queue, accessor);
if (durable) {
autoBindDLQ(applyPrefix(prefix, baseQueueName), queueName, accessor);
}
return binding;
}
private Map<String, Object> queueArgs(RabbitPropertiesAccessor accessor, String queueName) {
@@ -504,8 +439,9 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
return args;
}
private void doRegisterConsumer(String name, MessageChannel moduleInputChannel, Queue queue,
RabbitPropertiesAccessor properties, boolean isPubSub) {
private Binding<MessageChannel> doRegisterConsumer(String name, String group, MessageChannel moduleInputChannel, Queue queue,
RabbitPropertiesAccessor properties) {
Binding<MessageChannel> consumerBinding = null;
// Fix for XD-2503
// Temporarily overrides the thread context classloader with the one where the SimpleMessageListenerContainer
// is defined
@@ -520,15 +456,15 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
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);
}
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() + "-"));
@@ -559,7 +495,7 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns));
adapter.setHeaderMapper(mapper);
adapter.afterPropertiesSet();
Binding consumerBinding = Binding.forConsumer(name, adapter, moduleInputChannel, properties);
consumerBinding = Binding.forConsumer(name, group, adapter, moduleInputChannel, properties);
addBinding(consumerBinding);
ReceivingHandler convertingBridge = new ReceivingHandler();
convertingBridge.setOutputChannel(moduleInputChannel);
@@ -571,6 +507,7 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
finally {
Thread.currentThread().setContextClassLoader(originalClassloader);
}
return consumerBinding;
}
private MessageRecoverer determineRecoverer(String name, RabbitPropertiesAccessor properties) {
@@ -587,54 +524,36 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
}
}
@Override
public void bindProducer(final String name, MessageChannel moduleOutputChannel,
Properties properties) {
Assert.isInstanceOf(SubscribableChannel.class, moduleOutputChannel);
RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
if (name.startsWith(P2P_NAMED_CHANNEL_TYPE_PREFIX)) {
validateProducerProperties(name, properties, SUPPORTED_NAMED_PRODUCER_PROPERTIES);
}
else {
validateProducerProperties(name, properties, SUPPORTED_PRODUCER_PROPERTIES);
}
if (!bindNewProducerDirectlyIfPossible(name, (SubscribableChannel) moduleOutputChannel, accessor)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("declaring queue for outbound: " + name);
}
AmqpOutboundEndpoint queue = this.buildOutboundEndpoint(name, accessor, determineRabbitTemplate(accessor));
doRegisterProducer(name, moduleOutputChannel, queue, accessor);
}
}
private AmqpOutboundEndpoint buildOutboundEndpoint(final String name, RabbitPropertiesAccessor properties,
RabbitTemplate rabbitTemplate) {
String prefix = properties.getPrefix(this.defaultPrefix);
String queueName = applyPrefix(prefix, name);
String exchangeName = applyPrefix(prefix, name);
String partitionKeyExtractorClass = properties.getPartitionKeyExtractorClass();
Expression partitionKeyExpression = properties.getPartitionKeyExpression();
TopicExchange exchange = new TopicExchange(queueName);
declareExchange(queueName, exchange);
TopicExchange exchange = new TopicExchange(exchangeName);
declareExchange(exchangeName, exchange);
AmqpOutboundEndpoint endpoint = new AmqpOutboundEndpoint(rabbitTemplate);
endpoint.setExchangeName(exchange.getName());
String baseQueueName = exchangeName + ".default";
if (partitionKeyExpression == null && !StringUtils.hasText(partitionKeyExtractorClass)) {
Queue queue = new Queue(queueName, true, false, false, queueArgs(properties, queueName));
declareQueue(name, queue);
autoBindDLQ(name, properties);
endpoint.setRoutingKey(queueName);
org.springframework.amqp.core.Binding binding = BindingBuilder.bind(queue).to(exchange).with(queueName);
declareBinding(queueName, binding);
Queue queue = new Queue(baseQueueName, true, false, false, queueArgs(properties, baseQueueName));
declareQueue(baseQueueName, queue);
autoBindDLQ(baseQueueName, baseQueueName, properties);
endpoint.setRoutingKey(name);
org.springframework.amqp.core.Binding binding = BindingBuilder.bind(queue).to(exchange).with(name);
declareBinding(baseQueueName, binding);
}
else {
endpoint.setExpressionRoutingKey(EXPRESSION_PARSER.parseExpression(buildPartitionRoutingExpression
(queueName)));
// if the stream is partitioned, create one queue for each target partition
endpoint.setExpressionRoutingKey(EXPRESSION_PARSER.parseExpression(buildPartitionRoutingExpression(name)));
// if the stream is partitioned, create one queue for each target partition for the default group
for (int i = 0; i < properties.getNextModuleCount(); i++) {
String partitionSuffix = "-" + i;
Queue queue = new Queue(queueName + partitionSuffix, true, false, false, queueArgs(properties, queueName));
String partitionQueueName = baseQueueName + partitionSuffix;
Queue queue = new Queue(partitionQueueName, true, false, false,
queueArgs(properties, partitionQueueName));
declareQueue(queue.getName(), queue);
autoBindDLQ(name + partitionSuffix, properties);
declareBinding(queue.getName(), BindingBuilder.bind(queue).to(exchange).with(queue.getName()));
autoBindDLQ(baseQueueName, baseQueueName + partitionSuffix, properties);
declareBinding(queue.getName(), BindingBuilder.bind(queue).to(exchange).with(name + partitionSuffix));
}
}
configureOutboundHandler(endpoint, properties);
@@ -652,18 +571,14 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
}
@Override
public void bindPubSubProducer(String name, MessageChannel moduleOutputChannel,
Properties properties) {
validateProducerProperties(name, properties, SUPPORTED_PUBSUB_PRODUCER_PROPERTIES);
public Binding<MessageChannel> bindProducer(String name, MessageChannel outputChannel, Properties properties) {
validateProducerProperties(name, properties, SUPPORTED_PRODUCER_PROPERTIES);
RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties);
String exchangeName = applyPrefix(accessor.getPrefix(this.defaultPrefix), name);
TopicExchange exchange = new TopicExchange(exchangeName);
declareExchange(exchangeName, exchange);
AmqpOutboundEndpoint endpoint = new AmqpOutboundEndpoint(determineRabbitTemplate(accessor));
endpoint.setExchangeName(exchangeName);
endpoint.setRoutingKey(name);
configureOutboundHandler(endpoint, accessor);
doRegisterProducer(name, moduleOutputChannel, endpoint, accessor);
AmqpOutboundEndpoint endpoint = this.buildOutboundEndpoint(name, accessor, determineRabbitTemplate(accessor));
return doRegisterProducer(name, outputChannel, endpoint, accessor);
}
private RabbitTemplate determineRabbitTemplate(RabbitPropertiesAccessor properties) {
@@ -691,12 +606,12 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
return rabbitTemplate;
}
private void doRegisterProducer(final String name, MessageChannel moduleOutputChannel,
private Binding<MessageChannel> doRegisterProducer(final String name, MessageChannel moduleOutputChannel,
AmqpOutboundEndpoint delegate, RabbitPropertiesAccessor properties) {
this.doRegisterProducer(name, moduleOutputChannel, delegate, null, properties);
return this.doRegisterProducer(name, moduleOutputChannel, delegate, null, properties);
}
private void doRegisterProducer(final String name, MessageChannel moduleOutputChannel,
private Binding<MessageChannel> doRegisterProducer(final String name, MessageChannel moduleOutputChannel,
AmqpOutboundEndpoint delegate, String replyTo, RabbitPropertiesAccessor properties) {
Assert.isInstanceOf(SubscribableChannel.class, moduleOutputChannel);
MessageHandler handler = new SendingHandler(delegate, replyTo, properties);
@@ -704,72 +619,33 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
consumer.setBeanFactory(getBeanFactory());
consumer.setBeanName("outbound." + name);
consumer.afterPropertiesSet();
Binding producerBinding = Binding.forProducer(name, moduleOutputChannel, consumer, properties);
Binding<MessageChannel> producerBinding = Binding.forProducer(name, moduleOutputChannel, consumer, properties);
addBinding(producerBinding);
producerBinding.start();
}
@Override
public void bindRequestor(String name, MessageChannel requests, MessageChannel replies,
Properties properties) {
if (this.logger.isInfoEnabled()) {
this.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
declareQueue(replyQueueName, replyQueue);
this.doRegisterConsumer(name, replies, replyQueue, accessor, false);
}
@Override
public void bindReplier(String name, MessageChannel requests, MessageChannel replies,
Properties properties) {
if (this.logger.isInfoEnabled()) {
this.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)));
declareQueue(requestQueue.getName(), requestQueue);
this.doRegisterConsumer(name, requests, requestQueue, accessor, false);
AmqpOutboundEndpoint replyQueue = new AmqpOutboundEndpoint(this.rabbitTemplate);
replyQueue.setExpressionRoutingKey(EXPRESSION_PARSER.parseExpression("headers['" + AmqpHeaders.REPLY_TO +
"']"));
configureOutboundHandler(replyQueue, accessor);
doRegisterProducer(name, replies, replyQueue, accessor);
return producerBinding;
}
/**
* 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 queueName The base name for the queue (including the binder prefix, if any).
* @param routingKey The routing key for the queue.
* @param properties The properties accessor.
*/
private void autoBindDLQ(final String name, RabbitPropertiesAccessor properties) {
private void autoBindDLQ(final String queueName, String routingKey, RabbitPropertiesAccessor properties) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("autoBindDLQ=" + properties.getAutoBindDLQ(this.defaultAutoBindDLQ)
+ " for: " + name);
+ " for: " + queueName);
}
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);
declareQueue(dlqName, dlq);
final String dlxName = deadLetterExchangeName(prefix);
final DirectExchange dlx = new DirectExchange(dlxName);
declareExchange(dlxName, dlx);
declareBinding(dlqName, BindingBuilder.bind(dlq).to(dlx).with(queueName));
declareBinding(dlqName, BindingBuilder.bind(dlq).to(dlx).with(routingKey));
}
}
@@ -814,21 +690,10 @@ public class RabbitMessageChannelBinder extends MessageChannelBinderSupport impl
}
@Override
public void unbindConsumer(String name, MessageChannel channel) {
super.unbindConsumer(name, channel);
cleanAutoDeclareContext(name);
}
@Override
public void unbindConsumers(String name) {
super.unbindConsumers(name);
cleanAutoDeclareContext(name);
}
@Override
public void unbindPubSubConsumers(String name, String group) {
super.unbindPubSubConsumers(name, group);
cleanAutoDeclareContext(BinderUtils.groupedName(name, group));
protected void afterUnbind(Binding<MessageChannel> binding) {
if (Binding.Type.consumer.equals(binding.getType())) {
cleanAutoDeclareContext(groupedName(binding.getName(), binding.getGroup()));
}
}
private void addToAutoDeclareContext(String name, Object bean) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ public class LocalizedQueueConnectionFactoryIntegrationTests {
@Before
public void setup() {
ConnectionFactory defaultConnectionFactory = new CachingConnectionFactory("localhost");
ConnectionFactory defaultConnectionFactory = rabbitAvailableRule.getResource();
String[] addresses = new String[] { "localhost:9999", "localhost:5672" };
String[] adminAddresses = new String[] { "http://localhost:15672", "http://localhost:15672" };
String[] nodes = new String[] { "foo@bar", "rabbit@localhost" };
@@ -66,6 +66,8 @@ public class LocalizedQueueConnectionFactoryIntegrationTests {
RabbitTemplate template = new RabbitTemplate(targetConnectionFactory);
template.convertAndSend("", queue.getName(), "foo");
assertEquals("foo", template.receiveAndConvert(queue.getName()));
((CachingConnectionFactory) targetConnectionFactory).destroy();
admin.deleteQueue(queue.getName());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -69,8 +69,8 @@ public class RabbitBinderCleanerTests {
CachingConnectionFactory connectionFactory = rabbitWithMgmtEnabled.getResource();
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
for (int i = 0; i < 5; i++) {
String queue1Name = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, stream1 + "." + i);
String queue2Name = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, stream2 + "." + i);
String queue1Name = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, stream1 + ".default." + i);
String queue2Name = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, stream2 + ".default." + i);
if (firstQueue == null) {
firstQueue = queue1Name;
}
@@ -110,7 +110,7 @@ public class RabbitBinderCleanerTests {
@Override
public Void doInRabbit(Channel channel) throws Exception {
String queueName = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, stream1 + "." + 4);
String queueName = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, stream1 + ".default." + 4);
String consumerTag = channel.basicConsume(queueName, new DefaultConsumer(channel));
try {
waitForConsumerStateNot(queueName, 0);
@@ -160,8 +160,8 @@ public class RabbitBinderCleanerTests {
// should *not* clean stream2
assertEquals(10, cleanedQueues.size());
for (int i = 0; i < 5; i++) {
assertEquals(BINDER_PREFIX + stream1 + "." + i, cleanedQueues.get(i * 2));
assertEquals(BINDER_PREFIX + stream1 + "." + i + ".dlq", cleanedQueues.get(i * 2 + 1));
assertEquals(BINDER_PREFIX + stream1 + ".default." + i, cleanedQueues.get(i * 2));
assertEquals(BINDER_PREFIX + stream1 + ".default." + i + ".dlq", cleanedQueues.get(i * 2 + 1));
}
List<String> cleanedExchanges = cleanedMap.get("exchanges");
assertEquals(6, cleanedExchanges.size());
@@ -172,7 +172,7 @@ public class RabbitBinderCleanerTests {
cleanedQueues = cleanedMap.get("queues");
assertEquals(5, cleanedQueues.size());
for (int i = 0; i < 5; i++) {
assertEquals(BINDER_PREFIX + stream2 + "." + i, cleanedQueues.get(i));
assertEquals(BINDER_PREFIX + stream2 + ".default." + i, cleanedQueues.get(i));
}
cleanedExchanges = cleanedMap.get("exchanges");
assertEquals(6, cleanedExchanges.size());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
package org.springframework.cloud.stream.binder.rabbit;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.startsWith;
@@ -26,8 +25,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -58,14 +55,13 @@ import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.amqp.support.postprocessor.DelegatingDecompressingPostProcessor;
import org.springframework.amqp.utils.test.TestUtils;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.cloud.stream.binder.AbstractTestBinder;
import org.springframework.cloud.stream.binder.Binder;
import org.springframework.cloud.stream.binder.BinderPropertyKeys;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.PartitionCapableBinderTests;
import org.springframework.cloud.stream.binder.Spy;
import org.springframework.cloud.stream.test.junit.rabbit.RabbitTestSupport;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -110,8 +106,8 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
Binder<MessageChannel> binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
DirectChannel moduleInputChannel = new DirectChannel();
binder.bindProducer("bad.0", moduleOutputChannel, null);
binder.bindConsumer("bad.0", moduleInputChannel, null);
Binding<MessageChannel> producerBinding = binder.bindProducer("bad.0", moduleOutputChannel, null);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("bad.0", "test", moduleInputChannel, null);
Message<?> message = MessageBuilder.withPayload("bad").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
final CountDownLatch latch = new CountDownLatch(3);
@@ -125,8 +121,8 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
});
moduleOutputChannel.send(message);
assertTrue(latch.await(10, TimeUnit.SECONDS));
binder.unbindConsumers("bad.0");
binder.unbindProducers("bad.0");
binder.unbind(consumerBinding);
binder.unbind(producerBinding);
}
@Test
@@ -134,15 +130,15 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
Binder<MessageChannel> binder = getBinder();
Properties properties = new Properties();
properties.put("transacted", "true"); // test transacted with defaults; not allowed with ackmode NONE
binder.bindConsumer("props.0", new DirectChannel(), properties);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("props.0", null, new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
List<Binding<MessageChannel>> bindings = TestUtils.getPropertyValue(binder, "binder.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(RabbitMessageChannelBinder.DEFAULT_RABBIT_PREFIX + "props.0", container.getQueueNames()[0]);
assertEquals(RabbitMessageChannelBinder.DEFAULT_RABBIT_PREFIX + "props.0.default", container.getQueueNames()[0]);
assertTrue(TestUtils.getPropertyValue(container, "transactional", Boolean.class));
assertEquals(1, TestUtils.getPropertyValue(container, "concurrentConsumers"));
assertNull(TestUtils.getPropertyValue(container, "maxConcurrentConsumers"));
@@ -154,7 +150,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
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"));
binder.unbindConsumers("props.0");
binder.unbind(consumerBinding);
assertEquals(0, bindings.size());
properties = new Properties();
@@ -171,46 +167,26 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
properties.put("requeue", "false");
properties.put("txSize", "10");
properties.put("partitionIndex", 0);
binder.bindConsumer("props.0", new DirectChannel(), properties);
consumerBinding = binder.bindConsumer("props.0", "test", new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindingsNow = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
List<Binding<MessageChannel>> bindingsNow = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindingsNow.size());
endpoint = bindingsNow.get(0).getEndpoint();
container = verifyContainer(endpoint);
assertEquals("foo.props.0", container.getQueueNames()[0]);
assertEquals("foo.props.0.test", container.getQueueNames()[0]);
try {
binder.bindPubSubConsumer("dummy", null, null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString(getClassUnderTestName() + " does not support consumer properties: "),
containsString("partitionIndex"),
containsString("concurrency"),
containsString(" for dummy.")));
}
try {
binder.bindConsumer("queue:dummy", null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertEquals(getClassUnderTestName() + " does not support consumer property: partitionIndex for queue:dummy.",
e.getMessage());
}
binder.unbindConsumers("props.0");
binder.unbind(consumerBinding);
assertEquals(0, bindingsNow.size());
}
@Test
public void testProducerProperties() throws Exception {
Binder<MessageChannel> binder = getBinder();
binder.bindProducer("props.0", new DirectChannel(), null);
Binding<MessageChannel> producerBinding = binder.bindProducer("props.0", new DirectChannel(), null);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
List<Binding<MessageChannel>> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
MessageDeliveryMode mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
@@ -219,7 +195,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
List<?> requestHeaders = TestUtils.getPropertyValue(endpoint,
"handler.delegate.headerMapper.requestHeaderMatcher.strategies", List.class);
assertEquals(2, requestHeaders.size());
binder.unbindProducers("props.0");
binder.unbind(producerBinding);
assertEquals(0, bindings.size());
Properties properties = new Properties();
@@ -232,11 +208,11 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
properties.put("partitionSelectorClass", "foo");
properties.put(BinderPropertyKeys.NEXT_MODULE_COUNT, "1");
binder.bindProducer("props.0", new DirectChannel(), properties);
producerBinding = binder.bindProducer("props.0", new DirectChannel(), properties);
assertEquals(1, bindings.size());
endpoint = bindings.get(0).getEndpoint();
assertEquals(
"'foo.props.0-' + headers['partition']",
"'props.0-' + headers['partition']",
TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression",
SpelExpression.class).getExpressionString());
mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
@@ -244,167 +220,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
assertEquals(MessageDeliveryMode.NON_PERSISTENT, mode);
verifyFooRequestProducer(endpoint);
try {
binder.bindPubSubProducer("dummy", new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
containsString("partitionSelectorClass")));
assertThat(e.getMessage(), containsString("for dummy."));
}
try {
binder.bindProducer("queue:dummy", new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
containsString("partitionSelectorClass")));
assertThat(e.getMessage(), containsString("for queue:dummy."));
}
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testRequestReplyRequestorProperties() throws Exception {
Binder<MessageChannel> binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "foo.");
properties.put("deliveryMode", "NON_PERSISTENT");
properties.put("requestHeaderPatterns", "foo");
properties.put("replyHeaderPatterns", "bar");
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("requeue", "false");
properties.put("txSize", "10");
binder.bindRequestor("props.0", new DirectChannel(), new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(2, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint(); // producer
MessageDeliveryMode mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
MessageDeliveryMode.class);
assertEquals(MessageDeliveryMode.NON_PERSISTENT, mode);
verifyFooRequestBarReplyProducer(endpoint);
endpoint = bindings.get(1).getEndpoint(); // consumer
verifyContainer(endpoint);
verifyBarReplyConsumer(endpoint);
properties.put("partitionKeyExpression", "'foo'");
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BinderPropertyKeys.NEXT_MODULE_COUNT, "1");
properties.put("partitionIndex", "0");
try {
binder.bindRequestor("dummy", null, null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
containsString("partitionSelectorClass")));
assertThat(e.getMessage(), allOf(containsString("partitionIndex"), containsString("for dummy.")));
}
binder.unbindConsumers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testRequestReplyReplierProperties() throws Exception {
Binder<MessageChannel> binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "foo.");
properties.put("deliveryMode", "NON_PERSISTENT");
properties.put("requestHeaderPatterns", "foo");
properties.put("replyHeaderPatterns", "bar");
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("requeue", "false");
properties.put("txSize", "10");
binder.bindReplier("props.0", new DirectChannel(), new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(2, bindings.size());
AbstractEndpoint endpoint = bindings.get(1).getEndpoint(); // producer
assertEquals(
"headers['amqp_replyTo']",
TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression",
SpelExpression.class).getExpressionString());
MessageDeliveryMode mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
MessageDeliveryMode.class);
assertEquals(MessageDeliveryMode.NON_PERSISTENT, mode);
verifyFooRequestBarReplyProducer(endpoint);
endpoint = bindings.get(0).getEndpoint(); // consumer
verifyContainer(endpoint);
verifyBarReplyConsumer(endpoint);
properties.put("partitionKeyExpression", "'foo'");
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BinderPropertyKeys.NEXT_MODULE_COUNT, "1");
properties.put("partitionIndex", "0");
try {
binder.bindReplier("dummy", null, null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString(getClassUnderTestName() + " does not support consumer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
containsString("partitionSelectorClass")));
assertThat(e.getMessage(), allOf(containsString("partitionIndex"), containsString("for dummy.")));
}
binder.unbindConsumers("props.0");
binder.unbindProducers("props.0");
binder.unbind(producerBinding);
assertEquals(0, bindings.size());
}
@@ -430,14 +246,14 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
});
binder.bindPubSubConsumer("durabletest.0", moduleInputChannel, "tgroup", properties);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("durabletest.0", "tgroup", moduleInputChannel, properties);
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.convertAndSend(TEST_PREFIX + "durabletest.0", "", "foo");
int n = 0;
while (n++ < 100) {
Object deadLetter = template.receiveAndConvert(TEST_PREFIX + "tgroup.durabletest.0.dlq");
Object deadLetter = template.receiveAndConvert(TEST_PREFIX + "durabletest.0.tgroup.dlq");
if (deadLetter != null) {
assertEquals("foo", deadLetter);
break;
@@ -446,13 +262,8 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
assertTrue(n < 100);
binder.unbindConsumer("durabletest.0", moduleInputChannel);
binder.unbindPubSubConsumers("durabletest.0", "tgroup");
assertNotNull(admin.getQueueProperties(TEST_PREFIX + "tgroup.durabletest.0.dlq"));
admin.deleteQueue(TEST_PREFIX + "tgroup.durabletest.0.dlq");
admin.deleteQueue(TEST_PREFIX + "tgroup.durabletest.0");
admin.deleteExchange(TEST_PREFIX + "durabletest.0");
admin.deleteExchange(TEST_PREFIX + "DLX");
binder.unbind(consumerBinding);
assertNotNull(admin.getQueueProperties(TEST_PREFIX + "durabletest.0.tgroup.dlq"));
}
@Test
@@ -476,18 +287,14 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
});
binder.bindPubSubConsumer("nondurabletest.0", moduleInputChannel, "tgroup", properties);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("nondurabletest.0", "tgroup", moduleInputChannel, properties);
binder.unbindPubSubConsumers("nondurabletest.0", "tgroup");
binder.unbind(consumerBinding);
assertNull(admin.getQueueProperties(TEST_PREFIX + "nondurabletest.0.dlq"));
admin.deleteQueue(TEST_PREFIX + "tgroup.nondurabletest.0");
admin.deleteExchange(TEST_PREFIX + "nondurabletest.0");
}
@Test
public void testAutoBindDLQ() throws Exception {
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
Binder<MessageChannel> binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", TEST_PREFIX);
@@ -504,14 +311,14 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
});
binder.bindConsumer("dlqtest", moduleInputChannel, properties);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("dlqtest", null, moduleInputChannel, properties);
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.convertAndSend("", TEST_PREFIX + "dlqtest", "foo");
template.convertAndSend("", TEST_PREFIX + "dlqtest.default", "foo");
int n = 0;
while (n++ < 100) {
Object deadLetter = template.receiveAndConvert(TEST_PREFIX + "dlqtest.dlq");
Object deadLetter = template.receiveAndConvert(TEST_PREFIX + "dlqtest.default.dlq");
if (deadLetter != null) {
assertEquals("foo", deadLetter);
break;
@@ -520,10 +327,176 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
assertTrue(n < 100);
binder.unbindConsumer("dlqtest", moduleInputChannel);
admin.deleteQueue(TEST_PREFIX + "dlqtest.dlq");
admin.deleteQueue(TEST_PREFIX + "dlqtest");
admin.deleteExchange(TEST_PREFIX + "DLX");
binder.unbind(consumerBinding);
}
@Test
public void testAutoBindDLQPartionedConsumerFirst() throws Exception {
Binder<MessageChannel> binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "bindertest.");
properties.put("autoBindDLQ", "true");
properties.put("maxAttempts", "1"); // disable retry
properties.put("requeue", "false");
properties.put("partitionIndex", "0");
DirectChannel input0 = new DirectChannel();
input0.setBeanName("test.input0DLQ");
Binding<MessageChannel> input0Binding = binder.bindConsumer("partDLQ.0", "dlqPartGrp", input0, properties);
Binding<MessageChannel> defaultConsumerBinding1 = binder.bindConsumer("partDLQ.0", null, new QueueChannel(), properties);
properties.put("partitionIndex", "1");
DirectChannel input1 = new DirectChannel();
input1.setBeanName("test.input1DLQ");
Binding<MessageChannel> input1Binding = binder.bindConsumer("partDLQ.0", "dlqPartGrp", input1, properties);
Binding<MessageChannel> defaultConsumerBinding2 = binder.bindConsumer("partDLQ.0", null, new QueueChannel(), properties);
properties.clear();
properties.put("prefix", "bindertest.");
properties.put("autoBindDLQ", "true");
properties.put("partitionKeyExtractorClass", "org.springframework.cloud.stream.binder.PartitionTestSupport");
properties.put("partitionSelectorClass", "org.springframework.cloud.stream.binder.PartitionTestSupport");
properties.put(BinderPropertyKeys.NEXT_MODULE_COUNT, "2");
DirectChannel output = new DirectChannel();
output.setBeanName("test.output");
Binding<MessageChannel> outputBinding = binder.bindProducer("partDLQ.0", output, properties);
final CountDownLatch latch0 = new CountDownLatch(1);
input0.subscribe(new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
if (latch0.getCount() <= 0) {
throw new RuntimeException("dlq");
}
latch0.countDown();
}
});
final CountDownLatch latch1 = new CountDownLatch(1);
input1.subscribe(new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
if (latch1.getCount() <= 0) {
throw new RuntimeException("dlq");
}
latch1.countDown();
}
});
output.send(new GenericMessage<Integer>(1));
assertTrue(latch1.await(10, TimeUnit.SECONDS));
output.send(new GenericMessage<Integer>(0));
assertTrue(latch0.await(10, TimeUnit.SECONDS));
output.send(new GenericMessage<Integer>(1));
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.setReceiveTimeout(10000);
String streamDLQName = "bindertest.partDLQ.0.dlqPartGrp.dlq";
org.springframework.amqp.core.Message received = template.receive(streamDLQName);
assertNotNull(received);
assertEquals(1, received.getMessageProperties().getHeaders().get("partition"));
output.send(new GenericMessage<Integer>(0));
received = template.receive(streamDLQName);
assertNotNull(received);
assertEquals(0, received.getMessageProperties().getHeaders().get("partition"));
binder.unbind(input0Binding);
binder.unbind(input1Binding);
binder.unbind(defaultConsumerBinding1);
binder.unbind(defaultConsumerBinding2);
binder.unbind(outputBinding);
}
@Test
public void testAutoBindDLQPartionedProducerFirst() throws Exception {
Binder<MessageChannel> binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "bindertest.");
properties.put("autoBindDLQ", "true");
properties.put("partitionKeyExtractorClass", "org.springframework.cloud.stream.binder.PartitionTestSupport");
properties.put("partitionSelectorClass", "org.springframework.cloud.stream.binder.PartitionTestSupport");
properties.put(BinderPropertyKeys.NEXT_MODULE_COUNT, "2");
DirectChannel output = new DirectChannel();
output.setBeanName("test.output");
Binding<MessageChannel> outputBinding = binder.bindProducer("partDLQ.1", output, properties);
properties.clear();
properties.put("prefix", "bindertest.");
properties.put("autoBindDLQ", "true");
properties.put("maxAttempts", "1"); // disable retry
properties.put("requeue", "false");
properties.put("partitionIndex", "0");
DirectChannel input0 = new DirectChannel();
input0.setBeanName("test.input0DLQ");
Binding<MessageChannel> input0Binding = binder.bindConsumer("partDLQ.1", "dlqPartGrp", input0, properties);
Binding<MessageChannel> defaultConsumerBinding1 = binder.bindConsumer("partDLQ.1", null, new QueueChannel(), properties);
properties.put("partitionIndex", "1");
DirectChannel input1 = new DirectChannel();
input1.setBeanName("test.input1DLQ");
Binding<MessageChannel> input1Binding = binder.bindConsumer("partDLQ.1", "dlqPartGrp", input1, properties);
Binding<MessageChannel> defaultConsumerBinding2 = binder.bindConsumer("partDLQ.1", null, new QueueChannel(), properties);
final CountDownLatch latch0 = new CountDownLatch(1);
input0.subscribe(new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
if (latch0.getCount() <= 0) {
throw new RuntimeException("dlq");
}
latch0.countDown();
}
});
final CountDownLatch latch1 = new CountDownLatch(1);
input1.subscribe(new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
if (latch1.getCount() <= 0) {
throw new RuntimeException("dlq");
}
latch1.countDown();
}
});
output.send(new GenericMessage<Integer>(1));
assertTrue(latch1.await(10, TimeUnit.SECONDS));
output.send(new GenericMessage<Integer>(0));
assertTrue(latch0.await(10, TimeUnit.SECONDS));
output.send(new GenericMessage<Integer>(1));
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.setReceiveTimeout(10000);
String streamDLQName = "bindertest.partDLQ.1.dlqPartGrp.dlq";
org.springframework.amqp.core.Message received = template.receive(streamDLQName);
assertNotNull(received);
assertEquals(1, received.getMessageProperties().getHeaders().get("partition"));
output.send(new GenericMessage<Integer>(0));
received = template.receive(streamDLQName);
assertNotNull(received);
assertEquals(0, received.getMessageProperties().getHeaders().get("partition"));
binder.unbind(input0Binding);
binder.unbind(input1Binding);
binder.unbind(defaultConsumerBinding1);
binder.unbind(defaultConsumerBinding2);
binder.unbind(outputBinding);
}
@Test
@@ -532,8 +505,8 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", TEST_PREFIX + "DLX");
args.put("x-dead-letter-routing-key", TEST_PREFIX + "dlqpubtest");
Queue queue = new Queue(TEST_PREFIX + "dlqpubtest", true, false, false, args);
args.put("x-dead-letter-routing-key", TEST_PREFIX + "dlqpubtest.default");
Queue queue = new Queue(TEST_PREFIX + "dlqpubtest.default", true, false, false, args);
admin.declareQueue(queue);
Binder<MessageChannel> binder = getBinder();
@@ -553,14 +526,14 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
});
binder.bindConsumer("dlqpubtest", moduleInputChannel, properties);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("dlqpubtest", "default", moduleInputChannel, properties);
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.convertAndSend("", TEST_PREFIX + "dlqpubtest", "foo");
template.convertAndSend("", TEST_PREFIX + "dlqpubtest.default", "foo");
int n = 0;
while (n++ < 100) {
org.springframework.amqp.core.Message deadLetter = template.receive(TEST_PREFIX + "dlqpubtest.dlq");
org.springframework.amqp.core.Message deadLetter = template.receive(TEST_PREFIX + "dlqpubtest.default.dlq");
if (deadLetter != null) {
assertEquals("foo", new String(deadLetter.getBody()));
assertNotNull(deadLetter.getMessageProperties().getHeaders().get("x-exception-stacktrace"));
@@ -570,10 +543,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
}
assertTrue(n < 100);
binder.unbindConsumer("dlqpubtest", moduleInputChannel);
admin.deleteQueue(TEST_PREFIX + "dlqpubtest.dlq");
admin.deleteQueue(TEST_PREFIX + "dlqpubtest");
admin.deleteExchange(TEST_PREFIX + "DLX");
binder.unbind(consumerBinding);
}
@SuppressWarnings("unchecked")
@@ -591,9 +561,9 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
DirectChannel output = new DirectChannel();
output.setBeanName("batchingProducer");
binder.bindProducer("batching.0", output, properties);
Binding<MessageChannel> producerBinding = binder.bindProducer("batching.0", output, properties);
while (template.receive(RabbitMessageChannelBinder.DEFAULT_RABBIT_PREFIX + "batching.0") != null) {
while (template.receive(RabbitMessageChannelBinder.DEFAULT_RABBIT_PREFIX + "batching.0.default") != null) {
}
Log logger = spy(TestUtils.getPropertyValue(binder, "binder.compressingPostProcessor.logger", Log.class));
@@ -606,7 +576,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
output.send(new GenericMessage<>("foo".getBytes()));
output.send(new GenericMessage<>("bar".getBytes()));
Object out = spyOn("batching.0").receive(false);
Object out = spyOn("batching.0.default").receive(false);
assertThat(out, instanceOf(byte[].class));
assertEquals("\u0000\u0000\u0000\u0003foo\u0000\u0000\u0000\u0003bar", new String((byte[]) out));
@@ -616,7 +586,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
QueueChannel input = new QueueChannel();
input.setBeanName("batchingConsumer");
binder.bindConsumer("batching.0", input, null);
Binding<MessageChannel> consumerBinding = binder.bindConsumer("batching.0", "test", input, null);
output.send(new GenericMessage<>("foo".getBytes()));
output.send(new GenericMessage<>("bar".getBytes()));
@@ -629,8 +599,8 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
assertEquals("bar", new String(in.getPayload()));
assertNull(in.getHeaders().get(AmqpHeaders.DELIVERY_MODE));
binder.unbindProducers("batching.0");
binder.unbindConsumers("batching.0");
binder.unbind(producerBinding);
binder.unbind(consumerBinding);
}
/*
@@ -641,53 +611,51 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
public void testLateBinding() throws Exception {
RabbitTestSupport.RabbitProxy proxy = new RabbitTestSupport.RabbitProxy();
CachingConnectionFactory cf = new CachingConnectionFactory("localhost", proxy.getPort());
RabbitMessageChannelBinder binder = new RabbitMessageChannelBinder(cf);
AbstractApplicationContext applicationContext = mock(AbstractApplicationContext.class);
when(applicationContext.getBeanFactory()).thenReturn(mock(ConfigurableListableBeanFactory.class));
binder.setApplicationContext(applicationContext);
binder.setDefaultAutoBindDLQ(true);
binder.afterPropertiesSet();
RabbitMessageChannelBinder rabbitBinder = new RabbitMessageChannelBinder(cf);
rabbitBinder.setDefaultAutoBindDLQ(true);
AbstractTestBinder<RabbitMessageChannelBinder> binder = new RabbitTestBinder(cf, rabbitBinder);
Properties properties = new Properties();
properties.put("prefix", "latebinder.");
MessageChannel moduleOutputChannel = new DirectChannel();
binder.bindProducer("late.0", moduleOutputChannel, properties);
Binding<MessageChannel> late0ProducerBinding = binder.bindProducer("late.0", moduleOutputChannel, properties);
QueueChannel moduleInputChannel = new QueueChannel();
binder.bindConsumer("late.0", moduleInputChannel, properties);
Binding<MessageChannel> late0ConsumerBinding = binder.bindConsumer("late.0", "test", moduleInputChannel, properties);
properties.put("partitionKeyExpression", "payload.equals('0') ? 0 : 1");
properties.put("partitionSelectorExpression", "hashCode()");
properties.put("nextModuleCount", "2");
MessageChannel partOutputChannel = new DirectChannel();
binder.bindProducer("partlate.0", partOutputChannel, properties);
Binding<MessageChannel> partlate0ProducerBinding = binder.bindProducer("partlate.0", partOutputChannel, properties);
QueueChannel partInputChannel0 = new QueueChannel();
QueueChannel partInputChannel1 = new QueueChannel();
properties.clear();
properties.put("prefix", "latebinder.");
properties.put("partitionIndex", "0");
binder.bindConsumer("partlate.0", partInputChannel0, properties);
Binding<MessageChannel> partlate0Consumer0Binding = binder.bindConsumer("partlate.0", "test", partInputChannel0, properties);
properties.put("partitionIndex", "1");
binder.bindConsumer("partlate.0", partInputChannel1, properties);
Binding<MessageChannel> partlate0Consumer1Binding = binder.bindConsumer("partlate.0", "test", partInputChannel1, properties);
binder.setDefaultAutoBindDLQ(false);
rabbitBinder.setDefaultAutoBindDLQ(false);
properties.clear();
properties.put("prefix", "latebinder.");
MessageChannel noDLQOutputChannel = new DirectChannel();
binder.bindProducer("lateNoDLQ.0", noDLQOutputChannel, properties);
Binding<MessageChannel> noDlqProducerBinding = binder.bindProducer("lateNoDLQ.0", noDLQOutputChannel, properties);
QueueChannel noDLQInputChannel = new QueueChannel();
binder.bindConsumer("lateNoDLQ.0", noDLQInputChannel, properties);
Binding<MessageChannel> noDlqConsumerBinding = binder.bindConsumer("lateNoDLQ.0", "test", noDLQInputChannel, properties);
MessageChannel pubSubOutputChannel = new DirectChannel();
binder.bindPubSubProducer("latePubSub", pubSubOutputChannel, properties);
MessageChannel outputChannel = new DirectChannel();
Binding<MessageChannel> pubSubProducerBinding = binder.bindProducer("latePubSub", outputChannel, properties);
QueueChannel pubSubInputChannel = new QueueChannel();
binder.bindPubSubConsumer("latePubSub", pubSubInputChannel, "lategroup", properties);
Binding<MessageChannel> nonDurableConsumerBinding = binder.bindConsumer("latePubSub", "lategroup", pubSubInputChannel, properties);
QueueChannel durablePubSubInputChannel = new QueueChannel();
properties.setProperty("durableSubscription", "true");
binder.bindPubSubConsumer("latePubSub", durablePubSubInputChannel, "lateDurableGroup", properties);
Binding<MessageChannel> durableConsumerBinding = binder.bindConsumer("latePubSub", "lateDurableGroup", durablePubSubInputChannel, properties);
proxy.start();
@@ -701,7 +669,7 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
assertNotNull(message);
assertEquals("bar", message.getPayload());
pubSubOutputChannel.send(new GenericMessage<>("baz"));
outputChannel.send(new GenericMessage<>("baz"));
message = pubSubInputChannel.receive(10000);
assertNotNull(message);
assertEquals("baz", message.getPayload());
@@ -718,28 +686,22 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
assertNotNull(message);
assertEquals("1", message.getPayload());
binder.unbindProducer("late.0", moduleOutputChannel);
binder.unbindConsumer("late.0", moduleInputChannel);
binder.unbindProducer("partlate.0", moduleOutputChannel);
binder.unbindConsumers("partlate.0");
binder.unbind(late0ProducerBinding);
binder.unbind(late0ConsumerBinding);
binder.unbind(partlate0ProducerBinding);
binder.unbind(partlate0Consumer0Binding);
binder.unbind(partlate0Consumer1Binding);
binder.unbind(noDlqProducerBinding);
binder.unbind(noDlqConsumerBinding);
binder.unbind(pubSubProducerBinding);
binder.unbind(nonDurableConsumerBinding);
binder.unbind(durableConsumerBinding);
binder.cleanup();
proxy.stop();
cf.destroy();
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
admin.deleteQueue("latebinder.late.0");
admin.deleteQueue("latebinder.lateNoDLQ.0");
admin.deleteQueue("latebinder.partlate.0-0");
admin.deleteQueue("latebinder.partlate.0-1");
admin.deleteQueue("latebinder.late.0.dlq");
admin.deleteQueue("latebinder.partlate.0-0.dlq");
admin.deleteQueue("latebinder.partlate.0-1.dlq");
admin.deleteQueue("latebinder.lateDurableGroup.latePubSub");
admin.deleteExchange("latebinder.late.0");
admin.deleteExchange("latebinder.lateNoDLQ.0");
admin.deleteExchange("latebinder.partlate.0");
admin.deleteExchange("latebinder.latePubSub");
admin.deleteExchange("latebinder.DLX");
this.rabbitAvailableRule.getResource().destroy();
}
@@ -772,26 +734,6 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
return container;
}
private void verifyBarReplyConsumer(AbstractEndpoint endpoint) {
List<?> replyMatchers;
replyMatchers = TestUtils.getPropertyValue(endpoint,
"headerMapper.replyHeaderMatcher.strategies",
List.class);
assertEquals(1, replyMatchers.size());
assertEquals("bar",
TestUtils.getPropertyValue(replyMatchers.get(0), "patterns", Collection.class).iterator().next());
}
private void verifyFooRequestBarReplyProducer(AbstractEndpoint endpoint) {
verifyFooRequestProducer(endpoint);
List<?> replyMatchers = TestUtils.getPropertyValue(endpoint,
"handler.delegate.headerMapper.replyHeaderMatcher.strategies",
List.class);
assertEquals(1, replyMatchers.size());
assertEquals("bar",
TestUtils.getPropertyValue(replyMatchers.get(0), "patterns", Collection.class).iterator().next());
}
private void verifyFooRequestProducer(AbstractEndpoint endpoint) {
List<?> requestMatchers = TestUtils.getPropertyValue(endpoint,
"handler.delegate.headerMapper.requestHeaderMatcher.strategies",
@@ -807,6 +749,11 @@ public class RabbitBinderTests extends PartitionCapableBinderTests {
SpelExpression.class).getExpressionString();
}
@Override
protected String getExpectedRoutingBaseDestination(String name, String group) {
return name;
}
@Override
protected String getPubSubEndpointRouting(AbstractEndpoint endpoint) {
return TestUtils.getPropertyValue(endpoint, "handler.delegate.exchangeNameExpression",

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,19 +23,20 @@ import java.util.Set;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.cloud.stream.binder.AbstractTestBinder;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.integration.codec.kryo.PojoCodec;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* Test support class for {@link RabbitMessageChannelBinder}.
*
* @author Ilayaperumal Gopinathan
* @author Gary Russell
* @author David Turanski
* @author Mark Fisher
*/
public class RabbitTestBinder extends AbstractTestBinder<RabbitMessageChannelBinder> {
@@ -45,8 +46,15 @@ public class RabbitTestBinder extends AbstractTestBinder<RabbitMessageChannelBin
private final Set<String> prefixes = new HashSet<>();
private final Set<String> queues = new HashSet<String>();
private final Set<String> exchanges = new HashSet<String>();
public RabbitTestBinder(ConnectionFactory connectionFactory) {
RabbitMessageChannelBinder binder = new RabbitMessageChannelBinder(connectionFactory);
this(connectionFactory, new RabbitMessageChannelBinder(connectionFactory));
}
public RabbitTestBinder(ConnectionFactory connectionFactory, RabbitMessageChannelBinder binder) {
GenericApplicationContext context = new GenericApplicationContext();
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(1);
@@ -60,75 +68,48 @@ public class RabbitTestBinder extends AbstractTestBinder<RabbitMessageChannelBin
}
@Override
public void bindConsumer(String name, MessageChannel moduleInputChannel, Properties properties) {
capturePrefix(properties);
super.bindConsumer(name, moduleInputChannel, properties);
public Binding<MessageChannel> bindConsumer(String name, String group, MessageChannel moduleInputChannel, Properties properties) {
this.queues.add(prefix(properties) + name + (group == null ? ".default" : "." + group));
this.exchanges.add(prefix(properties) + name);
return super.bindConsumer(name, group, moduleInputChannel, properties);
}
@Override
public void bindProducer(String name, MessageChannel moduleOutputChannel, Properties properties) {
capturePrefix(properties);
super.bindProducer(name, moduleOutputChannel, properties);
public Binding<MessageChannel> bindProducer(String name, MessageChannel moduleOutputChannel, Properties properties) {
this.queues.add(prefix(properties) + name + ".default");
this.exchanges.add(prefix(properties) + name);
return super.bindProducer(name, moduleOutputChannel, properties);
}
@Override
public void bindPubSubConsumer(String name, MessageChannel inputChannel, String group, Properties properties) {
capturePrefix(properties);
super.bindPubSubConsumer(name, inputChannel, group, properties);
}
@Override
public void bindPubSubProducer(String name, MessageChannel outputChannel, Properties properties) {
capturePrefix(properties);
super.bindPubSubProducer(name, outputChannel, properties);
}
@Override
public void bindRequestor(String name, MessageChannel requests, MessageChannel replies, Properties properties) {
capturePrefix(properties);
super.bindRequestor(name, requests, replies, properties);
}
@Override
public void bindReplier(String name, MessageChannel requests, MessageChannel replies, Properties properties) {
capturePrefix(properties);
super.bindReplier(name, requests, replies, properties);
}
public void capturePrefix(Properties properties) {
public String prefix(Properties properties) {
if (properties != null) {
String prefix = properties.getProperty("prefix");
if (prefix != null) {
this.prefixes.add(prefix);
return prefix;
}
}
return BINDER_PREFIX;
}
@Override
public void cleanup() {
if (!queues.isEmpty()) {
for (String queue : queues) {
rabbitAdmin.deleteQueue(BINDER_PREFIX + queue);
// delete any partitioned queues
for (int i = 0; i < 10; i++) {
rabbitAdmin.deleteQueue(BINDER_PREFIX + queue + "-" + i);
}
for (String prefix : this.prefixes) {
rabbitAdmin.deleteQueue(prefix + queue);
// delete any partitioned queues
for (int i = 0; i < 10; i++) {
rabbitAdmin.deleteQueue(prefix + queue + "-" + i);
}
rabbitAdmin.deleteExchange(prefix + queue);
rabbitAdmin.deleteExchange(prefix + queue + ".requests");
}
rabbitAdmin.deleteExchange(BINDER_PREFIX + queue);
for (String queue : this.queues) {
this.rabbitAdmin.deleteQueue(queue);
this.rabbitAdmin.deleteQueue(queue + ".dlq");
// delete any partitioned queues
for (int i = 0; i < 10; i++) {
this.rabbitAdmin.deleteQueue(queue + "-" + i);
this.rabbitAdmin.deleteQueue(queue + "-" + i + ".dlq");
}
}
if (!topics.isEmpty()) {
for (String exchange : topics) {
rabbitAdmin.deleteExchange(BINDER_PREFIX + exchange);
}
for (String exchange : this.exchanges) {
this.rabbitAdmin.deleteExchange(exchange);
}
for (String prefix : this.prefixes) {
this.rabbitAdmin.deleteExchange(prefix + "DLX");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,8 +65,8 @@ public class RabbitBinderModuleTests {
context = null;
}
RabbitAdmin admin = new RabbitAdmin(rabbitTestSupport.getResource());
admin.deleteQueue("binder.input");
admin.deleteQueue("binder.output");
admin.deleteQueue("binder.input.default");
admin.deleteQueue("binder.output.default");
admin.deleteExchange("binder.input");
admin.deleteExchange("binder.output");
}