Renamed MessageBus to Binder

- Renamed MessageBus to Binder
- Parameterized Binder interface
- Restored exclusion of spring-xd-codec
This commit is contained in:
David Turanski
2015-07-20 17:42:48 -04:00
committed by Marius Bogoevici
parent 11e9f269db
commit 35b74b00b3
101 changed files with 1204 additions and 1381 deletions

View File

@@ -27,9 +27,8 @@
</properties>
<modules>
<module>spring-cloud-stream</module>
<module>spring-cloud-stream-bindings</module>
<module>spring-cloud-stream-binders</module>
<module>spring-cloud-stream-codec</module>
<module>spring-cloud-stream-common</module>
<module>spring-cloud-stream-samples</module>
<module>docs</module>
</modules>
@@ -76,17 +75,17 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-local</artifactId>
<artifactId>spring-cloud-stream-binder-local</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-rabbit</artifactId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View File

@@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<packaging>pom</packaging>
<url>http://projects.spring.io/spring-xd/</url>
<organization>
@@ -20,24 +20,24 @@
<curator.version>2.6.0</curator.version>
</properties>
<modules>
<module>spring-cloud-stream-binding-spi</module>
<module>spring-cloud-stream-binding-test</module>
<module>spring-cloud-stream-binding-local</module>
<module>spring-cloud-stream-binding-rabbit</module>
<module>spring-cloud-stream-binding-redis</module>
<module>spring-cloud-stream-binding-kafka</module>
<module>spring-cloud-stream-binder-spi</module>
<module>spring-cloud-stream-binder-test</module>
<module>spring-cloud-stream-binder-local</module>
<module>spring-cloud-stream-binder-rabbit</module>
<module>spring-cloud-stream-binder-redis</module>
<module>spring-cloud-stream-binder-kafka</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-test</artifactId>
<artifactId>spring-cloud-stream-binder-test</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

View File

@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-binding-kafka</artifactId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-stream-binding-kafka</name>
<description>Kafka binding implementation</description>
<name>spring-cloud-stream-binder-kafka</name>
<description>Kafka binder implementation</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
@@ -24,11 +24,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-test</artifactId>
<artifactId>spring-cloud-stream-binder-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>

View File

@@ -43,6 +43,8 @@ import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.ByteArraySerializer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.cloud.stream.binder.BinderException;
import org.springframework.cloud.stream.binder.BinderHeaders;
import org.springframework.http.MediaType;
import org.springframework.integration.channel.FixedSubscriberChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
@@ -77,21 +79,20 @@ import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.integration.bus.AbstractBusPropertiesAccessor;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.EmbeddedHeadersMessageConverter;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
import org.springframework.xd.dirt.integration.bus.MessageValues;
import org.springframework.xd.dirt.integration.bus.XdHeaders;
import org.springframework.cloud.stream.binder.AbstractBinderPropertiesAccessor;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.EmbeddedHeadersMessageConverter;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.cloud.stream.binder.MessageValues;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
import scala.collection.Seq;
/**
* A message bus that uses Kafka as the underlying middleware. The general implementation mapping between XD concepts
* A binder that uses Kafka as the underlying middleware. The general implementation mapping between XD concepts
* and Kafka concepts is as follows:
* A message bus that uses Kafka as the underlying middleware.
* A binder that uses Kafka as the underlying middleware.
* The general implementation mapping between XD concepts and Kafka concepts is as follows:
* <table>
* <tr>
@@ -124,7 +125,7 @@ import scala.collection.Seq;
* @author David Turanski
* @author Gary Russell
*/
public class KafkaMessageBus extends MessageBusSupport {
public class KafkaMessageChannelBinder extends MessageChannelBinderSupport {
public static final ByteArraySerializer BYTE_ARRAY_SERIALIZER = new ByteArraySerializer();
@@ -182,7 +183,7 @@ public class KafkaMessageBus extends MessageBusSupport {
protected static final Set<Object> PRODUCER_COMPRESSION_PROPERTIES = new HashSet<Object>(
Arrays.asList(new String[] {
KafkaMessageBus.COMPRESSION_CODEC,
KafkaMessageChannelBinder.COMPRESSION_CODEC,
}));
/**
@@ -192,7 +193,7 @@ public class KafkaMessageBus extends MessageBusSupport {
private static final String POINT_TO_POINT_SEMANTICS_CONSUMER_GROUP = "springXD";
private static final Set<Object> KAFKA_CONSUMER_PROPERTIES = new SetBuilder()
.add(BusProperties.MIN_PARTITION_COUNT)
.add(BinderProperties.MIN_PARTITION_COUNT)
.build();
/**
@@ -201,14 +202,14 @@ public class KafkaMessageBus extends MessageBusSupport {
private static final Set<Object> SUPPORTED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(CONSUMER_STANDARD_PROPERTIES)
.addAll(KAFKA_CONSUMER_PROPERTIES)
.add(BusProperties.PARTITION_INDEX) // Not actually used
.add(BusProperties.COUNT) // Not actually used
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.PARTITION_INDEX) // Not actually used
.add(BinderProperties.COUNT) // Not actually used
.add(BinderProperties.CONCURRENCY)
.add(FETCH_SIZE)
.build();
private static final Set<Object> KAFKA_PRODUCER_PROPERTIES = new SetBuilder()
.add(BusProperties.MIN_PARTITION_COUNT)
.add(BinderProperties.MIN_PARTITION_COUNT)
.build();
/**
@@ -229,7 +230,7 @@ public class KafkaMessageBus extends MessageBusSupport {
private static final Set<Object> SUPPORTED_PRODUCER_PROPERTIES = new SetBuilder()
.addAll(PRODUCER_PARTITIONING_PROPERTIES)
.addAll(PRODUCER_STANDARD_PROPERTIES)
.add(BusProperties.DIRECT_BINDING_ALLOWED)
.add(BinderProperties.DIRECT_BINDING_ALLOWED)
.addAll(KAFKA_PRODUCER_PROPERTIES)
.addAll(PRODUCER_BATCHING_BASIC_PROPERTIES)
.addAll(PRODUCER_COMPRESSION_PROPERTIES)
@@ -291,7 +292,7 @@ public class KafkaMessageBus extends MessageBusSupport {
private Mode mode = Mode.embeddedHeaders;
public KafkaMessageBus(ZookeeperConnect zookeeperConnect, String brokers, String zkAddress,
public KafkaMessageChannelBinder(ZookeeperConnect zookeeperConnect, String brokers, String zkAddress,
MultiTypeCodec<Object> codec, String... headersToMap) {
this.zookeeperConnect = zookeeperConnect;
this.brokers = brokers;
@@ -299,14 +300,14 @@ public class KafkaMessageBus extends MessageBusSupport {
setCodec(codec);
if (headersToMap.length > 0) {
String[] combinedHeadersToMap =
Arrays.copyOfRange(XdHeaders.STANDARD_HEADERS, 0, XdHeaders.STANDARD_HEADERS.length + headersToMap
Arrays.copyOfRange(BinderHeaders.STANDARD_HEADERS, 0, BinderHeaders.STANDARD_HEADERS.length + headersToMap
.length);
System.arraycopy(headersToMap, 0, combinedHeadersToMap, XdHeaders.STANDARD_HEADERS.length, headersToMap
System.arraycopy(headersToMap, 0, combinedHeadersToMap, BinderHeaders.STANDARD_HEADERS.length, headersToMap
.length);
this.headersToMap = combinedHeadersToMap;
}
else {
this.headersToMap = XdHeaders.STANDARD_HEADERS;
this.headersToMap = BinderHeaders.STANDARD_HEADERS;
}
}
@@ -546,12 +547,12 @@ public class KafkaMessageBus extends MessageBusSupport {
@Override
public void bindRequestor(String name, MessageChannel requests, MessageChannel replies, Properties properties) {
throw new UnsupportedOperationException("requestor binding is not supported by this bus");
throw new UnsupportedOperationException("requestor binding is not supported by this binder");
}
@Override
public void bindReplier(String name, MessageChannel requests, MessageChannel replies, Properties properties) {
throw new UnsupportedOperationException("replier binding is not supported by this bus");
throw new UnsupportedOperationException("replier binding is not supported by this binder");
}
/**
@@ -599,8 +600,8 @@ public class KafkaMessageBus extends MessageBusSupport {
return partitions;
}
catch (Exception e) {
logger.error("Cannot initialize MessageBus", e);
throw new RuntimeException("Cannot initialize message bus:", e);
logger.error("Cannot initialize Binder", e);
throw new BinderException("Cannot initialize binder:", e);
}
}
@@ -786,7 +787,7 @@ public class KafkaMessageBus extends MessageBusSupport {
}
}
private class KafkaPropertiesAccessor extends AbstractBusPropertiesAccessor {
private class KafkaPropertiesAccessor extends AbstractBinderPropertiesAccessor {
public KafkaPropertiesAccessor(Properties properties) {
super(properties);
@@ -833,7 +834,7 @@ public class KafkaMessageBus extends MessageBusSupport {
private class ReceivingHandler extends AbstractReplyProducingMessageHandler {
public ReceivingHandler() {
this.setBeanFactory(KafkaMessageBus.this.getBeanFactory());
this.setBeanFactory(KafkaMessageChannelBinder.this.getBeanFactory());
}
@Override
@@ -850,7 +851,7 @@ public class KafkaMessageBus extends MessageBusSupport {
messageValues = new MessageValues(requestMessage);
}
messageValues = deserializePayloadIfNecessary(messageValues);
return MessageBuilder.createMessage(messageValues.getPayload(), new KafkaBusMessageHeaders(
return MessageBuilder.createMessage(messageValues.getPayload(), new KafkaBinderHeaders(
messageValues));
}
else {
@@ -859,9 +860,9 @@ public class KafkaMessageBus extends MessageBusSupport {
}
@SuppressWarnings("serial")
private final class KafkaBusMessageHeaders extends MessageHeaders {
private final class KafkaBinderHeaders extends MessageHeaders {
KafkaBusMessageHeaders(Map<String, Object> headers) {
KafkaBinderHeaders(Map<String, Object> headers) {
super(headers, MessageHeaders.ID_VALUE_NONE, -1L);
}
}
@@ -892,7 +893,7 @@ public class KafkaMessageBus extends MessageBusSupport {
this.topicName = topicName;
this.numberOfKafkaPartitions = numberOfPartitions;
this.partitioningMetadata = new PartitioningMetadata(properties, numberOfPartitions);
this.setBeanFactory(KafkaMessageBus.this.getBeanFactory());
this.setBeanFactory(KafkaMessageChannelBinder.this.getBeanFactory());
this.producerConfiguration = producerConfiguration;
}
@@ -909,7 +910,7 @@ public class KafkaMessageBus extends MessageBusSupport {
if (Mode.embeddedHeaders.equals(mode)) {
MessageValues transformed = serializePayloadIfNecessary(message);
byte[] messageToSend = embeddedHeadersMessageConverter.embedHeaders(transformed,
KafkaMessageBus.this.headersToMap);
KafkaMessageChannelBinder.this.headersToMap);
producerConfiguration.send(topicName, targetPartition, null, messageToSend);
}
else if (Mode.raw.equals(mode)) {

View File

@@ -11,7 +11,7 @@
</bean>
<bean id="messageBus" class="org.springframework.xd.dirt.integration.kafka.KafkaMessageBus">
<bean id="messageBus" class="org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder">
<constructor-arg ref="zookeeperConnect"/>
<constructor-arg value="${xd.messagebus.kafka.brokers}"/>
<constructor-arg value="${xd.messagebus.kafka.zkAddress}"/>

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.xd.dirt.integration.kafka;
package org.springframework.cloud.stream.binder.kafka;
import java.io.File;
import java.net.InetSocketAddress;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.kafka;
package org.springframework.cloud.stream.binder.kafka;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.junit.Assert.assertArrayEquals;
@@ -35,6 +35,7 @@ import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.cloud.stream.binder.PartitionCapableBinderTests;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.kafka.core.KafkaMessage;
@@ -42,42 +43,42 @@ import org.springframework.integration.kafka.core.Partition;
import org.springframework.integration.kafka.listener.KafkaMessageListenerContainer;
import org.springframework.integration.kafka.listener.MessageListener;
import org.springframework.messaging.Message;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.PartitionCapableBusTests;
import org.springframework.xd.dirt.integration.bus.Spy;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageBus;
import org.springframework.xd.dirt.integration.kafka.KafkaTestSupport;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.Binder;
import org.springframework.cloud.stream.binder.Spy;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder;
/**
* Integration tests for the {@link KafkaMessageBus}.
* Integration tests for the {@link org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder}.
*
* @author Eric Bottard
* @author Marius Bogoevici
*/
public class KafkaMessageBusTests extends PartitionCapableBusTests {
public class KafkaBinderTests extends PartitionCapableBinderTests {
private final String CLASS_UNDER_TEST_NAME = KafkaMessageChannelBinder.class.getSimpleName();
@ClassRule
public static KafkaTestSupport kafkaTestSupport = new KafkaTestSupport();
private KafkaTestMessageBus messageBus;
private KafkaTestBinder binder;
@Override
protected void busBindUnbindLatency() throws InterruptedException {
protected void binderBindUnbindLatency() throws InterruptedException {
Thread.sleep(500);
}
@Override
protected MessageBus getMessageBus() {
if (messageBus == null) {
messageBus = createKafkaTestMessageBus();
protected Binder getBinder() {
if (binder == null) {
binder = createKafkaTestBinder();
}
return messageBus;
return binder;
}
protected KafkaTestMessageBus createKafkaTestMessageBus() {
return new KafkaTestMessageBus(kafkaTestSupport, getCodec(), KafkaMessageBus.Mode.embeddedHeaders);
protected KafkaTestBinder createKafkaTestBinder() {
return new KafkaTestBinder(kafkaTestSupport, getCodec(), KafkaMessageChannelBinder.Mode.embeddedHeaders);
}
@Override
@@ -86,13 +87,18 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
}
@Override
public Spy spyOn(final String name) {
String topic = KafkaMessageBus.escapeTopicName(name);
protected String getClassUnderTestName() {
return CLASS_UNDER_TEST_NAME;
}
KafkaTestMessageBus busWrapper = (KafkaTestMessageBus) getMessageBus();
@Override
public Spy spyOn(final String name) {
String topic = KafkaMessageChannelBinder.escapeTopicName(name);
KafkaTestBinder binderWrapper = (KafkaTestBinder) getBinder();
// Rewind offset, as tests will have typically already sent the messages we're trying to consume
KafkaMessageListenerContainer messageListenerContainer = busWrapper.getCoreMessageBus().createMessageListenerContainer(
KafkaMessageListenerContainer messageListenerContainer = binderWrapper.getCoreBinder().createMessageListenerContainer(
new Properties(), UUID.randomUUID().toString(), 1, topic, OffsetRequest.EarliestTime());
final BlockingQueue<KafkaMessage> messages = new ArrayBlockingQueue<KafkaMessage>(10);
@@ -122,26 +128,26 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
byte[] ratherBigPayload = new byte[2048];
Arrays.fill(ratherBigPayload, (byte) 65);
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
for (String codec : codecs) {
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
Properties props = new Properties();
if (codec != null) {
props.put(KafkaMessageBus.COMPRESSION_CODEC, codec);
props.put(KafkaMessageChannelBinder.COMPRESSION_CODEC, codec);
}
messageBus.bindProducer("foo.0", moduleOutputChannel, props);
messageBus.bindConsumer("foo.0", moduleInputChannel, null);
binder.bindProducer("foo.0", moduleOutputChannel, props);
binder.bindConsumer("foo.0", moduleInputChannel, null);
Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(2000);
assertNotNull(inbound);
assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload());
messageBus.unbindProducers("foo.0");
messageBus.unbindConsumers("foo.0");
binder.unbindProducers("foo.0");
binder.unbindConsumers("foo.0");
}
}
@@ -150,30 +156,30 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
byte[] ratherBigPayload = new byte[2048];
Arrays.fill(ratherBigPayload, (byte) 65);
KafkaTestMessageBus messageBus = (KafkaTestMessageBus) getMessageBus();
KafkaTestBinder binder = (KafkaTestBinder) getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
Properties producerProperties = new Properties();
producerProperties.put(BusProperties.MIN_PARTITION_COUNT, "10");
producerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "10");
Properties consumerProperties = new Properties();
consumerProperties.put(BusProperties.MIN_PARTITION_COUNT, "10");
consumerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "10");
long uniqueBindingId = System.currentTimeMillis();
messageBus.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties);
messageBus.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties);
binder.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties);
binder.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties);
Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(2000);
assertNotNull(inbound);
assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload());
Collection<Partition> partitions = messageBus.getCoreMessageBus().getConnectionFactory().getPartitions(
Collection<Partition> partitions = binder.getCoreBinder().getConnectionFactory().getPartitions(
"foo" + uniqueBindingId + ".0");
assertThat(partitions, hasSize(10));
messageBus.unbindProducers("foo" + uniqueBindingId + ".0");
messageBus.unbindConsumers("foo" + uniqueBindingId + ".0");
binder.unbindProducers("foo" + uniqueBindingId + ".0");
binder.unbindConsumers("foo" + uniqueBindingId + ".0");
}
@Test
@@ -181,32 +187,32 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
byte[] ratherBigPayload = new byte[2048];
Arrays.fill(ratherBigPayload, (byte) 65);
KafkaTestMessageBus messageBus = (KafkaTestMessageBus) getMessageBus();
KafkaTestBinder binder = (KafkaTestBinder) getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
Properties producerProps = new Properties();
producerProps.put(BusProperties.MIN_PARTITION_COUNT, "5");
producerProps.put(BusProperties.NEXT_MODULE_CONCURRENCY, "6");
producerProps.put(BinderProperties.MIN_PARTITION_COUNT, "5");
producerProps.put(BinderProperties.NEXT_MODULE_CONCURRENCY, "6");
Properties consumerProps = new Properties();
consumerProps.put(BusProperties.MIN_PARTITION_COUNT, "5");
consumerProps.put(BusProperties.CONCURRENCY, "6");
consumerProps.put(BinderProperties.MIN_PARTITION_COUNT, "5");
consumerProps.put(BinderProperties.CONCURRENCY, "6");
long uniqueBindingId = System.currentTimeMillis();
messageBus.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProps);
messageBus.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProps);
binder.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProps);
binder.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProps);
Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(2000);
assertNotNull(inbound);
assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload());
Collection<Partition> partitions = messageBus.getCoreMessageBus().getConnectionFactory().getPartitions(
Collection<Partition> partitions = binder.getCoreBinder().getConnectionFactory().getPartitions(
"foo" + uniqueBindingId + ".0");
assertThat(partitions, hasSize(6));
messageBus.unbindProducers("foo" + uniqueBindingId + ".0");
messageBus.unbindConsumers("foo" + uniqueBindingId + ".0");
binder.unbindProducers("foo" + uniqueBindingId + ".0");
binder.unbindConsumers("foo" + uniqueBindingId + ".0");
}
@Test
@@ -214,31 +220,31 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
byte[] ratherBigPayload = new byte[2048];
Arrays.fill(ratherBigPayload, (byte) 65);
KafkaTestMessageBus messageBus = (KafkaTestMessageBus) getMessageBus();
KafkaTestBinder binder = (KafkaTestBinder) getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
Properties producerProps = new Properties();
producerProps.put(BusProperties.MIN_PARTITION_COUNT, "6");
producerProps.put(BusProperties.NEXT_MODULE_CONCURRENCY, "5");
producerProps.put(BinderProperties.MIN_PARTITION_COUNT, "6");
producerProps.put(BinderProperties.NEXT_MODULE_CONCURRENCY, "5");
Properties consumerProps = new Properties();
consumerProps.put(BusProperties.MIN_PARTITION_COUNT, "6");
consumerProps.put(BusProperties.CONCURRENCY, "5");
consumerProps.put(BinderProperties.MIN_PARTITION_COUNT, "6");
consumerProps.put(BinderProperties.CONCURRENCY, "5");
long uniqueBindingId = System.currentTimeMillis();
messageBus.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProps);
messageBus.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProps);
binder.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProps);
binder.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProps);
Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(2000);
assertNotNull(inbound);
assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload());
Collection<Partition> partitions = messageBus.getCoreMessageBus().getConnectionFactory().getPartitions(
Collection<Partition> partitions = binder.getCoreBinder().getConnectionFactory().getPartitions(
"foo" + uniqueBindingId + ".0");
assertThat(partitions, hasSize(6));
messageBus.unbindProducers("foo" + uniqueBindingId + ".0");
messageBus.unbindConsumers("foo" + uniqueBindingId + ".0");
binder.unbindProducers("foo" + uniqueBindingId + ".0");
binder.unbindConsumers("foo" + uniqueBindingId + ".0");
}
@Test
@@ -246,31 +252,31 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
byte[] ratherBigPayload = new byte[2048];
Arrays.fill(ratherBigPayload, (byte) 65);
KafkaTestMessageBus messageBus = (KafkaTestMessageBus) getMessageBus();
KafkaTestBinder binder = (KafkaTestBinder) getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
Properties producerProperties = new Properties();
producerProperties.put(BusProperties.MIN_PARTITION_COUNT, "3");
producerProperties.put(BusProperties.NEXT_MODULE_COUNT, "5");
producerProperties.put(BusProperties.PARTITION_KEY_EXPRESSION, "payload");
producerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "3");
producerProperties.put(BinderProperties.NEXT_MODULE_COUNT, "5");
producerProperties.put(BinderProperties.PARTITION_KEY_EXPRESSION, "payload");
Properties consumerProperties = new Properties();
consumerProperties.put(BusProperties.MIN_PARTITION_COUNT, "3");
consumerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "3");
long uniqueBindingId = System.currentTimeMillis();
messageBus.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties);
messageBus.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties);
binder.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties);
binder.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties);
Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(2000);
assertNotNull(inbound);
assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload());
Collection<Partition> partitions = messageBus.getCoreMessageBus().getConnectionFactory().getPartitions(
Collection<Partition> partitions = binder.getCoreBinder().getConnectionFactory().getPartitions(
"foo" + uniqueBindingId + ".0");
assertThat(partitions, hasSize(5));
messageBus.unbindProducers("foo" + uniqueBindingId + ".0");
messageBus.unbindConsumers("foo" + uniqueBindingId + ".0");
binder.unbindProducers("foo" + uniqueBindingId + ".0");
binder.unbindConsumers("foo" + uniqueBindingId + ".0");
}
@Test
@@ -278,35 +284,35 @@ public class KafkaMessageBusTests extends PartitionCapableBusTests {
byte[] ratherBigPayload = new byte[2048];
Arrays.fill(ratherBigPayload, (byte) 65);
KafkaTestMessageBus messageBus = (KafkaTestMessageBus) getMessageBus();
KafkaTestBinder binder = (KafkaTestBinder) getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
Properties producerProperties = new Properties();
producerProperties.put(BusProperties.MIN_PARTITION_COUNT, "5");
producerProperties.put(BusProperties.NEXT_MODULE_COUNT, "3");
producerProperties.put(BusProperties.PARTITION_KEY_EXPRESSION, "payload");
producerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "5");
producerProperties.put(BinderProperties.NEXT_MODULE_COUNT, "3");
producerProperties.put(BinderProperties.PARTITION_KEY_EXPRESSION, "payload");
Properties consumerProperties = new Properties();
consumerProperties.put(BusProperties.MIN_PARTITION_COUNT, "5");
consumerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "5");
long uniqueBindingId = System.currentTimeMillis();
messageBus.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties);
messageBus.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties);
binder.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties);
binder.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties);
Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(2000);
assertNotNull(inbound);
assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload());
Collection<Partition> partitions = messageBus.getCoreMessageBus().getConnectionFactory().getPartitions(
Collection<Partition> partitions = binder.getCoreBinder().getConnectionFactory().getPartitions(
"foo" + uniqueBindingId + ".0");
assertThat(partitions, hasSize(5));
messageBus.unbindProducers("foo" + uniqueBindingId + ".0");
messageBus.unbindConsumers("foo" + uniqueBindingId + ".0");
binder.unbindProducers("foo" + uniqueBindingId + ".0");
binder.unbindConsumers("foo" + uniqueBindingId + ".0");
}
@Test
@Ignore("Kafka message bus does not support direct binding")
@Ignore("Kafka binder does not support direct binding")
@Override
public void testDirectBinding() throws Exception {

View File

@@ -14,49 +14,47 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.kafka;
package org.springframework.cloud.stream.binder.kafka;
import org.springframework.cloud.stream.binder.AbstractTestBinder;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.integration.kafka.support.ZookeeperConnect;
import org.springframework.xd.dirt.integration.bus.AbstractTestMessageBus;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
import org.springframework.xd.dirt.integration.bus.serializer.kryo.PojoCodec;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageBus;
import org.springframework.xd.dirt.integration.kafka.TestKafkaCluster;
import org.springframework.xd.dirt.integration.kafka.KafkaTestSupport;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder;
import org.springframework.xd.tuple.serializer.kryo.TupleKryoRegistrar;
/**
* Test support class for {@link KafkaMessageBus}.
* Creates a bus that uses a test {@link TestKafkaCluster kafka cluster}.
* Test support class for {@link org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder}.
* Creates a binder that uses a test {@link TestKafkaCluster kafka cluster}.
* @author Eric Bottard
* @author Marius Bogoevici
* @author David Turanski
*/
public class KafkaTestMessageBus extends AbstractTestMessageBus<KafkaMessageBus> {
public class KafkaTestBinder extends AbstractTestBinder<KafkaMessageChannelBinder> {
public KafkaTestMessageBus(KafkaTestSupport kafkaTestSupport) {
this(kafkaTestSupport, getCodec(), KafkaMessageBus.Mode.embeddedHeaders);
public KafkaTestBinder(KafkaTestSupport kafkaTestSupport) {
this(kafkaTestSupport, getCodec(), KafkaMessageChannelBinder.Mode.embeddedHeaders);
}
public KafkaTestMessageBus(KafkaTestSupport kafkaTestSupport, MultiTypeCodec<Object> codec,
KafkaMessageBus.Mode mode) {
public KafkaTestBinder(KafkaTestSupport kafkaTestSupport, MultiTypeCodec<Object> codec,
KafkaMessageChannelBinder.Mode mode) {
try {
ZookeeperConnect zookeeperConnect = new ZookeeperConnect();
zookeeperConnect.setZkConnect(kafkaTestSupport.getZkConnectString());
KafkaMessageBus messageBus = new KafkaMessageBus(zookeeperConnect,
KafkaMessageChannelBinder binder = new KafkaMessageChannelBinder(zookeeperConnect,
kafkaTestSupport.getBrokerAddress(),
kafkaTestSupport.getZkConnectString(), codec);
messageBus.setDefaultBatchingEnabled(false);
messageBus.setMode(mode);
messageBus.afterPropertiesSet();
binder.setDefaultBatchingEnabled(false);
binder.setMode(mode);
binder.afterPropertiesSet();
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
messageBus.setApplicationContext(context);
this.setMessageBus(messageBus);
binder.setApplicationContext(context);
this.setBinder(binder);
}
catch (Exception e) {
throw new RuntimeException(e);

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.kafka;
package org.springframework.cloud.stream.binder.kafka;
import java.util.Properties;
@@ -34,7 +34,7 @@ import org.junit.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.xd.test.AbstractExternalResourceTestSupport;
import org.springframework.cloud.stream.binder.AbstractExternalResourceTestSupport;
/**
* JUnit {@link Rule} that starts an embedded Kafka server (with an associated Zookeeper)

View File

@@ -14,11 +14,11 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.kafka;
package org.springframework.cloud.stream.binder.kafka;
import org.springframework.messaging.Message;
import org.springframework.xd.dirt.integration.bus.PartitionKeyExtractorStrategy;
import org.springframework.xd.dirt.integration.bus.PartitionSelectorStrategy;
import org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy;
import org.springframework.cloud.stream.binder.PartitionSelectorStrategy;
/**

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.kafka;
package org.springframework.cloud.stream.binder.kafka;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
@@ -32,6 +32,7 @@ import java.util.Properties;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.cloud.stream.binder.BinderHeaders;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -41,39 +42,38 @@ import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.XdHeaders;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageBus;
import org.springframework.xd.test.TestUtils;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.Binder;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder;
import org.springframework.cloud.stream.binder.TestUtils;
/**
* @author Marius Bogoevici
*/
public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
public class RawModeKafkaBinderTests extends KafkaBinderTests {
@Override
protected KafkaTestMessageBus createKafkaTestMessageBus() {
return new KafkaTestMessageBus(kafkaTestSupport, getCodec(), KafkaMessageBus.Mode.raw);
protected KafkaTestBinder createKafkaTestBinder() {
return new KafkaTestBinder(kafkaTestSupport, getCodec(), KafkaMessageChannelBinder.Mode.raw);
}
@Test
@Override
public void testPartitionedModuleJava() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("partitionKeyExtractorClass", "org.springframework.xd.dirt.integration.bus.kafka.RawKafkaPartitionTestSupport");
properties.put("partitionSelectorClass", "org.springframework.xd.dirt.integration.bus.kafka.RawKafkaPartitionTestSupport");
properties.put(BusProperties.NEXT_MODULE_COUNT, "3");
properties.put(BusProperties.NEXT_MODULE_CONCURRENCY, "2");
properties.put("partitionKeyExtractorClass", "org.springframework.cloud.stream.binder.kafka.RawKafkaPartitionTestSupport");
properties.put("partitionSelectorClass", "org.springframework.cloud.stream.binder.kafka.RawKafkaPartitionTestSupport");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "3");
properties.put(BinderProperties.NEXT_MODULE_CONCURRENCY, "2");
DirectChannel output = new DirectChannel();
output.setBeanName("test.output");
bus.bindProducer("partJ.0", output, properties);
binder.bindProducer("partJ.0", output, properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
properties.clear();
@@ -82,15 +82,15 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
properties.put("partitionIndex", "0");
QueueChannel input0 = new QueueChannel();
input0.setBeanName("test.input0J");
bus.bindConsumer("partJ.0", input0, properties);
binder.bindConsumer("partJ.0", input0, properties);
properties.put("partitionIndex", "1");
QueueChannel input1 = new QueueChannel();
input1.setBeanName("test.input1J");
bus.bindConsumer("partJ.0", input1, properties);
binder.bindConsumer("partJ.0", input1, properties);
properties.put("partitionIndex", "2");
QueueChannel input2 = new QueueChannel();
input2.setBeanName("test.input2J");
bus.bindConsumer("partJ.0", input2, properties);
binder.bindConsumer("partJ.0", input2, properties);
output.send(new GenericMessage<>(new byte[]{(byte)0}));
output.send(new GenericMessage<>(new byte[]{(byte)1}));
@@ -109,25 +109,25 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
((byte[]) receive2.getPayload())[0]),
containsInAnyOrder((byte)0, (byte)1, (byte)2));
bus.unbindConsumers("partJ.0");
bus.unbindProducers("partJ.0");
binder.unbindConsumers("partJ.0");
binder.unbindProducers("partJ.0");
}
@Test
@Override
public void testPartitionedModuleSpEL() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("partitionKeyExpression", "payload[0]");
properties.put("partitionSelectorExpression", "hashCode()");
properties.put(BusProperties.NEXT_MODULE_COUNT, "3");
properties.put(BusProperties.NEXT_MODULE_CONCURRENCY, "2");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "3");
properties.put(BinderProperties.NEXT_MODULE_CONCURRENCY, "2");
DirectChannel output = new DirectChannel();
output.setBeanName("test.output");
bus.bindProducer("part.0", output, properties);
binder.bindProducer("part.0", output, properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
try {
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
@@ -143,15 +143,15 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
properties.put("count","3");
QueueChannel input0 = new QueueChannel();
input0.setBeanName("test.input0S");
bus.bindConsumer("part.0", input0, properties);
binder.bindConsumer("part.0", input0, properties);
properties.put("partitionIndex", "1");
QueueChannel input1 = new QueueChannel();
input1.setBeanName("test.input1S");
bus.bindConsumer("part.0", input1, properties);
binder.bindConsumer("part.0", input1, properties);
properties.put("partitionIndex", "2");
QueueChannel input2 = new QueueChannel();
input2.setBeanName("test.input2S");
bus.bindConsumer("part.0", input2, properties);
binder.bindConsumer("part.0", input2, properties);
Message<byte[]> message2 = MessageBuilder.withPayload(new byte[]{2})
.setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "foo")
@@ -177,14 +177,14 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
((byte[]) receive2.getPayload())[0]),
containsInAnyOrder((byte)0, (byte)1, (byte)2));
bus.unbindConsumers("part.0");
bus.unbindProducers("part.0");
binder.unbindConsumers("part.0");
binder.unbindProducers("part.0");
}
@Test
@Override
public void createInboundPubSubBeforeOutboundPubSub() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
// Test pub/sub by emulating how StreamPlugin handles taps
DirectChannel tapChannel = new DirectChannel();
@@ -192,18 +192,18 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
QueueChannel module2InputChannel = new QueueChannel();
QueueChannel module3InputChannel = new QueueChannel();
// Create the tap first
String fooTapName = messageBus.isCapable(MessageBus.Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(fooTapName, module2InputChannel, null);
String fooTapName = binder.isCapable(Binder.Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(fooTapName, module2InputChannel, null);
// Then create the stream
messageBus.bindProducer("baz.0", moduleOutputChannel, null);
messageBus.bindConsumer("baz.0", moduleInputChannel, null);
binder.bindProducer("baz.0", moduleOutputChannel, null);
binder.bindConsumer("baz.0", moduleInputChannel, null);
moduleOutputChannel.addInterceptor(new WireTap(tapChannel));
messageBus.bindPubSubProducer("tap:baz.http", tapChannel, null);
binder.bindPubSubProducer("tap:baz.http", tapChannel, null);
// Another new module is using tap as an input channel
String barTapName = messageBus.isCapable(MessageBus.Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(barTapName, module3InputChannel, null);
String barTapName = binder.isCapable(Binder.Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(barTapName, module3InputChannel, null);
Message<?> message = MessageBuilder.withPayload("foo".getBytes()).setHeader(MessageHeaders.CONTENT_TYPE, "foo/bar").build();
boolean success = false;
boolean retried = false;
@@ -222,11 +222,11 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
}
success = true;
assertEquals("foo", new String((byte[]) tapped1.getPayload()));
assertNull(tapped1.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(tapped1.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo", new String((byte[])tapped2.getPayload()));
}
// delete one tap stream is deleted
messageBus.unbindConsumer(barTapName, module3InputChannel);
binder.unbindConsumer(barTapName, module3InputChannel);
Message<?> message2 = MessageBuilder.withPayload("bar".getBytes()).setHeader(MessageHeaders.CONTENT_TYPE, "foo/bar").build();
moduleOutputChannel.send(message2);
@@ -238,31 +238,31 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
assertNull(module3InputChannel.receive(1000));
// when other tap stream is deleted
messageBus.unbindConsumer(fooTapName, module2InputChannel);
binder.unbindConsumer(fooTapName, module2InputChannel);
// Clean up as StreamPlugin would
messageBus.unbindConsumer("baz.0", moduleInputChannel);
messageBus.unbindProducer("baz.0", moduleOutputChannel);
messageBus.unbindProducers("tap:baz.http");
assertTrue(getBindings(messageBus).isEmpty());
binder.unbindConsumer("baz.0", moduleInputChannel);
binder.unbindProducer("baz.0", moduleOutputChannel);
binder.unbindProducers("tap:baz.http");
assertTrue(getBindings(binder).isEmpty());
}
@Test
@Override
public void testSendAndReceive() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
messageBus.bindProducer("foo.0", moduleOutputChannel, null);
messageBus.bindConsumer("foo.0", moduleInputChannel, null);
binder.bindProducer("foo.0", moduleOutputChannel, null);
binder.bindConsumer("foo.0", moduleInputChannel, null);
Message<?> message = MessageBuilder.withPayload("foo".getBytes()).build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(5000);
assertNotNull(inbound);
assertEquals("foo", new String((byte[])inbound.getPayload()));
messageBus.unbindProducers("foo.0");
messageBus.unbindConsumers("foo.0");
binder.unbindProducers("foo.0");
binder.unbindConsumers("foo.0");
}
// Ignored, since raw mode does not support headers
@@ -275,23 +275,23 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
@Test
public void testSendAndReceivePubSub() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
// Test pub/sub by emulating how StreamPlugin handles taps
DirectChannel tapChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
QueueChannel module2InputChannel = new QueueChannel();
QueueChannel module3InputChannel = new QueueChannel();
messageBus.bindProducer("baz.0", moduleOutputChannel, null);
messageBus.bindConsumer("baz.0", moduleInputChannel, null);
binder.bindProducer("baz.0", moduleOutputChannel, null);
binder.bindConsumer("baz.0", moduleInputChannel, null);
moduleOutputChannel.addInterceptor(new WireTap(tapChannel));
messageBus.bindPubSubProducer("tap:baz.http", tapChannel, null);
binder.bindPubSubProducer("tap:baz.http", tapChannel, null);
// A new module is using the tap as an input channel
String fooTapName = messageBus.isCapable(MessageBus.Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(fooTapName, module2InputChannel, null);
String fooTapName = binder.isCapable(Binder.Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(fooTapName, module2InputChannel, null);
// Another new module is using tap as an input channel
String barTapName = messageBus.isCapable(MessageBus.Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(barTapName, module3InputChannel, null);
String barTapName = binder.isCapable(Binder.Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(barTapName, module3InputChannel, null);
Message<?> message = MessageBuilder.withPayload("foo".getBytes()).build();
boolean success = false;
boolean retried = false;
@@ -314,7 +314,7 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
assertEquals("foo", new String((byte[])tapped2.getPayload()));
}
// delete one tap stream is deleted
messageBus.unbindConsumer(barTapName, module3InputChannel);
binder.unbindConsumer(barTapName, module3InputChannel);
Message<?> message2 = MessageBuilder.withPayload("bar".getBytes()).build();
moduleOutputChannel.send(message2);
@@ -326,12 +326,12 @@ public class RawModeKafkaMessageBusTests extends KafkaMessageBusTests {
assertNull(module3InputChannel.receive(1000));
// when other tap stream is deleted
messageBus.unbindConsumer(fooTapName, module2InputChannel);
binder.unbindConsumer(fooTapName, module2InputChannel);
// Clean up as StreamPlugin would
messageBus.unbindConsumer("baz.0", moduleInputChannel);
messageBus.unbindProducer("baz.0", moduleOutputChannel);
messageBus.unbindProducers("tap:baz.http");
assertTrue(getBindings(messageBus).isEmpty());
binder.unbindConsumer("baz.0", moduleInputChannel);
binder.unbindProducer("baz.0", moduleOutputChannel);
binder.unbindProducers("tap:baz.http");
assertTrue(getBindings(binder).isEmpty());
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.kafka;
package org.springframework.cloud.stream.binder.kafka;
import kafka.admin.AdminUtils;
import kafka.consumer.Consumer;
@@ -35,6 +35,7 @@ import org.apache.curator.test.TestingServer;
import org.springframework.util.Assert;
import org.springframework.util.SocketUtils;
import org.springframework.xd.dirt.integration.kafka.KafkaMessageChannelBinder;
import java.io.IOException;
import java.util.Collections;
@@ -90,7 +91,7 @@ public class TestKafkaCluster {
*/
public static void main(String[] args) throws Exception {
TestKafkaCluster cluster = new TestKafkaCluster();
ZkClient client = new ZkClient(cluster.getZkConnectString(), 10000, 10000, KafkaMessageBus.utf8Serializer);
ZkClient client = new ZkClient(cluster.getZkConnectString(), 10000, 10000, KafkaMessageChannelBinder.utf8Serializer);
int partitions = 5;
int replication = 1;
AdminUtils.createTopic(client, "mytopic", partitions, replication, new Properties());

View File

@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-binding-local</artifactId>
<artifactId>spring-cloud-stream-binder-local</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-stream-binding-local</name>
<description>Local(in memory) binding implementation</description>
<name>spring-cloud-stream-binder-local</name>
<description>Local(in memory) binder implementation</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
@@ -21,11 +21,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-test</artifactId>
<artifactId>spring-cloud-stream-binder-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -11,7 +11,7 @@
* specific language governing permissions and limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.local;
package org.springframework.cloud.stream.binder.local;
import java.util.Collection;
import java.util.HashMap;
@@ -37,13 +37,13 @@ import org.springframework.messaging.SubscribableChannel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.xd.dirt.integration.bus.AbstractBusPropertiesAccessor;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
import org.springframework.cloud.stream.binder.AbstractBinderPropertiesAccessor;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
/**
* A simple implementation of {@link org.springframework.xd.dirt.integration.bus.MessageBus} for in-process use. For inbound and outbound, creates a
* A simple implementation of {@link org.springframework.cloud.stream.binder.Binder} for in-process use. For inbound and outbound, creates a
* {@link DirectChannel} or a {@link QueueChannel} depending on whether the binding is aliased or not then bridges the
* passed {@link MessageChannel} to the channel which is registered in the given application context. If that channel
* does not yet exist, it will be created.
@@ -55,7 +55,7 @@ import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
* @author Ilayaperumal Gopinathan
* @since 1.0
*/
public class LocalMessageBus extends MessageBusSupport {
public class LocalMessageChannelBinder extends MessageChannelBinderSupport {
private static final int DEFAULT_EXECUTOR_CORE_POOL_SIZE = 0;
@@ -69,9 +69,11 @@ public class LocalMessageBus extends MessageBusSupport {
protected static final Set<Object> CONSUMER_REQUEST_REPLY_PROPERTIES = new SetBuilder()
.addAll(CONSUMER_STANDARD_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
.build();
public static final String THREAD_NAME_PREFIX = "binder.local-";
private volatile PollerMetadata poller;
private final Map<String, ExecutorChannel> requestReplyChannels = new HashMap<String, ExecutorChannel>();
@@ -173,12 +175,12 @@ public class LocalMessageBus extends MessageBusSupport {
this.executor.setMaxPoolSize(this.executorMaxPoolSize);
this.executor.setQueueCapacity(this.executorQueueSize);
this.executor.setKeepAliveSeconds(this.executorKeepAliveSeconds);
this.executor.setThreadNamePrefix("xd.localbus-");
this.executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
this.executor.initialize();
}
/**
* For the local bus we bridge the router "output" channel to a queue channel; the queue
* For the local binder we bridge the router "output" channel to a queue channel; the queue
* channel gets the name and the source channel is named 'dynamic.output.to.' + name.
* {@inheritDoc}
*/
@@ -188,7 +190,7 @@ public class LocalMessageBus extends MessageBusSupport {
}
/**
* For the local bus we bridge the router "output" channel to a pub/sub channel; the pub/sub
* For the local binder we bridge the router "output" channel to a pub/sub channel; the pub/sub
* channel gets the name and the source channel is named 'dynamic.output.to.' + name.
* {@inheritDoc}
*/
@@ -230,7 +232,7 @@ public class LocalMessageBus extends MessageBusSupport {
MessageChannel registeredChannel = channelProvider.lookupOrCreateSharedChannel(name);
bridge(name, registeredChannel, moduleInputChannel,
"inbound." + ((NamedComponent) registeredChannel).getComponentName(),
new LocalBusPropertiesAccessor(properties));
new LocalBinderPropertiesAccessor(properties));
}
/**
@@ -257,7 +259,7 @@ public class LocalMessageBus extends MessageBusSupport {
MessageChannel registeredChannel = channelProvider.lookupOrCreateSharedChannel(name);
bridge(name, moduleOutputChannel, registeredChannel,
"outbound." + ((NamedComponent) registeredChannel).getComponentName(),
new LocalBusPropertiesAccessor(properties));
new LocalBinderPropertiesAccessor(properties));
}
@Override
@@ -326,8 +328,8 @@ public class LocalMessageBus extends MessageBusSupport {
private ThreadPoolTaskExecutor createRequestReplyExecutor(String name, Properties properties) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(new LocalBusPropertiesAccessor(properties).getConcurrency(DEFAULT_REQ_REPLY_CONCURRENCY));
executor.setThreadNamePrefix("xd.localBus." + name + "-");
executor.setCorePoolSize(new LocalBinderPropertiesAccessor(properties).getConcurrency(DEFAULT_REQ_REPLY_CONCURRENCY));
executor.setThreadNamePrefix(THREAD_NAME_PREFIX + name + "-");
executor.initialize();
return executor;
}
@@ -346,13 +348,13 @@ public class LocalMessageBus extends MessageBusSupport {
}
protected BridgeHandler bridge(String name, MessageChannel from, MessageChannel to, String bridgeName,
LocalBusPropertiesAccessor properties) {
LocalBinderPropertiesAccessor properties) {
return bridge(name, from, to, bridgeName, null, properties);
}
protected BridgeHandler bridge(String name, MessageChannel from, MessageChannel to, String bridgeName,
final Collection<MimeType> acceptedMimeTypes, LocalBusPropertiesAccessor properties) {
final Collection<MimeType> acceptedMimeTypes, LocalBinderPropertiesAccessor properties) {
final boolean isInbound = bridgeName.startsWith("inbound.");
@@ -407,9 +409,9 @@ public class LocalMessageBus extends MessageBusSupport {
return getApplicationContext().getBean(name, requiredType);
}
private static class LocalBusPropertiesAccessor extends AbstractBusPropertiesAccessor {
private static class LocalBinderPropertiesAccessor extends AbstractBinderPropertiesAccessor {
public LocalBusPropertiesAccessor(Properties properties) {
public LocalBinderPropertiesAccessor(Properties properties) {
super(properties);
}

View File

@@ -4,7 +4,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageBus" class="org.springframework.xd.dirt.integration.bus.local.LocalMessageBus">
<bean id="messageBus" class="org.springframework.cloud.stream.binder.local.LocalMessageChannelBinder">
<property name="queueSize"
value="${xd.messagebus.local.queueSize: #{T(Integer).MAX_VALUE}}" />
<property name="poller">

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.local;
package org.springframework.cloud.stream.binder.local;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
@@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.cloud.stream.binder.AbstractBinderTests;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.integration.channel.DirectChannel;
@@ -39,8 +40,7 @@ import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.xd.dirt.integration.bus.AbstractMessageBusTests;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.cloud.stream.binder.Binder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -53,33 +53,33 @@ import static org.junit.Assert.assertTrue;
* @author David Turanski
* @since 1.0
*/
public class LocalMessageBusTests extends AbstractMessageBusTests {
public class LocalBinderTests extends AbstractBinderTests {
@Override
protected MessageBus getMessageBus() throws Exception {
LocalMessageBus bus = new LocalMessageBus();
protected Binder getBinder() throws Exception {
LocalMessageChannelBinder binder = new LocalMessageChannelBinder();
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.getBeanFactory().registerSingleton(
IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME,
new DefaultMessageBuilderFactory());
applicationContext.refresh();
bus.setApplicationContext(applicationContext);
bus.setExecutorCorePoolSize(2);
bus.setExecutorMaxPoolSize(10);
bus.setExecutorKeepAliveSeconds(59);
bus.setExecutorQueueSize(Integer.MAX_VALUE - 1);
bus.afterPropertiesSet();
return bus;
binder.setApplicationContext(applicationContext);
binder.setExecutorCorePoolSize(2);
binder.setExecutorMaxPoolSize(10);
binder.setExecutorKeepAliveSeconds(59);
binder.setExecutorQueueSize(Integer.MAX_VALUE - 1);
binder.afterPropertiesSet();
return binder;
}
protected Collection<?> getBindings(MessageBus testMessageBus) {
return getBindingsFromMsgBus(testMessageBus);
protected Collection<?> getBindings(Binder testBinder) {
return getBindingsFromBinder(testBinder);
}
@Test
public void testProps() throws Exception {
LocalMessageBus bus = (LocalMessageBus) getMessageBus();
ThreadPoolTaskExecutor exec = TestUtils.getPropertyValue(bus, "executor", ThreadPoolTaskExecutor.class);
LocalMessageChannelBinder binder = (LocalMessageChannelBinder) getBinder();
ThreadPoolTaskExecutor exec = TestUtils.getPropertyValue(binder, "executor", ThreadPoolTaskExecutor.class);
assertEquals(2, exec.getCorePoolSize());
assertEquals(10, exec.getMaxPoolSize());
assertEquals(59, exec.getKeepAliveSeconds());
@@ -88,29 +88,29 @@ public class LocalMessageBusTests extends AbstractMessageBusTests {
@Test
public void testPayloadConversionNotNeededExplicitType() throws Exception {
LocalMessageBus bus = (LocalMessageBus) getMessageBus();
verifyPayloadConversion(new TestPayload(), bus);
LocalMessageChannelBinder binder = (LocalMessageChannelBinder) getBinder();
verifyPayloadConversion(new TestPayload(), binder);
}
@Test
public void testNoPayloadConversionByDefault() throws Exception {
LocalMessageBus bus = (LocalMessageBus) getMessageBus();
verifyPayloadConversion(new TestPayload(), bus);
LocalMessageChannelBinder binder = (LocalMessageChannelBinder) getBinder();
verifyPayloadConversion(new TestPayload(), binder);
}
@Test
public void testTapDoesntHurtStream() throws Exception {
LocalMessageBus bus = (LocalMessageBus) getMessageBus();
LocalMessageChannelBinder binder = (LocalMessageChannelBinder) getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
moduleOutputChannel.setBeanName("bangOut");
DirectChannel tapChannel = new DirectChannel();
tapChannel.setBeanName("tapChannel");
WireTap tap = new WireTap(tapChannel);
moduleOutputChannel.addInterceptor(tap);
bus.bindProducer("bang.0", moduleOutputChannel, null);
binder.bindProducer("bang.0", moduleOutputChannel, null);
final AtomicBoolean messageReceived = new AtomicBoolean();
final AtomicReference<Thread> streamThread = new AtomicReference<Thread>();
bus.bindConsumer("bang.0", new DirectChannel() {
binder.bindConsumer("bang.0", new DirectChannel() {
@Override
protected boolean doSend(Message<?> message, long timeout) {
@@ -121,8 +121,8 @@ public class LocalMessageBusTests extends AbstractMessageBusTests {
}, null);
final CountDownLatch tapped = new CountDownLatch(1);
final AtomicReference<Thread> tapThread = new AtomicReference<Thread>();
bus.bindPubSubProducer("tap:stream:bang.0", tapChannel, null);
bus.bindPubSubConsumer("tap:stream:bang.0", new DirectChannel() {
binder.bindPubSubProducer("tap:stream:bang.0", tapChannel, null);
binder.bindPubSubConsumer("tap:stream:bang.0", new DirectChannel() {
@Override
protected boolean doSend(Message<?> message, long timeout) {
@@ -139,10 +139,10 @@ public class LocalMessageBusTests extends AbstractMessageBusTests {
assertNotSame(Thread.currentThread(), tapThread.get());
}
private void verifyPayloadConversion(final Object expectedValue, final LocalMessageBus bus) {
private void verifyPayloadConversion(final Object expectedValue, final LocalMessageChannelBinder binder) {
DirectChannel myChannel = new DirectChannel();
bus.bindConsumer("in", myChannel, null);
DirectChannel input = bus.getBean("in", DirectChannel.class);
binder.bindConsumer("in", myChannel, null);
DirectChannel input = binder.getBean("in", DirectChannel.class);
assertNotNull(input);
final AtomicBoolean msgSent = new AtomicBoolean(false);

View File

@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-binding-rabbit</artifactId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-stream-binding-rabbit</name>
<description>RabbitMQ binding implementation</description>
<name>spring-cloud-stream-binder-rabbit</name>
<description>RabbitMQ binder implementation</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
@@ -21,11 +21,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-test</artifactId>
<artifactId>spring-cloud-stream-binder-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -16,7 +16,7 @@
*
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
@@ -30,7 +30,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
/**
* Configures the connection factory used by the rabbit message bus.
* Configures the connection factory used by the rabbit binder.
*
* @author Eric Bottard
* @author Gary Russell

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import java.net.URI;
import java.util.Arrays;
@@ -35,7 +35,7 @@ import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.xd.dirt.integration.bus.RabbitManagementUtils;
import org.springframework.cloud.stream.binder.RabbitManagementUtils;
/**

View File

@@ -13,7 +13,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import java.net.URI;
import java.util.ArrayList;
@@ -26,80 +26,54 @@ import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.xd.dirt.integration.bus.BusCleaner;
import org.springframework.xd.dirt.integration.bus.BusUtils;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
import org.springframework.xd.dirt.integration.bus.RabbitAdminException;
import org.springframework.xd.dirt.integration.bus.RabbitManagementUtils;
import org.springframework.cloud.stream.binder.BinderCleaner;
import org.springframework.cloud.stream.binder.BinderUtils;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.cloud.stream.binder.RabbitAdminException;
import org.springframework.cloud.stream.binder.RabbitManagementUtils;
/**
* Implementation of {@link org.springframework.xd.dirt.integration.bus.BusCleaner} for the {@code RabbitMessageBus}.
* Implementation of {@link org.springframework.cloud.stream.binder.BinderCleaner} for the {@code RabbitBinder}.
* @author Gary Russell
* @author David Turanski
* @since 1.2
*/
public class RabbitBusCleaner implements BusCleaner {
public class RabbitBinderCleaner implements BinderCleaner {
private final static Logger logger = LoggerFactory.getLogger(RabbitBusCleaner.class);
private final static Logger logger = LoggerFactory.getLogger(RabbitBinderCleaner.class);
public static final String BINDER_PREFIX = "binder.rabbit.";
@Override
public Map<String, List<String>> clean(String entity, boolean isJob) {
return clean("http://localhost:15672", "guest", "guest", "/", "xdbus.", entity, isJob);
return clean("http://localhost:15672", "guest", "guest", "/", BINDER_PREFIX , entity, isJob);
}
public Map<String, List<String>> clean(String adminUri, String user, String pw, String vhost,
String busPrefix, String entity, boolean isJob) {
String binderPrefix, String entity, boolean isJob) {
return doClean(
adminUri == null ? "http://localhost:15672" : adminUri,
user == null ? "guest" : user,
pw == null ? "guest" : pw,
vhost == null ? "/" : vhost,
busPrefix == null ? "xdbus." : busPrefix,
//TODO: Change prefix
binderPrefix == null ? BINDER_PREFIX : binderPrefix,
entity, isJob);
}
private Map<String, List<String>> doClean(String adminUri, String user, String pw, String vhost,
String busPrefix, String entity, boolean isJob) {
String binderPrefix, String entity, boolean isJob) {
RestTemplate restTemplate = RabbitManagementUtils.buildRestTemplate(adminUri, user, pw);
List<String> removedQueues = isJob
? null//findJobQueues(adminUri, vhost, busPrefix, entity, restTemplate)
: findStreamQueues(adminUri, vhost, busPrefix, entity, restTemplate);
? null
: findStreamQueues(adminUri, vhost, binderPrefix, entity, restTemplate);
ExchangeCandidateCallback callback = null;
if (isJob) {
// String pattern;
// if (entity.endsWith("*")) {
// pattern = entity.substring(0, entity.length() - 1) + "[^.]*";
// }
// else {
// pattern = entity;
// }
// Collection<String> exchangeNames = JobEventsListenerPlugin.getEventListenerChannels(pattern).values();
// final Set<Pattern> jobExchanges = new HashSet<>();
// for (String exchange : exchangeNames) {
// jobExchanges.add(Pattern.compile(MessageBusSupport.applyPrefix(busPrefix,
// MessageBusSupport.applyPubSub(exchange))));
// }
// jobExchanges.add(Pattern.compile(MessageBusSupport.applyPrefix(busPrefix, MessageBusSupport.applyPubSub(
// JobEventsListenerPlugin.getEventListenerChannelName(pattern)))));
// callback = new ExchangeCandidateCallback() {
//
// @Override
// public boolean isCandidate(String exchangeName) {
// for (Pattern pattern : jobExchanges) {
// Matcher matcher = pattern.matcher(exchangeName);
// if (matcher.matches()) {
// return true;
// }
// }
// return false;
// }
//
// };
}
else {
final String tapPrefix = adjustPrefix(MessageBusSupport.applyPrefix(busPrefix,
MessageBusSupport.applyPubSub(BusUtils.constructTapPrefix(entity))));
final String tapPrefix = adjustPrefix(MessageChannelBinderSupport.applyPrefix(binderPrefix,
MessageChannelBinderSupport.applyPubSub(BinderUtils.constructTapPrefix(entity))));
callback = new ExchangeCandidateCallback() {
@Override
@@ -108,7 +82,7 @@ public class RabbitBusCleaner implements BusCleaner {
}
};
}
List<String> removedExchanges = findExchanges(adminUri, vhost, busPrefix, entity, restTemplate, callback);
List<String> removedExchanges = findExchanges(adminUri, vhost, binderPrefix, entity, restTemplate, callback);
// Delete the queues in reverse order to enable re-running after a partial success.
// The queue search above starts with 0 and terminates on a not found.
for (int i = removedQueues.size() - 1; i >= 0; i--) {
@@ -141,9 +115,9 @@ public class RabbitBusCleaner implements BusCleaner {
return results;
}
private List<String> findStreamQueues(String adminUri, String vhost, String busPrefix, String stream,
private List<String> findStreamQueues(String adminUri, String vhost, String binderPrefix, String stream,
RestTemplate restTemplate) {
String queueNamePrefix = adjustPrefix(MessageBusSupport.applyPrefix(busPrefix, stream));
String queueNamePrefix = adjustPrefix(MessageChannelBinderSupport.applyPrefix(binderPrefix, stream));
List<Map<String, Object>> queues = listAllQueues(adminUri, vhost, restTemplate);
List<String> removedQueues = new ArrayList<>();
for (Map<String, Object> queue : queues) {
@@ -156,37 +130,6 @@ public class RabbitBusCleaner implements BusCleaner {
return removedQueues;
}
// private List<String> findJobQueues(String adminUri, String vhost, String busPrefix, String job,
// RestTemplate restTemplate) {
// List<String> removedQueues = new ArrayList<>();
// String jobQueueName = MessageBusSupport.applyPrefix(busPrefix,
// AbstractJobPlugin.getJobChannelName(job));
// String jobRequestsQueuePrefix = adjustPrefix(MessageBusSupport.applyPrefix(busPrefix,
// AbstractJobPlugin.getJobChannelName(job)));
// List<Map<String, Object>> queues = listAllQueues(adminUri, vhost, restTemplate);
// for (Map<String, Object> queue : queues) {
// String queueName = (String) queue.get("name");
// if (job.endsWith("*")) {
// if (queueName.startsWith(jobQueueName.substring(0, jobQueueName.length() - 1))) {
// checkNoConsumers(queueName, queue);
// removedQueues.add(queueName);
// }
// }
// else {
// if (queueName.equals(jobQueueName)) {
// checkNoConsumers(queueName, queue);
// removedQueues.add(queueName);
// }
// else if (queueName.startsWith(jobRequestsQueuePrefix)
// && queueName.endsWith(MessageBusSupport.applyRequests(""))) {
// checkNoConsumers(queueName, queue);
// removedQueues.add(queueName);
// }
// }
// }
// return removedQueues;
// }
private List<Map<String, Object>> listAllQueues(String adminUri, String vhost, RestTemplate restTemplate) {
URI uri = UriComponentsBuilder.fromUriString(adminUri + "/api")
.pathSegment("queues", "{vhost}")
@@ -201,7 +144,7 @@ public class RabbitBusCleaner implements BusCleaner {
return prefix.substring(0, prefix.length() - 1);
}
else {
return prefix + BusUtils.GROUP_INDEX_DELIMITER;
return prefix + BinderUtils.GROUP_INDEX_DELIMITER;
}
}
@@ -212,7 +155,7 @@ public class RabbitBusCleaner implements BusCleaner {
}
@SuppressWarnings("unchecked")
private List<String> findExchanges(String adminUri, String vhost, String busPrefix, String entity,
private List<String> findExchanges(String adminUri, String vhost, String binderPrefix, String entity,
RestTemplate restTemplate, ExchangeCandidateCallback callback) {
List<String> removedExchanges = new ArrayList<>();
URI uri = UriComponentsBuilder.fromUriString(adminUri + "/api")

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import java.io.IOException;
import java.util.Arrays;
@@ -84,13 +84,12 @@ import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.integration.bus.AbstractBusPropertiesAccessor;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.BusUtils;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
import org.springframework.xd.dirt.integration.bus.MessageValues;
import org.springframework.cloud.stream.binder.AbstractBinderPropertiesAccessor;
import org.springframework.cloud.stream.binder.BinderUtils;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.cloud.stream.binder.MessageValues;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
import com.rabbitmq.client.AMQP;
@@ -98,7 +97,7 @@ import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Envelope;
/**
* A {@link MessageBus} implementation backed by RabbitMQ.
* A {@link org.springframework.cloud.stream.binder.Binder} implementation backed by RabbitMQ.
* @author Mark Fisher
* @author Gary Russell
* @author Jennifer Hickey
@@ -106,7 +105,7 @@ import com.rabbitmq.client.Envelope;
* @author Ilayaperumal Gopinathan
* @author David Turanski
*/
public class RabbitMessageBus extends MessageBusSupport implements DisposableBean {
public class RabbitMessageChannelBinder extends MessageChannelBinderSupport implements DisposableBean {
private static final AcknowledgeMode DEFAULT_ACKNOWLEDGE_MODE = AcknowledgeMode.AUTO;
@@ -118,7 +117,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private static final int DEFAULT_PREFETCH_COUNT = 1;
private static final String DEFAULT_RABBIT_PREFIX = "xdbus.";
private static final String DEFAULT_RABBIT_PREFIX = "binder.rabbit.";
private static final int DEFAULT_TX_SIZE = 1;
@@ -130,7 +129,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private static final Set<Object> RABBIT_CONSUMER_PROPERTIES = new HashSet<Object>(Arrays.asList(new String[] {
BusProperties.MAX_CONCURRENCY,
BinderProperties.MAX_CONCURRENCY,
RabbitPropertiesAccessor.ACK_MODE,
RabbitPropertiesAccessor.PREFETCH,
RabbitPropertiesAccessor.PREFIX,
@@ -153,7 +152,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private static final Set<Object> SUPPORTED_PUBSUB_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BusProperties.DURABLE)
.add(BinderProperties.DURABLE)
.build();
/**
@@ -161,7 +160,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
*/
private static final Set<Object> SUPPORTED_NAMED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
.build();
/**
@@ -169,8 +168,8 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
*/
private static final Set<Object> SUPPORTED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BusProperties.PARTITION_INDEX)
.add(BinderProperties.CONCURRENCY)
.add(BinderProperties.PARTITION_INDEX)
.build();
/**
@@ -179,7 +178,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private static final Set<Object> SUPPORTED_REPLYING_CONSUMER_PROPERTIES = new SetBuilder()
// request
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
// reply
.add(RabbitPropertiesAccessor.REPLY_HEADER_PATTERNS)
.add(RabbitPropertiesAccessor.DELIVERY_MODE)
@@ -193,7 +192,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
.add(RabbitPropertiesAccessor.DELIVERY_MODE)
.add(RabbitPropertiesAccessor.PREFIX)
.add(RabbitPropertiesAccessor.REQUEST_HEADER_PATTERNS)
.add(BusProperties.COMPRESS)
.add(BinderProperties.COMPRESS)
.build();
private static final Set<Object> SUPPORTED_PUBSUB_PRODUCER_PROPERTIES = new SetBuilder()
@@ -214,7 +213,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private static final Set<Object> SUPPORTED_PRODUCER_PROPERTIES = new SetBuilder()
.addAll(PRODUCER_PARTITIONING_PROPERTIES)
.addAll(SUPPORTED_BASIC_PRODUCER_PROPERTIES)
.add(BusProperties.DIRECT_BINDING_ALLOWED)
.add(BinderProperties.DIRECT_BINDING_ALLOWED)
.addAll(PRODUCER_BATCHING_BASIC_PROPERTIES)
.addAll(PRODUCER_BATCHING_ADVANCED_PROPERTIES)
.build();
@@ -227,7 +226,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
.addAll(SUPPORTED_BASIC_PRODUCER_PROPERTIES)
// reply
.addAll(SUPPORTED_BASIC_CONSUMER_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
.add(RabbitPropertiesAccessor.REPLY_HEADER_PATTERNS)
.build();
@@ -303,7 +302,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private volatile boolean clustered;
public RabbitMessageBus(ConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
public RabbitMessageChannelBinder(ConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
Assert.notNull(connectionFactory, "connectionFactory must not be null");
Assert.notNull(codec, "codec must not be null");
this.connectionFactory = connectionFactory;
@@ -353,7 +352,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
}
/**
* Set the bus's default max consumers; can be overridden by consumer.maxConcurrency. Values less than 'concurrency'
* Set the binder's default max consumers; can be overridden by consumer.maxConcurrency. Values less than 'concurrency'
* will be coerced to be equal to concurrency.
* @param defaultMaxConcurrency The default max concurrency.
*/
@@ -464,7 +463,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
@Override
public void bindPubSubConsumer(String name, MessageChannel moduleInputChannel, Properties properties) {
String exchangeName = BusUtils.removeGroupFromPubSub(name);
String exchangeName = BinderUtils.removeGroupFromPubSub(name);
if (logger.isInfoEnabled()) {
logger.info("declaring pubsub for inbound: " + name + ", bound to: " + exchangeName);
}
@@ -550,7 +549,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
listenerContainer.setAdviceChain(new Advice[] { retryInterceptor });
}
listenerContainer.setAfterReceivePostProcessors(this.decompressingPostProcessor);
listenerContainer.setMessagePropertiesConverter(RabbitMessageBus.inboundMessagePropertiesConverter);
listenerContainer.setMessagePropertiesConverter(RabbitMessageChannelBinder.inboundMessagePropertiesConverter);
listenerContainer.afterPropertiesSet();
AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer);
adapter.setBeanFactory(this.getBeanFactory());
@@ -768,7 +767,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
channel.exchangeDeclarePassive(exchange.getName());
}
catch (IOException e) {
RabbitMessageBus.this.rabbitAdmin.declareExchange(exchange);
RabbitMessageChannelBinder.this.rabbitAdmin.declareExchange(exchange);
}
return null;
}
@@ -874,7 +873,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
this.delegate = delegate;
this.replyTo = replyTo;
this.partitioningMetadata = new PartitioningMetadata(properties, properties.getNextModuleCount());
this.setBeanFactory(RabbitMessageBus.this.getBeanFactory());
this.setBeanFactory(RabbitMessageChannelBinder.this.getBeanFactory());
}
@Override
@@ -921,7 +920,7 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
public ReceivingHandler() {
super();
this.setBeanFactory(RabbitMessageBus.this.getBeanFactory());
this.setBeanFactory(RabbitMessageChannelBinder.this.getBeanFactory());
}
@Override
@@ -941,10 +940,10 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
}
/**
* Property accessor for the RabbitMessageBus. Refer to the Spring-AMQP documentation for information on the
* Property accessor for the RabbitBinder. Refer to the Spring-AMQP documentation for information on the
* specific properties.
*/
private static class RabbitPropertiesAccessor extends AbstractBusPropertiesAccessor {
private static class RabbitPropertiesAccessor extends AbstractBinderPropertiesAccessor {
/**
* The acknowledge mode.
@@ -992,12 +991,12 @@ public class RabbitMessageBus extends MessageBusSupport implements DisposableBea
private static final String TX_SIZE = "txSize";
/**
* Whether to automatically declare the DLQ and bind it to the bus DLX.
* Whether to automatically declare the DLQ and bind it to the binder DLX.
*/
private static final String AUTO_BIND_DLQ = "autoBindDLQ";
/**
* Whether to automatically declare the DLQ and bind it to the bus DLX.
* Whether to automatically declare the DLQ and bind it to the binder DLX.
*/
private static final String REPUBLISH_TO_DLQ = "republishToDLQ";

View File

@@ -0,0 +1,5 @@
/**
* This package contains an implementation of the {@link org.springframework.cloud.stream.binder.Binder} for RabbitMQ.
*/
package org.springframework.cloud.stream.binder.rabbit;

View File

@@ -5,9 +5,9 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.xd.dirt.integration.rabbit.ConnectionFactorySettings" />
<bean class="org.springframework.cloud.stream.binder.rabbit.ConnectionFactorySettings" />
<bean id="messageBus" class="org.springframework.xd.dirt.integration.rabbit.RabbitMessageBus">
<bean id="messageBus" class="org.springframework.cloud.stream.binder.rabbit.RabbitMessageChannelBinder">
<constructor-arg ref="rabbitConnectionFactory" />
<constructor-arg ref="codec"/>
<property name="defaultAcknowledgeMode" value="#{T(org.springframework.amqp.core.AcknowledgeMode).${xd.messagebus.rabbit.default.ackMode}}" />

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;

View File

@@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.xd.test.AbstractExternalResourceTestSupport;
import org.springframework.cloud.stream.binder.AbstractExternalResourceTestSupport;
import java.util.Map;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import java.net.URI;
@@ -37,10 +37,10 @@ import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.xd.dirt.integration.bus.BusUtils;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
import org.springframework.xd.dirt.integration.bus.RabbitAdminException;
import org.springframework.xd.dirt.integration.bus.RabbitManagementUtils;
import org.springframework.cloud.stream.binder.BinderUtils;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.cloud.stream.binder.RabbitAdminException;
import org.springframework.cloud.stream.binder.RabbitManagementUtils;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
@@ -52,9 +52,9 @@ import static org.junit.Assert.fail;
* @author Gary Russell
* @since 1.2
*/
public class RabbitBusCleanerTests {
public class RabbitBinderCleanerTests {
private static final String XDBUS_PREFIX = "xdbus.";
private static final String BINDER_PREFIX = "binder.rabbit.";
@Rule
public RabbitAdminTestSupport adminTest = new RabbitAdminTestSupport();
@@ -64,17 +64,17 @@ public class RabbitBusCleanerTests {
@Test
public void testCleanStream() {
final RabbitBusCleaner cleaner = new RabbitBusCleaner();
final RabbitBinderCleaner cleaner = new RabbitBinderCleaner();
final RestTemplate template = RabbitManagementUtils.buildRestTemplate("http://localhost:15672", "guest",
"guest");
final String stream1 = UUID.randomUUID().toString();
String stream2 = stream1 + "-1";
String firstQueue = null;
for (int i = 0; i < 5; i++) {
String queue1Name = MessageBusSupport.applyPrefix(XDBUS_PREFIX,
BusUtils.constructPipeName(stream1, i));
String queue2Name = MessageBusSupport.applyPrefix(XDBUS_PREFIX,
BusUtils.constructPipeName(stream2, i));
String queue1Name = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX,
BinderUtils.constructPipeName(stream1, i));
String queue2Name = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX,
BinderUtils.constructPipeName(stream2, i));
if (firstQueue == null) {
firstQueue = queue1Name;
}
@@ -90,27 +90,27 @@ public class RabbitBusCleanerTests {
template.put(uri, new AmqpQueue(false, true));
uri = UriComponentsBuilder.fromUriString("http://localhost:15672/api/queues")
.pathSegment("{vhost}", "{queue}")
.buildAndExpand("/", MessageBusSupport.constructDLQName(queue1Name)).encode().toUri();
.buildAndExpand("/", MessageChannelBinderSupport.constructDLQName(queue1Name)).encode().toUri();
template.put(uri, new AmqpQueue(false, true));
}
CachingConnectionFactory connectionFactory = test.getResource();
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
final FanoutExchange fanout1 = new FanoutExchange(
MessageBusSupport.applyPrefix(XDBUS_PREFIX, MessageBusSupport.applyPubSub(
BusUtils.constructTapPrefix(stream1) + ".foo.bar")));
MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, MessageChannelBinderSupport.applyPubSub(
BinderUtils.constructTapPrefix(stream1) + ".foo.bar")));
rabbitAdmin.declareExchange(fanout1);
rabbitAdmin.declareBinding(BindingBuilder.bind(new Queue(firstQueue)).to(fanout1));
final FanoutExchange fanout2 = new FanoutExchange(
MessageBusSupport.applyPrefix(XDBUS_PREFIX, MessageBusSupport.applyPubSub(
BusUtils.constructTapPrefix(stream2) + ".foo.bar")));
MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX, MessageChannelBinderSupport.applyPubSub(
BinderUtils.constructTapPrefix(stream2) + ".foo.bar")));
rabbitAdmin.declareExchange(fanout2);
rabbitAdmin.declareBinding(BindingBuilder.bind(new Queue(firstQueue)).to(fanout2));
new RabbitTemplate(connectionFactory).execute(new ChannelCallback<Void>() {
@Override
public Void doInRabbit(Channel channel) throws Exception {
String queueName = MessageBusSupport.applyPrefix(XDBUS_PREFIX,
BusUtils.constructPipeName(stream1, 4));
String queueName = MessageChannelBinderSupport.applyPrefix(BINDER_PREFIX,
BinderUtils.constructPipeName(stream1, 4));
String consumerTag = channel.basicConsume(queueName, new DefaultConsumer(channel));
try {
waitForConsumerStateNot(queueName, 0);
@@ -159,8 +159,8 @@ public class RabbitBusCleanerTests {
// should *not* clean stream2
assertEquals(10, cleanedQueues.size());
for (int i = 0; i < 5; i++) {
assertEquals(XDBUS_PREFIX + stream1 + "." + i, cleanedQueues.get(i * 2));
assertEquals(XDBUS_PREFIX + stream1 + "." + i + ".dlq", cleanedQueues.get(i * 2 + 1));
assertEquals(BINDER_PREFIX + stream1 + "." + i, cleanedQueues.get(i * 2));
assertEquals(BINDER_PREFIX + stream1 + "." + i + ".dlq", cleanedQueues.get(i * 2 + 1));
}
List<String> cleanedExchanges = cleanedMap.get("exchanges");
assertEquals(1, cleanedExchanges.size());
@@ -172,7 +172,7 @@ public class RabbitBusCleanerTests {
cleanedQueues = cleanedMap.get("queues");
assertEquals(5, cleanedQueues.size());
for (int i = 0; i < 5; i++) {
assertEquals(XDBUS_PREFIX + stream2 + "." + i, cleanedQueues.get(i));
assertEquals(BINDER_PREFIX + stream2 + "." + i, cleanedQueues.get(i));
}
cleanedExchanges = cleanedMap.get("exchanges");
assertEquals(1, cleanedExchanges.size());

View File

@@ -14,22 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
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.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
package org.springframework.cloud.stream.binder.rabbit;
import java.util.Collection;
import java.util.HashMap;
@@ -56,6 +41,11 @@ 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.cloud.stream.binder.Binder;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.PartitionCapableBinderTests;
import org.springframework.cloud.stream.binder.Spy;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -66,27 +56,43 @@ import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.PartitionCapableBusTests;
import org.springframework.xd.dirt.integration.bus.Spy;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
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.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Mark Fisher
* @author Gary Russell
*/
public class RabbitMessageBusTests extends PartitionCapableBusTests {
public class RabbitBinderTests extends PartitionCapableBinderTests {
private final String CLASS_UNDER_TEST_NAME = RabbitMessageChannelBinder.class.getSimpleName();
public static final String BINDER_PREFIX = "binder.rabbit.";
public static final String TEST_PREFIX = "bindertest.";
@Rule
public RabbitTestSupport rabbitAvailableRule = new RabbitTestSupport();
@Override
protected MessageBus getMessageBus() {
if (testMessageBus == null) {
testMessageBus = new RabbitTestMessageBus(rabbitAvailableRule.getResource(), getCodec());
protected Binder getBinder() {
if (testBinder == null) {
testBinder = new RabbitTestBinder(rabbitAvailableRule.getResource(), getCodec());
}
return testMessageBus;
return testBinder;
}
@Override
@@ -96,12 +102,13 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
@Test
public void testSendAndReceiveBad() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
DirectChannel moduleInputChannel = new DirectChannel();
messageBus.bindProducer("bad.0", moduleOutputChannel, null);
messageBus.bindConsumer("bad.0", moduleInputChannel, null);
Message<?> message = MessageBuilder.withPayload("bad").setHeader(MessageHeaders.CONTENT_TYPE, "foo/bar").build();
binder.bindProducer("bad.0", moduleOutputChannel, null);
binder.bindConsumer("bad.0", moduleInputChannel, null);
Message<?> message = MessageBuilder.withPayload("bad").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
final CountDownLatch latch = new CountDownLatch(3);
moduleInputChannel.subscribe(new MessageHandler() {
@@ -113,24 +120,24 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
});
moduleOutputChannel.send(message);
assertTrue(latch.await(10, TimeUnit.SECONDS));
messageBus.unbindConsumers("bad.0");
messageBus.unbindProducers("bad.0");
binder.unbindConsumers("bad.0");
binder.unbindProducers("bad.0");
}
@Test
public void testConsumerProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("transacted", "true"); // test transacted with defaults; not allowed with ackmode NONE
bus.bindConsumer("props.0", new DirectChannel(), properties);
binder.bindConsumer("props.0", new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> 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("xdbus.props.0", container.getQueueNames()[0]);
assertEquals(BINDER_PREFIX + "props.0", container.getQueueNames()[0]);
assertTrue(TestUtils.getPropertyValue(container, "transactional", Boolean.class));
assertEquals(1, TestUtils.getPropertyValue(container, "concurrentConsumers"));
assertNull(TestUtils.getPropertyValue(container, "maxConcurrentConsumers"));
@@ -142,7 +149,7 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
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");
binder.unbindConsumers("props.0");
assertEquals(0, bindings.size());
properties = new Properties();
@@ -159,10 +166,10 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
properties.put("requeue", "false");
properties.put("txSize", "10");
properties.put("partitionIndex", 0);
bus.bindConsumer("props.0", new DirectChannel(), properties);
binder.bindConsumer("props.0", new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindingsNow = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindingsNow = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindingsNow.size());
endpoint = bindingsNow.get(0).getEndpoint();
container = verifyContainer(endpoint);
@@ -170,45 +177,45 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
assertEquals("foo.props.0", container.getQueueNames()[0]);
try {
bus.bindPubSubConsumer("dummy", null, properties);
binder.bindPubSubConsumer("dummy", null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RabbitMessageBus does not support consumer properties: "),
containsString(getClassUnderTestName() + " does not support consumer properties: "),
containsString("partitionIndex"),
containsString("concurrency"),
containsString(" for dummy.")));
}
try {
bus.bindConsumer("queue:dummy", null, properties);
binder.bindConsumer("queue:dummy", null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertEquals("RabbitMessageBus does not support consumer property: partitionIndex for queue:dummy.",
assertEquals(getClassUnderTestName() + " does not support consumer property: partitionIndex for queue:dummy.",
e.getMessage());
}
bus.unbindConsumers("props.0");
binder.unbindConsumers("props.0");
assertEquals(0, bindingsNow.size());
}
@Test
public void testProducerProperties() throws Exception {
MessageBus bus = getMessageBus();
bus.bindProducer("props.0", new DirectChannel(), null);
Binder binder = getBinder();
binder.bindProducer("props.0", new DirectChannel(), null);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
assertEquals("xdbus.props.0", TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKey"));
assertEquals(BINDER_PREFIX + "props.0", TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKey"));
MessageDeliveryMode mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
MessageDeliveryMode.class);
assertEquals(MessageDeliveryMode.PERSISTENT, mode);
List<?> requestHeaders = TestUtils.getPropertyValue(endpoint,
"handler.delegate.headerMapper.requestHeaderMatcher.strategies", List.class);
assertEquals(2, requestHeaders.size());
bus.unbindProducers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
Properties properties = new Properties();
@@ -219,26 +226,27 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BusProperties.NEXT_MODULE_COUNT, "1");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "1");
bus.bindProducer("props.0", new DirectChannel(), properties);
binder.bindProducer("props.0", new DirectChannel(), properties);
assertEquals(1, bindings.size());
endpoint = bindings.get(0).getEndpoint();
assertEquals(
"'foo.props.0-' + headers['partition']",
TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression", SpelExpression.class).getExpressionString());
TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression",
SpelExpression.class).getExpressionString());
mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
MessageDeliveryMode.class);
assertEquals(MessageDeliveryMode.NON_PERSISTENT, mode);
verifyFooRequestProducer(endpoint);
try {
bus.bindPubSubProducer("dummy", new DirectChannel(), properties);
binder.bindPubSubProducer("dummy", new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RabbitMessageBus does not support producer properties: "),
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -246,12 +254,12 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), containsString("for dummy."));
}
try {
bus.bindProducer("queue:dummy", new DirectChannel(), properties);
binder.bindProducer("queue:dummy", new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RabbitMessageBus does not support producer properties: "),
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -259,13 +267,13 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), containsString("for queue:dummy."));
}
bus.unbindProducers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testRequestReplyRequestorProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "foo.");
properties.put("deliveryMode", "NON_PERSISTENT");
@@ -285,9 +293,9 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
properties.put("requeue", "false");
properties.put("txSize", "10");
bus.bindRequestor("props.0", new DirectChannel(), new DirectChannel(), properties);
binder.bindRequestor("props.0", new DirectChannel(), new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(2, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint(); // producer
@@ -308,15 +316,15 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BusProperties.NEXT_MODULE_COUNT, "1");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "1");
properties.put("partitionIndex", "0");
try {
bus.bindRequestor("dummy", null, null, properties);
binder.bindRequestor("dummy", null, null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RabbitMessageBus does not support producer properties: "),
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -324,14 +332,14 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), allOf(containsString("partitionIndex"), containsString("for dummy.")));
}
bus.unbindConsumers("props.0");
bus.unbindProducers("props.0");
binder.unbindConsumers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testRequestReplyReplierProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "foo.");
properties.put("deliveryMode", "NON_PERSISTENT");
@@ -351,15 +359,16 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
properties.put("requeue", "false");
properties.put("txSize", "10");
bus.bindReplier("props.0", new DirectChannel(), new DirectChannel(), properties);
binder.bindReplier("props.0", new DirectChannel(), new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
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());
TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression",
SpelExpression.class).getExpressionString());
MessageDeliveryMode mode = TestUtils.getPropertyValue(endpoint, "handler.delegate.defaultDeliveryMode",
MessageDeliveryMode.class);
assertEquals(MessageDeliveryMode.NON_PERSISTENT, mode);
@@ -376,15 +385,15 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BusProperties.NEXT_MODULE_COUNT, "1");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "1");
properties.put("partitionIndex", "0");
try {
bus.bindReplier("dummy", null, null, properties);
binder.bindReplier("dummy", null, null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RabbitMessageBus does not support consumer properties: "),
containsString(getClassUnderTestName() + " does not support consumer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -392,8 +401,8 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), allOf(containsString("partitionIndex"), containsString("for dummy.")));
}
bus.unbindConsumers("props.0");
bus.unbindProducers("props.0");
binder.unbindConsumers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@@ -401,9 +410,10 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
public void testDurablePubSubWithAutoBindDLQ() throws Exception {
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "xdbustest.");
properties.put("prefix", TEST_PREFIX);
properties.put("autoBindDLQ", "true");
properties.put("durableSubscription", "true");
properties.put("maxAttempts", "1"); // disable retry
@@ -418,14 +428,14 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
});
bus.bindPubSubConsumer("teststream.tap:stream:durabletest.0", moduleInputChannel, properties);
binder.bindPubSubConsumer("teststream.tap:stream:durabletest.0", moduleInputChannel, properties);
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.convertAndSend("xdbustest.topic.tap:stream:durabletest.0", "", "foo");
template.convertAndSend(TEST_PREFIX + "topic.tap:stream:durabletest.0", "", "foo");
int n = 0;
while (n++ < 100) {
Object deadLetter = template.receiveAndConvert("xdbustest.teststream.tap:stream:durabletest.0.dlq");
Object deadLetter = template.receiveAndConvert(TEST_PREFIX + "teststream.tap:stream:durabletest.0.dlq");
if (deadLetter != null) {
assertEquals("foo", deadLetter);
break;
@@ -434,21 +444,21 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
assertTrue(n < 100);
bus.unbindConsumer("teststream.tap:stream:durabletest.0", moduleInputChannel);
assertNotNull(admin.getQueueProperties("xdbustest.teststream.tap:stream:durabletest.0.dlq"));
admin.deleteQueue("xdbustest.teststream.tap:stream:durabletest.0.dlq");
admin.deleteQueue("xdbustest.teststream.tap:stream:durabletest.0");
admin.deleteExchange("xdbustest.topic.tap:stream:durabletest.0");
admin.deleteExchange("xdbustest.DLX");
binder.unbindConsumer("teststream.tap:stream:durabletest.0", moduleInputChannel);
assertNotNull(admin.getQueueProperties(TEST_PREFIX + "teststream.tap:stream:durabletest.0.dlq"));
admin.deleteQueue(TEST_PREFIX + "teststream.tap:stream:durabletest.0.dlq");
admin.deleteQueue(TEST_PREFIX + "teststream.tap:stream:durabletest.0");
admin.deleteExchange(TEST_PREFIX + "topic.tap:stream:durabletest.0");
admin.deleteExchange(TEST_PREFIX + "DLX");
}
@Test
public void testNonDurablePubSubWithAutoBindDLQ() throws Exception {
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "xdbustest.");
properties.put("prefix", TEST_PREFIX);
properties.put("autoBindDLQ", "true");
properties.put("durableSubscription", "false");
properties.put("maxAttempts", "1"); // disable retry
@@ -463,21 +473,21 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
});
bus.bindPubSubConsumer("teststream.tap:stream:nondurabletest.0", moduleInputChannel, properties);
binder.bindPubSubConsumer("teststream.tap:stream:nondurabletest.0", moduleInputChannel, properties);
bus.unbindConsumer("teststream.tap:stream:nondurabletest.0", moduleInputChannel);
assertNull(admin.getQueueProperties("xdbustest.teststream.tap:stream:nondurabletest.0.dlq"));
admin.deleteQueue("xdbustest.teststream.tap:stream:nondurabletest.0");
admin.deleteExchange("xdbustest.topic.tap:stream:nondurabletest.0");
binder.unbindConsumer("teststream.tap:stream:nondurabletest.0", moduleInputChannel);
assertNull(admin.getQueueProperties(TEST_PREFIX + "teststream.tap:stream:nondurabletest.0.dlq"));
admin.deleteQueue(TEST_PREFIX + "teststream.tap:stream:nondurabletest.0");
admin.deleteExchange(TEST_PREFIX + "topic.tap:stream:nondurabletest.0");
}
@Test
public void testAutoBindDLQ() throws Exception {
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "xdbustest.");
properties.put("prefix", TEST_PREFIX);
properties.put("autoBindDLQ", "true");
properties.put("maxAttempts", "1"); // disable retry
properties.put("requeue", "false");
@@ -491,14 +501,14 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
});
bus.bindConsumer("dlqtest", moduleInputChannel, properties);
binder.bindConsumer("dlqtest", moduleInputChannel, properties);
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.convertAndSend("", "xdbustest.dlqtest", "foo");
template.convertAndSend("", TEST_PREFIX + "dlqtest", "foo");
int n = 0;
while (n++ < 100) {
Object deadLetter = template.receiveAndConvert("xdbustest.dlqtest.dlq");
Object deadLetter = template.receiveAndConvert(TEST_PREFIX + "dlqtest.dlq");
if (deadLetter != null) {
assertEquals("foo", deadLetter);
break;
@@ -507,10 +517,10 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
assertTrue(n < 100);
bus.unbindConsumer("dlqtest", moduleInputChannel);
admin.deleteQueue("xdbustest.dlqtest.dlq");
admin.deleteQueue("xdbustest.dlqtest");
admin.deleteExchange("xdbustest.DLX");
binder.unbindConsumer("dlqtest", moduleInputChannel);
admin.deleteQueue(TEST_PREFIX + "dlqtest.dlq");
admin.deleteQueue(TEST_PREFIX + "dlqtest");
admin.deleteExchange(TEST_PREFIX + "DLX");
}
@Test
@@ -518,13 +528,13 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
// pre-declare the queue with dead-lettering, users can also use a policy
RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource());
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "xdbustest.DLX");
Queue queue = new Queue("xdbustest.dlqpubtest", true, false, false, args);
args.put("x-dead-letter-exchange", TEST_PREFIX + "DLX");
Queue queue = new Queue(TEST_PREFIX + "dlqpubtest", true, false, false, args);
admin.declareQueue(queue);
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("prefix", "xdbustest.");
properties.put("prefix", TEST_PREFIX);
properties.put("autoBindDLQ", "true");
properties.put("republishToDLQ", "true");
properties.put("maxAttempts", "1"); // disable retry
@@ -539,14 +549,14 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
});
bus.bindConsumer("dlqpubtest", moduleInputChannel, properties);
binder.bindConsumer("dlqpubtest", moduleInputChannel, properties);
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
template.convertAndSend("", "xdbustest.dlqpubtest", "foo");
template.convertAndSend("", TEST_PREFIX + "dlqpubtest", "foo");
int n = 0;
while (n++ < 100) {
org.springframework.amqp.core.Message deadLetter = template.receive("xdbustest.dlqpubtest.dlq");
org.springframework.amqp.core.Message deadLetter = template.receive(TEST_PREFIX + "dlqpubtest.dlq");
if (deadLetter != null) {
assertEquals("foo", new String(deadLetter.getBody()));
assertNotNull(deadLetter.getMessageProperties().getHeaders().get("x-exception-stacktrace"));
@@ -556,17 +566,17 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
}
assertTrue(n < 100);
bus.unbindConsumer("dlqpubtest", moduleInputChannel);
admin.deleteQueue("xdbustest.dlqpubtest.dlq");
admin.deleteQueue("xdbustest.dlqpubtest");
admin.deleteExchange("xdbustest.DLX");
binder.unbindConsumer("dlqpubtest", moduleInputChannel);
admin.deleteQueue(TEST_PREFIX + "dlqpubtest.dlq");
admin.deleteQueue(TEST_PREFIX + "dlqpubtest");
admin.deleteExchange(TEST_PREFIX + "DLX");
}
@SuppressWarnings("unchecked")
@Test
public void testBatchingAndCompression() throws Exception {
RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource());
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("deliveryMode", "NON_PERSISTENT");
properties.put("batchingEnabled", "true");
@@ -577,17 +587,17 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
DirectChannel output = new DirectChannel();
output.setBeanName("batchingProducer");
bus.bindProducer("batching.0", output, properties);
binder.bindProducer("batching.0", output, properties);
while (template.receive("xdbus.batching.0") != null) {
while (template.receive(BINDER_PREFIX + "batching.0") != null) {
}
Log logger = spy(TestUtils.getPropertyValue(bus, "messageBus.compressingPostProcessor.logger", Log.class));
new DirectFieldAccessor(TestUtils.getPropertyValue(bus, "messageBus.compressingPostProcessor"))
Log logger = spy(TestUtils.getPropertyValue(binder, "binder.compressingPostProcessor.logger", Log.class));
new DirectFieldAccessor(TestUtils.getPropertyValue(binder, "binder.compressingPostProcessor"))
.setPropertyValue("logger", logger);
when(logger.isTraceEnabled()).thenReturn(true);
assertEquals(Deflater.BEST_SPEED, TestUtils.getPropertyValue(bus, "messageBus.compressingPostProcessor.level"));
assertEquals(Deflater.BEST_SPEED, TestUtils.getPropertyValue(binder, "binder.compressingPostProcessor.level"));
output.send(new GenericMessage<>("foo".getBytes()));
output.send(new GenericMessage<>("bar".getBytes()));
@@ -602,7 +612,7 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
QueueChannel input = new QueueChannel();
input.setBeanName("batchingConsumer");
bus.bindConsumer("batching.0", input, null);
binder.bindConsumer("batching.0", input, null);
output.send(new GenericMessage<>("foo".getBytes()));
output.send(new GenericMessage<>("bar".getBytes()));
@@ -615,8 +625,8 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
assertEquals("bar", new String(in.getPayload()));
assertNull(in.getHeaders().get(AmqpHeaders.DELIVERY_MODE));
bus.unbindProducers("batching.0");
bus.unbindConsumers("batching.0");
binder.unbindProducers("batching.0");
binder.unbindConsumers("batching.0");
}
private SimpleMessageListenerContainer verifyContainer(AbstractEndpoint endpoint) {
@@ -679,12 +689,19 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
@Override
protected String getEndpointRouting(AbstractEndpoint endpoint) {
return TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression", SpelExpression.class).getExpressionString();
return TestUtils.getPropertyValue(endpoint, "handler.delegate.routingKeyExpression",
SpelExpression.class).getExpressionString();
}
@Override
protected String getPubSubEndpointRouting(AbstractEndpoint endpoint) {
return TestUtils.getPropertyValue(endpoint, "handler.delegate.exchangeNameExpression", SpelExpression.class).getExpressionString();
return TestUtils.getPropertyValue(endpoint, "handler.delegate.exchangeNameExpression",
SpelExpression.class).getExpressionString();
}
@Override
protected String getClassUnderTestName() {
return CLASS_UNDER_TEST_NAME;
}
@Override
@@ -697,12 +714,12 @@ public class RabbitMessageBusTests extends PartitionCapableBusTests {
public Object receive(boolean expectNull) throws Exception {
if (expectNull) {
Thread.sleep(50);
return template.receiveAndConvert("xdbus." + queue);
return template.receiveAndConvert(BINDER_PREFIX + queue);
}
Object bar = null;
int n = 0;
while (n++ < 100 && bar == null) {
bar = template.receiveAndConvert("xdbus." + queue);
bar = template.receiveAndConvert(BINDER_PREFIX + queue);
Thread.sleep(100);
}
assertTrue("Message did not arrive in RabbitMQ", n < 100);

View File

@@ -14,41 +14,43 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.xd.dirt.integration.bus.AbstractTestMessageBus;
import org.springframework.cloud.stream.binder.AbstractTestBinder;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
/**
* Test support class for {@link org.springframework.xd.dirt.integration.rabbit.RabbitMessageBus}.
* Test support class for {@link RabbitMessageChannelBinder}.
*
* @author Ilayaperumal Gopinathan
* @author Gary Russell
*/
public class RabbitTestMessageBus extends AbstractTestMessageBus<RabbitMessageBus> {
public class RabbitTestBinder extends AbstractTestBinder<RabbitMessageChannelBinder> {
public static final String BINDER_PREFIX = "binder.rabbit.";
private final RabbitAdmin rabbitAdmin;
public RabbitTestMessageBus(ConnectionFactory connectionFactory) {
public RabbitTestBinder(ConnectionFactory connectionFactory) {
this.rabbitAdmin = new RabbitAdmin(connectionFactory);
}
public RabbitTestMessageBus(ConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
RabbitMessageBus messageBus = new RabbitMessageBus(connectionFactory, codec);
public RabbitTestBinder(ConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
RabbitMessageChannelBinder binder = new RabbitMessageChannelBinder(connectionFactory, codec);
GenericApplicationContext context = new GenericApplicationContext();
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(1);
scheduler.afterPropertiesSet();
context.getBeanFactory().registerSingleton(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, scheduler);
context.refresh();
messageBus.setApplicationContext(context);
this.setMessageBus(messageBus);
binder.setApplicationContext(context);
this.setBinder(binder);
this.rabbitAdmin = new RabbitAdmin(connectionFactory);
}
@@ -56,10 +58,10 @@ public class RabbitTestMessageBus extends AbstractTestMessageBus<RabbitMessageBu
public void cleanup() {
if (!queues.isEmpty()) {
for (String queue : queues) {
rabbitAdmin.deleteQueue("xdbus." + queue);
rabbitAdmin.deleteQueue(BINDER_PREFIX + queue);
// delete any partitioned queues
for (int i = 0; i < 10; i++) {
rabbitAdmin.deleteQueue("xdbus." + queue + "-" + i);
rabbitAdmin.deleteQueue(BINDER_PREFIX + queue + "-" + i);
}
rabbitAdmin.deleteQueue("foo." + queue);
// delete any partitioned queues
@@ -70,7 +72,7 @@ public class RabbitTestMessageBus extends AbstractTestMessageBus<RabbitMessageBu
}
if (!topics.isEmpty()) {
for (String exchange : topics) {
rabbitAdmin.deleteExchange("xdbus." + exchange);
rabbitAdmin.deleteExchange(BINDER_PREFIX + exchange);
}
}
}

View File

@@ -14,11 +14,11 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.rabbit;
package org.springframework.cloud.stream.binder.rabbit;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.xd.test.AbstractExternalResourceTestSupport;
import org.springframework.cloud.stream.binder.AbstractExternalResourceTestSupport;
import javax.net.SocketFactory;
import java.net.Socket;

View File

@@ -5,4 +5,4 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n
log4j.category.org.springframework.xd.dirt.integration.rabbit=DEBUG
log4j.category.org.springframework.cloud.binder.rabbit=DEBUG

View File

@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-stream-binding-redis</name>
<description>Redis binding implementation</description>
<name>spring-cloud-stream-binder-redis</name>
<description>Redis binder implementation</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
@@ -21,11 +21,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-test</artifactId>
<artifactId>spring-cloud-stream-binder-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.redis;
package org.springframework.cloud.stream.binder.redis;
import java.util.ArrayList;
import java.util.Arrays;
@@ -23,6 +23,7 @@ import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.cloud.stream.binder.BinderHeaders;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -46,24 +47,22 @@ import org.springframework.retry.RetryContext;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.integration.bus.AbstractBusPropertiesAccessor;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.EmbeddedHeadersMessageConverter;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport;
import org.springframework.xd.dirt.integration.bus.MessageValues;
import org.springframework.xd.dirt.integration.bus.XdHeaders;
import org.springframework.cloud.stream.binder.AbstractBinderPropertiesAccessor;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.EmbeddedHeadersMessageConverter;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;
import org.springframework.cloud.stream.binder.MessageValues;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
/**
* A {@link MessageBus} implementation backed by Redis.
* A {@link org.springframework.cloud.stream.binder.Binder} implementation backed by Redis.
* @author Mark Fisher
* @author Gary Russell
* @author David Turanski
* @author Jennifer Hickey
*/
public class RedisMessageBus extends MessageBusSupport implements DisposableBean {
public class RedisMessageChannelBinder extends MessageChannelBinderSupport implements DisposableBean {
private static final String ERROR_HEADER = "errorKey";
@@ -85,7 +84,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
private static final Set<Object> SUPPORTED_NAMED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(CONSUMER_STANDARD_PROPERTIES)
.addAll(CONSUMER_RETRY_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
.build();
/**
@@ -93,7 +92,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
*/
private static final Set<Object> SUPPORTED_CONSUMER_PROPERTIES = new SetBuilder()
.addAll(SUPPORTED_NAMED_CONSUMER_PROPERTIES)
.add(BusProperties.PARTITION_INDEX)
.add(BinderProperties.PARTITION_INDEX)
.build();
/**
@@ -103,7 +102,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
// request
.addAll(CONSUMER_STANDARD_PROPERTIES)
.addAll(CONSUMER_RETRY_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
.build();
/**
@@ -122,7 +121,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
private static final Set<Object> SUPPORTED_PRODUCER_PROPERTIES = new SetBuilder()
.addAll(PRODUCER_PARTITIONING_PROPERTIES)
.addAll(PRODUCER_STANDARD_PROPERTIES)
.add(BusProperties.DIRECT_BINDING_ALLOWED)
.add(BinderProperties.DIRECT_BINDING_ALLOWED)
.build();
/**
@@ -131,7 +130,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
private static final Set<Object> SUPPORTED_REQUESTING_PRODUCER_PROPERTIES = new SetBuilder()
// reply
.addAll(CONSUMER_RETRY_PROPERTIES)
.add(BusProperties.CONCURRENCY)
.add(BinderProperties.CONCURRENCY)
.build();
private final RedisConnectionFactory connectionFactory;
@@ -141,11 +140,11 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
private final RedisQueueOutboundChannelAdapter errorAdapter;
public RedisMessageBus(RedisConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
public RedisMessageChannelBinder(RedisConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
this(connectionFactory, codec, new String[0]);
}
public RedisMessageBus(RedisConnectionFactory connectionFactory, MultiTypeCodec<Object> codec,
public RedisMessageChannelBinder(RedisConnectionFactory connectionFactory, MultiTypeCodec<Object> codec,
String... headersToMap) {
Assert.notNull(connectionFactory, "connectionFactory must not be null");
Assert.notNull(codec, "codec must not be null");
@@ -155,14 +154,14 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
parser.parseExpression("headers['" + ERROR_HEADER + "']"), connectionFactory);
if (headersToMap != null && headersToMap.length > 0) {
String[] combinedHeadersToMap =
Arrays.copyOfRange(XdHeaders.STANDARD_HEADERS, 0, XdHeaders.STANDARD_HEADERS.length
Arrays.copyOfRange(BinderHeaders.STANDARD_HEADERS, 0, BinderHeaders.STANDARD_HEADERS.length
+ headersToMap.length);
System.arraycopy(headersToMap, 0, combinedHeadersToMap, XdHeaders.STANDARD_HEADERS.length,
System.arraycopy(headersToMap, 0, combinedHeadersToMap, BinderHeaders.STANDARD_HEADERS.length,
headersToMap.length);
this.headersToMap = combinedHeadersToMap;
}
else {
this.headersToMap = XdHeaders.STANDARD_HEADERS;
this.headersToMap = BinderHeaders.STANDARD_HEADERS;
}
}
@@ -388,7 +387,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
this.doRegisterConsumer(name, name, requests, adapter, accessor);
RedisQueueOutboundChannelAdapter replyQueue = new RedisQueueOutboundChannelAdapter(
RedisMessageBus.parser.parseExpression("headers['" + XdHeaders.REPLY_TO + "']"),
RedisMessageChannelBinder.parser.parseExpression("headers['" + BinderHeaders.REPLY_TO + "']"),
this.connectionFactory);
replyQueue.setBeanFactory(this.getBeanFactory());
replyQueue.setIntegrationEvaluationContext(this.evaluationContext);
@@ -414,7 +413,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
this.delegate = delegate;
this.replyTo = replyTo;
this.partitioningMetadata = new PartitioningMetadata(properties, properties.getNextModuleCount());
this.setBeanFactory(RedisMessageBus.this.getBeanFactory());
this.setBeanFactory(RedisMessageChannelBinder.this.getBeanFactory());
}
@Override
@@ -422,7 +421,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
MessageValues transformed = serializePayloadIfNecessary(message);
if (replyTo != null) {
transformed.put(XdHeaders.REPLY_TO, this.replyTo);
transformed.put(BinderHeaders.REPLY_TO, this.replyTo);
}
if (this.partitioningMetadata.isPartitionedModule()) {
@@ -430,7 +429,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
}
byte[] messageToSend = embeddedHeadersMessageConverter.embedHeaders(transformed,
RedisMessageBus.this.headersToMap);
RedisMessageChannelBinder.this.headersToMap);
delegate.handleMessage(MessageBuilder.withPayload(messageToSend).copyHeaders(transformed).build());
}
@@ -440,7 +439,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
public ReceivingHandler() {
super();
this.setBeanFactory(RedisMessageBus.this.getBeanFactory());
this.setBeanFactory(RedisMessageChannelBinder.this.getBeanFactory());
}
@SuppressWarnings("unchecked")
@@ -464,7 +463,7 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
}
}
private static class RedisPropertiesAccessor extends AbstractBusPropertiesAccessor {
private static class RedisPropertiesAccessor extends AbstractBinderPropertiesAccessor {
public RedisPropertiesAccessor(Properties properties) {
super(properties);
@@ -484,12 +483,12 @@ public class RedisMessageBus extends MessageBusSupport implements DisposableBean
for (int i = 0; i < concurrency; i++) {
RedisQueueMessageDrivenEndpoint adapter = new RedisQueueMessageDrivenEndpoint(queueName,
connectionFactory);
adapter.setBeanFactory(RedisMessageBus.this.getBeanFactory());
adapter.setBeanFactory(RedisMessageChannelBinder.this.getBeanFactory());
adapter.setSerializer(null);
adapter.setBeanName("inbound." + queueName + "." + i);
this.consumers.add(adapter);
}
this.setBeanFactory(RedisMessageBus.this.getBeanFactory());
this.setBeanFactory(RedisMessageChannelBinder.this.getBeanFactory());
}
@Override

View File

@@ -0,0 +1,5 @@
/**
* This package contains an implementation of the {@link org.springframework.cloud.stream.binder.Binder} for Redis.
*/
package org.springframework.cloud.stream.binder.redis;

View File

@@ -5,7 +5,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="messageBus" class="org.springframework.xd.dirt.integration.redis.RedisMessageBus">
<bean id="messageBus" class="org.springframework.cloud.stream.binder.redis.RedisMessageChannelBinder">
<constructor-arg ref="redisConnectionFactory" />
<constructor-arg ref="codec"/>
<constructor-arg value="${xd.messagebus.redis.headers:}" />

View File

@@ -11,7 +11,7 @@
* specific language governing permissions and limitations under the License.
*/
package org.springframework.xd.dirt.integration.redis;
package org.springframework.cloud.stream.binder.redis;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.redis;
package org.springframework.cloud.stream.binder.redis;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
@@ -37,6 +37,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.cloud.stream.binder.PartitionCapableBinderTests;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@@ -47,19 +48,18 @@ import org.springframework.integration.redis.inbound.RedisQueueMessageDrivenEndp
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.xd.dirt.integration.bus.Binding;
import org.springframework.xd.dirt.integration.bus.BusProperties;
import org.springframework.xd.dirt.integration.bus.EmbeddedHeadersMessageConverter;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.PartitionCapableBusTests;
import org.springframework.xd.dirt.integration.bus.Spy;
import org.springframework.xd.dirt.integration.redis.RedisMessageBus;
import org.springframework.xd.dirt.integration.redis.RedisTestSupport;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.BinderProperties;
import org.springframework.cloud.stream.binder.EmbeddedHeadersMessageConverter;
import org.springframework.cloud.stream.binder.Binder;
import org.springframework.cloud.stream.binder.Spy;
/**
* @author Gary Russell
*/
public class RedisMessageBusTests extends PartitionCapableBusTests {
public class RedisBinderTests extends PartitionCapableBinderTests {
private final String CLASS_UNDER_TEST_NAME = RedisMessageChannelBinder.class.getSimpleName();
@Rule
public RedisTestSupport redisAvailableRule = new RedisTestSupport();
@@ -70,11 +70,11 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
new EmbeddedHeadersMessageConverter();
@Override
protected MessageBus getMessageBus() {
if (testMessageBus == null) {
testMessageBus = new RedisTestMessageBus(redisAvailableRule.getResource(), getCodec());
protected Binder getBinder() {
if (testBinder == null) {
testBinder = new RedisTestBinder(redisAvailableRule.getResource(), getCodec());
}
return testMessageBus;
return testBinder;
}
@Override
@@ -97,17 +97,17 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
@Test
public void testConsumerProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("maxAttempts", "1"); // disable retry
bus.bindConsumer("props.0", new DirectChannel(), properties);
binder.bindConsumer("props.0", new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
assertThat(endpoint, instanceOf(RedisQueueMessageDrivenEndpoint.class));
assertSame(DirectChannel.class, TestUtils.getPropertyValue(endpoint, "outputChannel").getClass());
bus.unbindConsumers("props.0");
binder.unbindConsumers("props.0");
assertEquals(0, bindings.size());
properties.put("backOffInitialInterval", "2000");
@@ -117,47 +117,47 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
properties.put("maxAttempts", "23");
properties.put("partitionIndex", 0);
bus.bindConsumer("props.0", new DirectChannel(), properties);
binder.bindConsumer("props.0", new DirectChannel(), properties);
assertEquals(1, bindings.size());
endpoint = bindings.get(0).getEndpoint();
verifyConsumer(endpoint);
try {
bus.bindPubSubConsumer("dummy", null, properties);
binder.bindPubSubConsumer("dummy", null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RedisMessageBus does not support consumer properties: "),
containsString(getClassUnderTestName() + " does not support consumer properties: "),
containsString("partitionIndex"),
containsString("concurrency"),
containsString(" for dummy.")));
}
try {
bus.bindConsumer("queue:dummy", null, properties);
binder.bindConsumer("queue:dummy", null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertEquals("RedisMessageBus does not support consumer property: partitionIndex for queue:dummy.",
assertEquals(getClassUnderTestName() + " does not support consumer property: partitionIndex for queue:dummy.",
e.getMessage());
}
bus.unbindConsumers("props.0");
binder.unbindConsumers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testProducerProperties() throws Exception {
MessageBus bus = getMessageBus();
bus.bindProducer("props.0", new DirectChannel(), null);
Binder binder = getBinder();
binder.bindProducer("props.0", new DirectChannel(), null);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
assertEquals(
"queue.props.0",
TestUtils.getPropertyValue(endpoint, "handler.delegate.queueNameExpression", Expression.class).getExpressionString());
bus.unbindProducers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
Properties properties = new Properties();
@@ -165,9 +165,9 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BusProperties.NEXT_MODULE_COUNT, "1");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "1");
bus.bindProducer("props.0", new DirectChannel(), properties);
binder.bindProducer("props.0", new DirectChannel(), properties);
assertEquals(1, bindings.size());
endpoint = bindings.get(0).getEndpoint();
assertEquals(
@@ -175,12 +175,12 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
TestUtils.getPropertyValue(endpoint, "handler.delegate.queueNameExpression", Expression.class).getExpressionString());
try {
bus.bindPubSubProducer("dummy", null, properties);
binder.bindPubSubProducer("dummy", null, properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RedisMessageBus does not support producer properties: "),
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -188,12 +188,12 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), containsString("for dummy."));
}
try {
bus.bindProducer("queue:dummy", new DirectChannel(), properties);
binder.bindProducer("queue:dummy", new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RedisMessageBus does not support producer properties: "),
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -201,13 +201,13 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), containsString("for queue:dummy."));
}
bus.unbindProducers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testRequestReplyRequestorProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("backOffInitialInterval", "2000");
@@ -216,9 +216,9 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
properties.put("concurrency", "2");
properties.put("maxAttempts", "23");
bus.bindRequestor("props.0", new DirectChannel(), new DirectChannel(), properties);
binder.bindRequestor("props.0", new DirectChannel(), new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(2, bindings.size());
AbstractEndpoint endpoint = bindings.get(0).getEndpoint(); // producer
@@ -235,12 +235,12 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
properties.put("partitionSelectorClass", "foo");
properties.put("partitionIndex", "0");
try {
bus.bindRequestor("dummy", new DirectChannel(), new DirectChannel(), properties);
binder.bindRequestor("dummy", new DirectChannel(), new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RedisMessageBus does not support producer properties: "),
containsString(getClassUnderTestName() + " does not support producer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -248,14 +248,14 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), allOf(containsString("partitionIndex"), containsString("for dummy.")));
}
bus.unbindConsumers("props.0");
bus.unbindProducers("props.0");
binder.unbindConsumers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@Test
public void testRequestReplyReplierProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("backOffInitialInterval", "2000");
@@ -264,9 +264,9 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
properties.put("concurrency", "2");
properties.put("maxAttempts", "23");
bus.bindReplier("props.0", new DirectChannel(), new DirectChannel(), properties);
binder.bindReplier("props.0", new DirectChannel(), new DirectChannel(), properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(2, bindings.size());
AbstractEndpoint endpoint = bindings.get(1).getEndpoint(); // producer
@@ -281,15 +281,15 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
properties.put("partitionKeyExtractorClass", "foo");
properties.put("partitionSelectorExpression", "0");
properties.put("partitionSelectorClass", "foo");
properties.put(BusProperties.NEXT_MODULE_COUNT, "1");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "1");
properties.put("partitionIndex", "0");
try {
bus.bindReplier("dummy", new DirectChannel(), new DirectChannel(), properties);
binder.bindReplier("dummy", new DirectChannel(), new DirectChannel(), properties);
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(
containsString("RedisMessageBus does not support consumer properties: "),
containsString(getClassUnderTestName() + " does not support consumer properties: "),
containsString("partitionSelectorExpression"),
containsString("partitionKeyExtractorClass"),
containsString("partitionKeyExpression"),
@@ -297,8 +297,8 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
assertThat(e.getMessage(), allOf(containsString("partitionIndex"), containsString("for dummy.")));
}
bus.unbindConsumers("props.0");
bus.unbindProducers("props.0");
binder.unbindConsumers("props.0");
binder.unbindProducers("props.0");
assertEquals(0, bindings.size());
}
@@ -309,10 +309,10 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
TestUtils.getPropertyValue(endpoint, "consumers", List.class).get(0),
"outputChannel", DirectChannel.class);
assertThat(
channel.getClass().getName(), containsString("RedisMessageBus$")); // retry wrapper
channel.getClass().getName(), containsString(getClassUnderTestName() + "$")); // retry wrapper
assertThat(
TestUtils.getPropertyValue(TestUtils.getPropertyValue(endpoint, "consumers", List.class).get(1),
"outputChannel").getClass().getName(), containsString("RedisMessageBus$")); // retry wrapper
"outputChannel").getClass().getName(), containsString(getClassUnderTestName() + "$")); // retry wrapper
RetryTemplate retry = TestUtils.getPropertyValue(channel, "val$retryTemplate", RetryTemplate.class);
assertEquals(23, TestUtils.getPropertyValue(retry, "retryPolicy.maxAttempts"));
assertEquals(2000L, TestUtils.getPropertyValue(retry, "backOffPolicy.initialInterval"));
@@ -322,14 +322,14 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
@Test
public void testRetryFail() {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
DirectChannel channel = new DirectChannel();
bus.bindProducer("retry.0", channel, null);
binder.bindProducer("retry.0", channel, null);
Properties props = new Properties();
props.put("maxAttempts", 2);
props.put("backOffInitialInterval", 100);
props.put("backOffMultiplier", "1.0");
bus.bindConsumer("retry.0", new DirectChannel(), props); // no subscriber
binder.bindConsumer("retry.0", new DirectChannel(), props); // no subscriber
channel.send(new GenericMessage<String>("foo"));
RedisTemplate<String, Object> template = createTemplate();
Object rightPop = template.boundListOps("ERRORS:retry.0").rightPop(5, TimeUnit.SECONDS);
@@ -339,8 +339,8 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
@Test
public void testMoreHeaders() {
RedisMessageBus bus = new RedisMessageBus(mock(RedisConnectionFactory.class), getCodec(), "foo", "bar");
Collection<String> headers = Arrays.asList(TestUtils.getPropertyValue(bus, "headersToMap", String[].class));
RedisMessageChannelBinder binder = new RedisMessageChannelBinder(mock(RedisConnectionFactory.class), getCodec(), "foo", "bar");
Collection<String> headers = Arrays.asList(TestUtils.getPropertyValue(binder, "headersToMap", String[].class));
assertEquals(10, headers.size());
assertTrue(headers.contains("foo"));
assertTrue(headers.contains("bar"));
@@ -369,6 +369,11 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
return TestUtils.getPropertyValue(endpoint, "handler.delegate.topicExpression", Expression.class).getExpressionString();
}
@Override
protected String getClassUnderTestName() {
return CLASS_UNDER_TEST_NAME;
}
@Override
public Spy spyOn(final String queue) {
final RedisTemplate<String, Object> template = createTemplate();
@@ -388,7 +393,7 @@ public class RedisMessageBusTests extends PartitionCapableBusTests {
}
@Override
protected void busBindUnbindLatency() throws InterruptedException {
protected void binderBindUnbindLatency() throws InterruptedException {
Thread.sleep(3000); // needed for Redis see INT-3442
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.redis;
package org.springframework.cloud.stream.binder.redis;
import static org.junit.Assert.assertEquals;
@@ -26,6 +26,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.cloud.stream.binder.BinderTestUtils;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@@ -36,7 +37,6 @@ import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.integration.redis.outbound.RedisPublishingMessageHandler;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.xd.dirt.integration.bus.BusTestUtils;
/**
* Temporary copy of SI RedisPublishingMessageHandlerTests that adds tests that publish messages with data types other
@@ -70,7 +70,7 @@ public class RedisPublishingMessageHandlerTests {
public void testWithDefaultSerializer() throws Exception {
setupListener(new StringRedisSerializer());
final RedisPublishingMessageHandler handler = new RedisPublishingMessageHandler(connectionFactory);
handler.setBeanFactory(BusTestUtils.MOCK_BF);
handler.setBeanFactory(BinderTestUtils.MOCK_BF);
handler.setTopic(TOPIC);
handler.afterPropertiesSet();
for (int i = 0; i < NUM_MESSAGES; i++) {
@@ -85,7 +85,7 @@ public class RedisPublishingMessageHandlerTests {
public void testWithNoSerializer() throws Exception {
setupListener(null);
final RedisPublishingMessageHandler handler = new RedisPublishingMessageHandler(connectionFactory);
handler.setBeanFactory(BusTestUtils.MOCK_BF);
handler.setBeanFactory(BinderTestUtils.MOCK_BF);
handler.setTopic(TOPIC);
handler.afterPropertiesSet();
for (int i = 0; i < NUM_MESSAGES; i++) {
@@ -101,7 +101,7 @@ public class RedisPublishingMessageHandlerTests {
GenericToStringSerializer<Long> serializer = new GenericToStringSerializer<Long>(Long.class);
setupListener(serializer);
final RedisPublishingMessageHandler handler = new RedisPublishingMessageHandler(connectionFactory);
handler.setBeanFactory(BusTestUtils.MOCK_BF);
handler.setBeanFactory(BinderTestUtils.MOCK_BF);
handler.setTopic(TOPIC);
handler.setSerializer(serializer);
handler.afterPropertiesSet();

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.redis;
package org.springframework.cloud.stream.binder.redis;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -30,6 +30,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.cloud.stream.binder.BinderTestUtils;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
@@ -43,7 +44,6 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.xd.dirt.integration.bus.BusTestUtils;
/**
* Integration test of {@link RedisQueueInboundChannelAdapter}
@@ -70,13 +70,13 @@ public class RedisQueueInboundChannelAdapterTests {
messages.clear();
this.connectionFactory = redisAvailableRule.getResource();
DirectChannel outputChannel = new DirectChannel();
outputChannel.setBeanFactory(BusTestUtils.MOCK_BF);
outputChannel.setBeanFactory(BinderTestUtils.MOCK_BF);
outputChannel.subscribe(new TestMessageHandler());
this.currentQueueName = QUEUE_NAME + ":" + System.nanoTime();
adapter = new RedisQueueMessageDrivenEndpoint(currentQueueName, connectionFactory);
adapter.setBeanFactory(BusTestUtils.MOCK_BF);
adapter.setBeanFactory(BinderTestUtils.MOCK_BF);
adapter.setOutputChannel(outputChannel);
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.redis;
package org.springframework.cloud.stream.binder.redis;
import static org.junit.Assert.assertEquals;
@@ -26,6 +26,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.cloud.stream.binder.BinderTestUtils;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
@@ -37,7 +38,6 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.integration.redis.outbound.RedisQueueOutboundChannelAdapter;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.xd.dirt.integration.bus.BusTestUtils;
/**
* Integration test of {@link RedisQueueOutboundChannelAdapter}
@@ -60,7 +60,7 @@ public class RedisQueueOutboundChannelAdapterTests {
public void setUp() {
this.connectionFactory = redisAvailableRule.getResource();
adapter = new RedisQueueOutboundChannelAdapter(QUEUE_NAME, connectionFactory);
adapter.setBeanFactory(BusTestUtils.MOCK_BF);
adapter.setBeanFactory(BinderTestUtils.MOCK_BF);
}
@After

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.redis;
package org.springframework.cloud.stream.binder.redis;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -24,27 +24,26 @@ import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.xd.dirt.integration.bus.AbstractTestMessageBus;
import org.springframework.cloud.stream.binder.AbstractTestBinder;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
import org.springframework.xd.dirt.integration.redis.RedisMessageBus;
/**
* Test support class for {@link RedisMessageBus}.
* Test support class for {@link RedisMessageChannelBinder}.
*
* @author Ilayaperumal Gopinathan
* @author Gary Russell
*/
public class RedisTestMessageBus extends AbstractTestMessageBus<RedisMessageBus> {
public class RedisTestBinder extends AbstractTestBinder<RedisMessageChannelBinder> {
private StringRedisTemplate template;
public RedisTestMessageBus(RedisConnectionFactory connectionFactory) {
public RedisTestBinder(RedisConnectionFactory connectionFactory) {
template = new StringRedisTemplate(connectionFactory);
}
public RedisTestMessageBus(RedisConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
RedisMessageBus messageBus = new RedisMessageBus(connectionFactory, codec);
public RedisTestBinder(RedisConnectionFactory connectionFactory, MultiTypeCodec<Object> codec) {
RedisMessageChannelBinder binder = new RedisMessageChannelBinder(connectionFactory, codec);
GenericApplicationContext context = new GenericApplicationContext();
context.getBeanFactory().registerSingleton(IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME,
new DefaultMessageBuilderFactory());
@@ -57,8 +56,8 @@ public class RedisTestMessageBus extends AbstractTestMessageBus<RedisMessageBus>
IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME,
channelRegistry);
context.refresh();
messageBus.setApplicationContext(context);
setMessageBus(messageBus);
binder.setApplicationContext(context);
setBinder(binder);
template = new StringRedisTemplate(connectionFactory);
}

View File

@@ -14,12 +14,12 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.redis;
package org.springframework.cloud.stream.binder.redis;
import org.junit.Rule;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.xd.test.AbstractExternalResourceTestSupport;
import org.springframework.cloud.stream.binder.AbstractExternalResourceTestSupport;
/**
* JUnit {@link Rule} that detects the fact that a Redis server is running on localhost.

View File

@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-stream-binding-spi</name>
<description>SPI for binding implementations</description>
<name>spring-cloud-stream-binder-spi</name>
<description>SPI for binder implementations</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Properties;
@@ -24,18 +24,18 @@ import org.springframework.util.StringUtils;
/**
* Base class for bus-specific property accessors; common properties
* Base class for binder-specific property accessors; common properties
* are defined here.
*
* @author Gary Russell
*/
public abstract class AbstractBusPropertiesAccessor implements BusProperties {
public abstract class AbstractBinderPropertiesAccessor implements BinderProperties {
private static final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
private final Properties properties;
public AbstractBusPropertiesAccessor(Properties properties) {
public AbstractBinderPropertiesAccessor(Properties properties) {
if (properties == null) {
this.properties = new Properties();
}
@@ -142,7 +142,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
/**
* Return the 'concurrency' property or the default value.
* The meaning of concurrency depends on the bus implementation.
* The meaning of concurrency depends on the binder implementation.
* @param defaultValue The default value.
* @return The property or default value.
*/
@@ -152,7 +152,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
/**
* Return the 'maxConcurrency' property or the default value.
* The meaning of maxConcurrency depends on the bus implementation.
* The meaning of maxConcurrency depends on the binder implementation.
* @param defaultValue The default value.
* @return The property or default value.
*/
@@ -165,7 +165,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
/**
* Return the 'maxAttempts' property or the default value.
* This is used in the retry template's SimpleRetryPolicy
* in buses that support retry.
* in binders that support retry.
* @param defaultValue The default value.
* @return The property or default value.
*/
@@ -176,7 +176,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
/**
* Return the 'backOffInitialInterval' property or the default value.
* This is used in the retry template's ExponentialBackOffPolicy
* in buses that support retry.
* in binders that support retry.
* @param defaultValue The default value.
* @return The property or default value.
*/
@@ -187,7 +187,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
/**
* Return the 'backOffMultiplier' property or the default value.
* This is used in the retry template's ExponentialBackOffPolicy
* in buses that support retry.
* in binders that support retry.
* @param defaultValue The default value.
* @return The property or default value.
*/
@@ -198,7 +198,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
/**
* Return the 'backOffMaxInterval' property or the default value.
* This is used in the retry template's ExponentialBackOffPolicy
* in buses that support retry.
* in binders that support retry.
* @param defaultValue The default value.
* @return The property or default value.
*/
@@ -291,7 +291,7 @@ public abstract class AbstractBusPropertiesAccessor implements BusProperties {
// Direct Binding
/**
* If true, the bus can attempt a direct binding.
* If true, the binder can attempt a direct binding.
*/
public boolean isDirectBindingAllowed() {
return getProperty(DIRECT_BINDING_ALLOWED, false);

View File

@@ -11,14 +11,14 @@
* specific language governing permissions and limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Properties;
import org.springframework.messaging.MessageChannel;
/**
* A strategy interface used to bind a {@link MessageChannel} to a logical name. The name is intended to identify a
* A strategy interface used to bind a module interface to a logical name. The name is intended to identify a
* logical consumer or producer of messages. This may be a queue, a channel adapter, another message channel, a Spring
* bean, etc.
*
@@ -29,55 +29,55 @@ import org.springframework.messaging.MessageChannel;
* @author Ilayaperumal Gopinathan
* @since 1.0
*/
public interface MessageBus {
public interface Binder<T> {
/**
* Bind a message consumer on a p2p channel
*
* @param name the logical identity of the message source
* @param moduleInputChannel the channel bound as a consumer
* @param inboundBindTarget the module interface to be bound as a point to point consumer
* @param properties arbitrary String key/value pairs that will be used in the binding
*/
void bindConsumer(String name, MessageChannel moduleInputChannel, Properties properties);
void bindConsumer(String name, T inboundBindTarget, Properties properties);
/**
* Bind a message consumer on a pub/sub channel
*
* @param name the logical identity of the message source
* @param inputChannel the channel bound as a pub/sub consumer
* @param inboundBindTarget the module interface to be bound as a pub/sub consumer
* @param properties arbitrary String key/value pairs that will be used in the binding
*/
void bindPubSubConsumer(final String name, MessageChannel inputChannel, Properties properties);
void bindPubSubConsumer(final String name, T inboundBindTarget, Properties properties);
/**
* Bind a message producer on a p2p channel.
*
* @param name the logical identity of the message target
* @param moduleOutputChannel the channel bound as a producer
* @param outboundBindTarget the module interface bound as a producer
* @param properties arbitrary String key/value pairs that will be used in the binding
*/
void bindProducer(String name, MessageChannel moduleOutputChannel, Properties properties);
void bindProducer(String name, T outboundBindTarget, Properties properties);
/**
* Bind a message producer on a pub/sub channel.
*
* @param name the logical identity of the message target
* @param outputChannel the channel bound as a producer
* @param outboundBindTarget the module interface bound as a producer
* @param properties arbitrary String key/value pairs that will be used in the binding
*/
void bindPubSubProducer(final String name, MessageChannel outputChannel, Properties properties);
void bindPubSubProducer(final String name, T outboundBindTarget, Properties properties);
/**
* Unbind an inbound inter-module channel and stop any active components that use the channel.
* Unbind inbound module components and stop any active components that use the channel.
*
* @param name the channel name
*/
void unbindConsumers(String name);
/**
* Unbind an outbound inter-module channel and stop any active components that use the channel.
* Unbind an outbound module components and stop any active components that use the channel.
*
* @param name the channel name
*/
@@ -87,59 +87,59 @@ public interface MessageBus {
* Unbind a specific p2p or pub/sub message consumer
*
* @param name The logical identify of a message source
* @param channel The channel bound as a consumer
* @param inboundBindTarget The module interface bound as a consumer
*/
void unbindConsumer(String name, MessageChannel channel);
void unbindConsumer(String name, T inboundBindTarget);
/**
* Unbind a specific p2p or pub/sub message producer
*
* @param name the logical identity of the message target
* @param channel the channel bound as a producer
* @param outboundBindTarget the channel bound as a producer
*/
void unbindProducer(String name, MessageChannel channel);
void unbindProducer(String name, T outboundBindTarget);
/**
* Bind a producer that expects async replies. To unbind, invoke unbindProducer() and unbindConsumer().
*
* @param name The name of the requestor.
* @param requests The request channel - sends requests.
* @param replies The reply channel - receives replies.
* @param requests The interface used to send requests.
* @param replies The interface used to receive replies.
* @param properties arbitrary String key/value pairs that will be used in the binding.
*/
void bindRequestor(String name, MessageChannel requests, MessageChannel replies, Properties properties);
void bindRequestor(String name, T requests, T replies, Properties properties);
/**
* Bind a consumer that handles requests from a requestor and asynchronously sends replies. To unbind, invoke
* unbindProducer() and unbindConsumer().
*
* @param name The name of the requestor for which this replier will handle requests.
* @param requests The request channel - receives requests.
* @param replies The reply channel - sends replies.
* @param requests The interface used to send requests.
* @param replies The interface used to receive replies.
* @param properties arbitrary String key/value pairs that will be used in the binding.
*/
void bindReplier(String name, MessageChannel requests, MessageChannel replies, Properties properties);
void bindReplier(String name, T requests, T replies, Properties properties);
/**
* Create a channel and bind a producer dynamically, creating the infrastructure
* required by the bus technology.
* Create a object and bind a producer dynamically, creating the infrastructure
* required by the binder technology.
* @param name The name of the "queue:" channel.
* @param properties arbitrary String key/value pairs that will be used in the binding.
* @return The channel.
* @return The bound object.
*/
MessageChannel bindDynamicProducer(String name, Properties properties);
T bindDynamicProducer(String name, Properties properties);
/**
* Create a channel and bind a producer dynamically, creating the infrastructure
* required by the bus technology to broadcast messages to consumers.
* Create an object and bind a producer dynamically, creating the infrastructure
* required by the binder technology to broadcast messages to consumers.
* @param name The name of the "topic:" channel.
* @param properties arbitrary String key/value pairs that will be used in the binding.
* @return The channel.
* @return The bound Object.
*/
MessageChannel bindDynamicPubSubProducer(String name, Properties properties);
T bindDynamicPubSubProducer(String name, Properties properties);
/**
* Return true if the bus supports the capability.
* Return true if the binder supports the capability.
* @param capability the capability.
* @return true if the capability is supported.
*/
@@ -148,7 +148,7 @@ public interface MessageBus {
public enum Capability {
/**
* When a bus supports durable subscriptions to a pub/sub channel, the stream
* When a binder supports durable subscriptions to a pub/sub channel, the stream
* name will be included in the consumer name.
*/
DURABLE_PUBSUB

View File

@@ -13,19 +13,19 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.List;
import java.util.Map;
/**
* Interface for implementations that perform cleanup for message buses.
* Interface for implementations that perform cleanup for binders.
*
* @author Gary Russell
* @since 1.2
*/
public interface BusCleaner {
public interface BinderCleaner {
/**
* Clean up all resources for the supplied stream/job.

View File

@@ -14,19 +14,19 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
/**
* Exception thrown to indicate a message bus error (most
* Exception thrown to indicate a binder error (most
* likely a configuration error).
*
* @author Gary Russell
*/
@SuppressWarnings("serial")
public class MessageBusException extends RuntimeException {
public class BinderException extends RuntimeException {
public MessageBusException(String message, Throwable cause) {
public BinderException(String message, Throwable cause) {
super(message, cause);
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
import org.springframework.messaging.MessageHeaders;
@@ -24,17 +24,18 @@ import org.springframework.messaging.MessageHeaders;
* Spring Integration message headers for XD.
*
* @author Gary Russell
* @author David Turanski
*/
public final class XdHeaders {
public final class BinderHeaders {
public static final String XD_REPLY_CHANNEL = "xdReplyChannel";
public static final String BINDER_REPLY_CHANNEL = "binderReplyChannel";
public static final String XD_HISTORY = "xdHistory";
public static final String BINDER_HISTORY = "binderHistory";
/*
* no xd prefix for backwards compatibility
*/
public static final String XD_ORIGINAL_CONTENT_TYPE = "originalContentType";
public static final String BINDER_ORIGINAL_CONTENT_TYPE = "originalContentType";
/*
* no xd prefix for backwards compatibility
@@ -42,21 +43,21 @@ public final class XdHeaders {
public static final String REPLY_TO = "replyTo";
/**
* The headers that will be propagated, by default, by message bus implementations
* The headers that will be propagated, by default, by binder implementations
* that have no inherent header support (by embedding the headers in the payload).
*/
public static final String[] STANDARD_HEADERS = new String[] {
IntegrationMessageHeaderAccessor.CORRELATION_ID,
IntegrationMessageHeaderAccessor.SEQUENCE_SIZE,
IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER,
XD_REPLY_CHANNEL,
BINDER_REPLY_CHANNEL,
MessageHeaders.CONTENT_TYPE,
XD_ORIGINAL_CONTENT_TYPE,
BINDER_ORIGINAL_CONTENT_TYPE,
REPLY_TO,
XD_HISTORY
BINDER_HISTORY
};
private XdHeaders() {
private BinderHeaders() {
}
}

View File

@@ -14,15 +14,15 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
/**
* Common bus properties.
* Common binder properties.
*
* @author Gary Russell
*/
public interface BusProperties {
public interface BinderProperties {
/**
* The retry back off initial interval.
@@ -92,7 +92,7 @@ public interface BusProperties {
public static final String PARTITION_SELECTOR_EXPRESSION = "partitionSelectorExpression";
/**
* If true, the bus will attempt to create a direct binding between the producer and consumer.
* If true, the binder will attempt to create a direct binding between the producer and consumer.
*/
public static final String DIRECT_BINDING_ALLOWED = "directBindingAllowed";

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.regex.Pattern;
@@ -22,14 +22,14 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Message Bus utilities.
* Binder utilities.
*
* @author Gary Russell
*/
public class BusUtils {
public class BinderUtils {
/**
* The delimiter between a group and index when constructing a bus consumer/producer.
* The delimiter between a group and index when constructing a binder consumer/producer.
*/
public static final String GROUP_INDEX_DELIMITER = ".";

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import org.springframework.context.Lifecycle;
import org.springframework.integration.endpoint.AbstractEndpoint;
@@ -22,10 +22,10 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.util.Assert;
/**
* Represents a binding between a module's channel and an adapter endpoint that connects to the MessageBus. The binding
* could be for a consumer or a producer. A consumer binding represents a connection from an adapter on the bus to a
* Represents a binding between a module's channel and an adapter endpoint that connects to the Binder. The binding
* could be for a consumer or a producer. A consumer binding represents a connection from an adapter on the binder to a
* module's input channel. A producer binding represents a connection from a module's output channel to an adapter on
* the bus.
* the binder.
*
* @author Jennifer Hickey
* @author Mark Fisher
@@ -47,10 +47,10 @@ public class Binding implements Lifecycle {
private final String type;
private final AbstractBusPropertiesAccessor properties;
private final AbstractBinderPropertiesAccessor properties;
private Binding(String name, MessageChannel channel, AbstractEndpoint endpoint, String type,
AbstractBusPropertiesAccessor properties) {
AbstractBinderPropertiesAccessor properties) {
Assert.notNull(channel, "channel must not be null");
Assert.notNull(endpoint, "endpoint must not be null");
this.name = name;
@@ -60,18 +60,18 @@ public class Binding implements Lifecycle {
this.properties = properties;
}
public static Binding forConsumer(String name, AbstractEndpoint adapterFromBus, MessageChannel moduleInputChannel,
AbstractBusPropertiesAccessor properties) {
return new Binding(name, moduleInputChannel, adapterFromBus, CONSUMER, properties);
public static Binding forConsumer(String name, AbstractEndpoint adapterFromBinder, MessageChannel moduleInputChannel,
AbstractBinderPropertiesAccessor properties) {
return new Binding(name, moduleInputChannel, adapterFromBinder, CONSUMER, properties);
}
public static Binding forProducer(String name, MessageChannel moduleOutputChannel, AbstractEndpoint adapterToBus,
AbstractBusPropertiesAccessor properties) {
return new Binding(name, moduleOutputChannel, adapterToBus, PRODUCER, properties);
public static Binding forProducer(String name, MessageChannel moduleOutputChannel, AbstractEndpoint adapterToBinder,
AbstractBinderPropertiesAccessor properties) {
return new Binding(name, moduleOutputChannel, adapterToBinder, PRODUCER, properties);
}
public static Binding forDirectProducer(String name, MessageChannel moduleOutputChannel,
AbstractEndpoint adapter, AbstractBusPropertiesAccessor properties) {
AbstractEndpoint adapter, AbstractBinderPropertiesAccessor properties) {
return new Binding(name, moduleOutputChannel, adapter, DIRECT, properties);
}
@@ -91,7 +91,7 @@ public class Binding implements Lifecycle {
return type;
}
public AbstractBusPropertiesAccessor getPropertiesAccessor() {
public AbstractBinderPropertiesAccessor getPropertiesAccessor() {
return properties;
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

View File

@@ -11,13 +11,7 @@
* specific language governing permissions and limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
import static org.springframework.util.MimeTypeUtils.ALL;
import static org.springframework.util.MimeTypeUtils.APPLICATION_OCTET_STREAM;
import static org.springframework.util.MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE;
import static org.springframework.util.MimeTypeUtils.TEXT_PLAIN;
import static org.springframework.util.MimeTypeUtils.TEXT_PLAIN_VALUE;
package org.springframework.cloud.stream.binder;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -48,6 +42,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.Lifecycle;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.serializer.support.SerializationFailedException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.integration.channel.DirectChannel;
@@ -69,15 +64,20 @@ import org.springframework.util.IdGenerator;
import org.springframework.util.MimeType;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
import org.springframework.xd.dirt.integration.bus.serializer.SerializationException;
import static org.springframework.util.MimeTypeUtils.ALL;
import static org.springframework.util.MimeTypeUtils.APPLICATION_OCTET_STREAM;
import static org.springframework.util.MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE;
import static org.springframework.util.MimeTypeUtils.TEXT_PLAIN;
import static org.springframework.util.MimeTypeUtils.TEXT_PLAIN_VALUE;
/**
* @author David Turanski
* @author Gary Russell
* @author Ilayaperumal Gopinathan
*/
public abstract class MessageBusSupport
implements MessageBus, ApplicationContextAware, InitializingBean {
public abstract class MessageChannelBinderSupport
implements Binder<MessageChannel>, ApplicationContextAware, InitializingBean {
protected static final String P2P_NAMED_CHANNEL_TYPE_PREFIX = "queue:";
@@ -116,45 +116,45 @@ public abstract class MessageBusSupport
private static final int DEFAULT_BATCH_TIMEOUT = 0;
/**
* The set of properties every bus implementation must support (or at least tolerate).
* The set of properties every binder implementation must support (or at least tolerate).
*/
protected static final Set<Object> CONSUMER_STANDARD_PROPERTIES = new SetBuilder()
.add(BusProperties.COUNT)
.add(BusProperties.SEQUENCE)
.add(BinderProperties.COUNT)
.add(BinderProperties.SEQUENCE)
.build();
protected static final Set<Object> PRODUCER_STANDARD_PROPERTIES = new HashSet<Object>(Arrays.asList(
BusProperties.NEXT_MODULE_COUNT,
BusProperties.NEXT_MODULE_CONCURRENCY
));
BinderProperties.NEXT_MODULE_COUNT,
BinderProperties.NEXT_MODULE_CONCURRENCY
));
protected static final Set<Object> CONSUMER_RETRY_PROPERTIES = new HashSet<Object>(Arrays.asList(new String[] {
BusProperties.BACK_OFF_INITIAL_INTERVAL,
BusProperties.BACK_OFF_MAX_INTERVAL,
BusProperties.BACK_OFF_MULTIPLIER,
BusProperties.MAX_ATTEMPTS
BinderProperties.BACK_OFF_INITIAL_INTERVAL,
BinderProperties.BACK_OFF_MAX_INTERVAL,
BinderProperties.BACK_OFF_MULTIPLIER,
BinderProperties.MAX_ATTEMPTS
}));
protected static final Set<Object> PRODUCER_PARTITIONING_PROPERTIES = new HashSet<Object>(
Arrays.asList(new String[] {
BusProperties.PARTITION_KEY_EXPRESSION,
BusProperties.PARTITION_KEY_EXTRACTOR_CLASS,
BusProperties.PARTITION_SELECTOR_CLASS,
BusProperties.PARTITION_SELECTOR_EXPRESSION,
BinderProperties.PARTITION_KEY_EXPRESSION,
BinderProperties.PARTITION_KEY_EXTRACTOR_CLASS,
BinderProperties.PARTITION_SELECTOR_CLASS,
BinderProperties.PARTITION_SELECTOR_EXPRESSION,
}));
protected static final Set<Object> PRODUCER_BATCHING_BASIC_PROPERTIES = new HashSet<Object>(
Arrays.asList(new String[] {
BusProperties.BATCHING_ENABLED,
BusProperties.BATCH_SIZE,
BusProperties.BATCH_TIMEOUT,
BinderProperties.BATCHING_ENABLED,
BinderProperties.BATCH_SIZE,
BinderProperties.BATCH_TIMEOUT,
}));
protected static final Set<Object> PRODUCER_BATCHING_ADVANCED_PROPERTIES = new HashSet<Object>(
Arrays.asList(new String[] {
BusProperties.BATCH_BUFFER_LIMIT,
BinderProperties.BATCH_BUFFER_LIMIT,
}));
private final List<Binding> bindings = Collections.synchronizedList(new ArrayList<Binding>());
@@ -188,7 +188,7 @@ public abstract class MessageBusSupport
protected volatile int defaultMaxAttempts = DEFAULT_MAX_ATTEMPTS;
// properties for bus implementations that support batching
// properties for binder implementations that support batching
protected volatile boolean defaultBatchingEnabled = false;
@@ -208,7 +208,7 @@ public abstract class MessageBusSupport
private volatile Map<String, Class<?>> payloadTypeCache = new ConcurrentHashMap<>();
/**
* For bus implementations that support a prefix, apply the prefix to the name.
* For binder implementations that support a prefix, apply the prefix to the name.
* @param prefix the prefix.
* @param name the name.
*/
@@ -217,7 +217,7 @@ public abstract class MessageBusSupport
}
/**
* For bus implementations that include a pub/sub component in identifiers, construct the name.
* For binder implementations that include a pub/sub component in identifiers, construct the name.
* @param name the name.
*/
public static String applyPubSub(String name) {
@@ -234,7 +234,7 @@ public abstract class MessageBusSupport
}
/**
* For bus implementations that support dead lettering, construct the name of the dead letter entity for the
* For binder implementations that support dead lettering, construct the name of the dead letter entity for the
* underlying pipe name.
* @param name the name.
*/
@@ -269,7 +269,7 @@ public abstract class MessageBusSupport
}
/**
* Set the partition strategy to be used by this bus if no partitionExpression is provided for a module.
* Set the partition strategy to be used by this binder if no partitionExpression is provided for a module.
* @param partitionSelector The selector.
*/
public void setPartitionSelector(PartitionSelectorStrategy partitionSelector) {
@@ -277,7 +277,7 @@ public abstract class MessageBusSupport
}
/**
* Set the default retry back off initial interval for this bus; can be overridden with consumer
* Set the default retry back off initial interval for this binder; can be overridden with consumer
* 'backOffInitialInterval' property.
* @param defaultBackOffInitialInterval
*/
@@ -286,7 +286,7 @@ public abstract class MessageBusSupport
}
/**
* Set the default retry back off multiplier for this bus; can be overridden with consumer 'backOffMultiplier'
* Set the default retry back off multiplier for this binder; can be overridden with consumer 'backOffMultiplier'
* property.
* @param defaultBackOffMultiplier
*/
@@ -295,7 +295,7 @@ public abstract class MessageBusSupport
}
/**
* Set the default retry back off max interval for this bus; can be overridden with consumer 'backOffMaxInterval'
* Set the default retry back off max interval for this binder; can be overridden with consumer 'backOffMaxInterval'
* property.
* @param defaultBackOffMaxInterval
*/
@@ -304,7 +304,7 @@ public abstract class MessageBusSupport
}
/**
* Set the default concurrency for this bus; can be overridden with consumer 'concurrency' property.
* Set the default concurrency for this binder; can be overridden with consumer 'concurrency' property.
* @param defaultConcurrency
*/
public void setDefaultConcurrency(int defaultConcurrency) {
@@ -312,7 +312,7 @@ public abstract class MessageBusSupport
}
/**
* The default maximum delivery attempts for this bus. Can be overridden by consumer property 'maxAttempts' if
* The default maximum delivery attempts for this binder. Can be overridden by consumer property 'maxAttempts' if
* supported. Values less than 2 disable retry and one delivery attempt is made.
* @param defaultMaxAttempts The default maximum attempts.
*/
@@ -321,7 +321,7 @@ public abstract class MessageBusSupport
}
/**
* Set whether this bus batches message sends by default. Only applies to bus implementations that support
* Set whether this binder batches message sends by default. Only applies to binder implementations that support
* batching.
* @param defaultBatchingEnabled the defaultBatchingEnabled to set.
*/
@@ -330,7 +330,7 @@ public abstract class MessageBusSupport
}
/**
* Set the default batch size; only applies when batching is enabled and the bus supports batching.
* Set the default batch size; only applies when batching is enabled and the binder supports batching.
* @param defaultBatchSize the defaultBatchSize to set.
*/
public void setDefaultBatchSize(int defaultBatchSize) {
@@ -339,7 +339,7 @@ public abstract class MessageBusSupport
/**
* Set the default batch buffer limit - used to send a batch early if its size exceeds this. Only applies if
* batching is enabled and the bus supports this property.
* batching is enabled and the binder supports this property.
* @param defaultBatchBufferLimit the defaultBatchBufferLimit to set.
*/
public void setDefaultBatchBufferLimit(int defaultBatchBufferLimit) {
@@ -348,7 +348,7 @@ public abstract class MessageBusSupport
/**
* Set the default batch timeout - used to send a batch if no messages arrive during this time. Only applies if
* batching is enabled and the bus supports this property.
* batching is enabled and the binder supports this property.
* @param defaultBatchTimeout the defaultBatchTimeout to set.
*/
public void setDefaultBatchTimeout(long defaultBatchTimeout) {
@@ -395,7 +395,7 @@ public abstract class MessageBusSupport
}
/**
* Create a producer for the named channel and bind it to the bus. Synchronized to avoid creating multiple
* Create a producer for the named channel and bind it to the binder. Synchronized to avoid creating multiple
* instances.
* @param name The name.
* @param channelName The name of the channel to be created, and registered as bean.
@@ -412,7 +412,7 @@ public abstract class MessageBusSupport
}
catch (RuntimeException e) {
destroyCreatedChannel(channelName, channel);
throw new MessageBusException(
throw new BinderException(
"Failed to bind dynamic channel '" + name + "' with properties " + properties, e);
}
}
@@ -421,8 +421,8 @@ public abstract class MessageBusSupport
/**
* Dynamically create a producer for the named channel. Note: even though it's pub/sub, we still use a direct
* channel. It will be bridged to a pub/sub channel in the local bus and bound to an appropriate element for other
* buses.
* channel. It will be bridged to a pub/sub channel in the local binder and bound to an appropriate element for other
* binders.
* @param name The name.
* @param properties The properties.
* @return The channel.
@@ -433,7 +433,7 @@ public abstract class MessageBusSupport
}
/**
* Create a producer for the named channel and bind it to the bus. Synchronized to avoid creating multiple
* Create a producer for the named channel and bind it to the binder. Synchronized to avoid creating multiple
* instances.
* @param name The name.
* @param channelName The name of the channel to be created, and registered as bean.
@@ -450,7 +450,7 @@ public abstract class MessageBusSupport
}
catch (RuntimeException e) {
destroyCreatedChannel(channelName, channel);
throw new MessageBusException(
throw new BinderException(
"Failed to bind dynamic channel '" + name + "' with properties " + properties, e);
}
}
@@ -569,7 +569,7 @@ public abstract class MessageBusSupport
messageValues.setPayload(payload);
messageValues.put(MessageHeaders.CONTENT_TYPE, contentType);
if (originalContentType != null) {
messageValues.put(XdHeaders.XD_ORIGINAL_CONTENT_TYPE, originalContentType);
messageValues.put(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE, originalContentType);
}
return messageValues;
}
@@ -588,7 +588,7 @@ public abstract class MessageBusSupport
return bos.toByteArray();
}
catch (IOException e) {
throw new SerializationException("unable to serialize payload ["
throw new SerializationFailedException("unable to serialize payload ["
+ originalPayload.getClass().getName() + "]", e);
}
}
@@ -606,9 +606,9 @@ public abstract class MessageBusSupport
if (payload != null) {
messageToSend.setPayload(payload);
Object originalContentType = messageToSend.get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE);
Object originalContentType = messageToSend.get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE);
messageToSend.put(MessageHeaders.CONTENT_TYPE, originalContentType);
messageToSend.put(XdHeaders.XD_ORIGINAL_CONTENT_TYPE, null);
messageToSend.put(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE, null);
}
return messageToSend;
}
@@ -631,7 +631,8 @@ public abstract class MessageBusSupport
return new String(bytes, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new SerializationException("unable to deserialize [java.lang.String]. Encoding not supported.", e);
throw new SerializationFailedException("unable to deserialize [java.lang.String]. Encoding not supported.",
e);
}
}
else {
@@ -644,10 +645,13 @@ public abstract class MessageBusSupport
payloadTypeCache.put(className, targetType);
}
return codec.deserialize(bytes, targetType);
} catch (ClassNotFoundException e) {
throw new SerializationException("unable to deserialize [" + className + "]. Class not found.", e);//NOSONAR
} catch (IOException e) {
throw new SerializationException("unable to deserialize [" + className + "]", e);
}
catch (ClassNotFoundException e) {
throw new SerializationFailedException("unable to deserialize [" + className + "]. Class not found.",
e);//NOSONAR
}
catch (IOException e) {
throw new SerializationFailedException("unable to deserialize [" + className + "]", e);
}
}
}
@@ -658,7 +662,7 @@ public abstract class MessageBusSupport
* partition selector class is provided, it will be invoked to determine the partition. Otherwise, if the partition
* expression is not null, it is evaluated against the key and is expected to return an integer to which the modulo
* function will be applied, using the partitionCount as the divisor. If no partition expression is provided, the
* key will be passed to the bus partition strategy along with the partitionCount. The default partition strategy
* key will be passed to the binder partition strategy along with the partitionCount. The default partition strategy
* uses {@code key.hashCode()}, and the result will be the mod of that value.
* @param message the message.
* @param meta the partitioning metadata.
@@ -701,7 +705,7 @@ public abstract class MessageBusSupport
}
catch (Exception e) {
logger.error("Failed to load key extractor", e);
throw new MessageBusException("Failed to load key extractor: " + partitionKeyExtractorClassName, e);
throw new BinderException("Failed to load key extractor: " + partitionKeyExtractorClassName, e);
}
try {
Object extractor = clazz.newInstance();
@@ -712,7 +716,7 @@ public abstract class MessageBusSupport
}
catch (Exception e) {
logger.error("Failed to instantiate key extractor", e);
throw new MessageBusException("Failed to instantiate key extractor: " + partitionKeyExtractorClassName, e);
throw new BinderException("Failed to instantiate key extractor: " + partitionKeyExtractorClassName, e);
}
}
@@ -727,7 +731,7 @@ public abstract class MessageBusSupport
}
catch (Exception e) {
logger.error("Failed to load partition selector", e);
throw new MessageBusException("Failed to load partition selector: " + partitionSelectorClassName, e);
throw new BinderException("Failed to load partition selector: " + partitionSelectorClassName, e);
}
try {
Object extractor = clazz.newInstance();
@@ -738,14 +742,14 @@ public abstract class MessageBusSupport
}
catch (Exception e) {
logger.error("Failed to instantiate partition selector", e);
throw new MessageBusException("Failed to instantiate partition selector: " + partitionSelectorClassName,
throw new BinderException("Failed to instantiate partition selector: " + partitionSelectorClassName,
e);
}
}
/**
* Validate the provided deployment properties for the consumer against those supported by this bus implementation.
* The consumer is that part of the bus that consumes messages from the underlying infrastructure and sends them to
* Validate the provided deployment properties for the consumer against those supported by this binder implementation.
* The consumer is that part of the binder that consumes messages from the underlying infrastructure and sends them to
* the next module. Consumer properties are used to configure the consumer.
* @param name The name.
* @param properties The properties.
@@ -758,8 +762,8 @@ public abstract class MessageBusSupport
}
/**
* Validate the provided deployment properties for the producer against those supported by this bus implementation.
* When a module sends a message to the bus, the producer uses these properties while sending it to the underlying
* Validate the provided deployment properties for the producer against those supported by this binder implementation.
* When a module sends a message to the binder, the producer uses these properties while sending it to the underlying
* infrastructure.
* @param name The name.
* @param properties The properties.
@@ -799,7 +803,7 @@ public abstract class MessageBusSupport
* @param properties The properties.
* @return The retry template, or null if retry is not enabled.
*/
protected RetryTemplate buildRetryTemplateIfRetryEnabled(AbstractBusPropertiesAccessor properties) {
protected RetryTemplate buildRetryTemplateIfRetryEnabled(AbstractBinderPropertiesAccessor properties) {
int maxAttempts = properties.getMaxAttempts(this.defaultMaxAttempts);
if (maxAttempts > 1) {
RetryTemplate template = new RetryTemplate();
@@ -824,7 +828,7 @@ public abstract class MessageBusSupport
}
/**
* Attempt to create a direct binding (avoiding the bus) if the consumer is local. Named channel producers are not
* Attempt to create a direct binding (avoiding the binder) if the consumer is local. Named channel producers are not
* bound directly.
* @param name The name.
* @param moduleOutputChannel The channel to bind.
@@ -832,7 +836,7 @@ public abstract class MessageBusSupport
* @return true if the producer is bound.
*/
protected boolean bindNewProducerDirectlyIfPossible(String name, SubscribableChannel moduleOutputChannel,
AbstractBusPropertiesAccessor properties) {
AbstractBinderPropertiesAccessor properties) {
if (!properties.isDirectBindingAllowed()) {
return false;
}
@@ -865,7 +869,7 @@ public abstract class MessageBusSupport
}
private void bindProducerDirectly(String name, SubscribableChannel producerChannel,
MessageChannel consumerChannel, AbstractBusPropertiesAccessor properties) {
MessageChannel consumerChannel, AbstractBinderPropertiesAccessor properties) {
DirectHandler handler = new DirectHandler(consumerChannel);
EventDrivenConsumer consumer = new EventDrivenConsumer(producerChannel, handler);
consumer.setBeanFactory(getBeanFactory());
@@ -880,8 +884,8 @@ public abstract class MessageBusSupport
}
/**
* Attempt to bind a producer directly (avoiding the bus) if there is already a local producer. PubSub producers
* cannot be bound directly. Create the direct binding, then unbind the existing bus producer.
* Attempt to bind a producer directly (avoiding the binder) if there is already a local producer. PubSub producers
* cannot be bound directly. Create the direct binding, then unbind the existing binder producer.
* @param name The name.
* @param consumerChannel The channel to bind the producer to.
*/
@@ -896,7 +900,7 @@ public abstract class MessageBusSupport
}
}
if (producerBinding != null && producerBinding.getChannel() instanceof SubscribableChannel) {
AbstractBusPropertiesAccessor properties = producerBinding.getPropertiesAccessor();
AbstractBinderPropertiesAccessor properties = producerBinding.getPropertiesAccessor();
if (properties.isDirectBindingAllowed()) {
bindProducerDirectly(name, (SubscribableChannel) producerBinding.getChannel(), consumerChannel,
properties);
@@ -966,7 +970,7 @@ public abstract class MessageBusSupport
private final int partitionCount;
public PartitioningMetadata(AbstractBusPropertiesAccessor properties, int partitionCount) {
public PartitioningMetadata(AbstractBinderPropertiesAccessor properties, int partitionCount) {
this.partitionCount = partitionCount;
this.partitionKeyExtractorClass = properties.getPartitionKeyExtractorClass();
this.partitionKeyExpression = properties.getPartitionKeyExpression();
@@ -1039,7 +1043,8 @@ public abstract class MessageBusSupport
*/
abstract static class JavaClassMimeTypeConversion {
public static final MimeType APPLICATION_OCTET_STREAM_MIME_TYPE = MimeType.valueOf(APPLICATION_OCTET_STREAM_VALUE);
public static final MimeType APPLICATION_OCTET_STREAM_MIME_TYPE = MimeType.valueOf
(APPLICATION_OCTET_STREAM_VALUE);
public static final MimeType TEXT_PLAIN_MIME_TYPE = MimeType.valueOf(TEXT_PLAIN_VALUE);
@@ -1125,7 +1130,7 @@ public abstract class MessageBusSupport
}
/**
* Perform manual acknowledgement based on the metadata stored in message bus.
* Perform manual acknowledgement based on the metadata stored in the binder.
*/
public void doManualAck(LinkedList<MessageHeaders> messageHeaders) {
}

View File

@@ -13,7 +13,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Collection;
import java.util.HashMap;
@@ -26,7 +26,7 @@ import org.springframework.messaging.Message;
import org.springframework.util.Assert;
/**
* A mutable type for allowing {@link MessageBus} implementations to transform and enrich message content more
* A mutable type for allowing {@link Binder} implementations to transform and enrich message content more
* efficiently.
* @author David Turanski
*/
@@ -46,7 +46,7 @@ public class MessageValues implements Map<String, Object> {
}
}
public MessageValues(Object payload, Map<String,Object> headers) {
public MessageValues(Object payload, Map<String, Object> headers) {
this.payload = payload;
this.headers.putAll(headers);
}
@@ -145,8 +145,8 @@ public class MessageValues implements Map<String, Object> {
return headers.entrySet();
}
public void copyHeadersIfAbsent(Map<String,Object> headersToCopy) {
for (Entry<String, Object> headersToCopyEntry : headersToCopy.entrySet()) {
public void copyHeadersIfAbsent(Map<String, Object> headersToCopy) {
for (Entry<String, Object> headersToCopyEntry : headersToCopy.entrySet()) {
if (!containsKey(headersToCopyEntry.getKey())) {
put(headersToCopyEntry.getKey(), headersToCopyEntry.getValue());
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import org.springframework.messaging.Message;

View File

@@ -14,19 +14,16 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import org.springframework.cloud.stream.exception.CloudStreamsRuntimeException;
/**
* Exceptions thrown while interfacing with the RabbitMQ admin plugin.
*
* @author Gary Russell
* @since 1.2
*/
@SuppressWarnings("serial")
public class RabbitAdminException extends CloudStreamsRuntimeException {
public class RabbitAdminException extends RuntimeException {
public RabbitAdminException(String message, Throwable cause) {
super(message, cause);

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.net.URI;
import java.net.URISyntaxException;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.startsWith;

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-test</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cloud-stream-binder-test</name>
<description>Test support for binder implementations</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binders-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-amqp.version>1.4.5.RELEASE</spring-amqp.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-test</artifactId>
<version>${spring-integration.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.avro</groupId>
<artifactId>avro-compiler</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.xd</groupId>
<artifactId>spring-xd-tuple</artifactId>
<version>${spring-xd.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.xd</groupId>
<artifactId>spring-xd-codec</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-spi</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-codec</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Collection;
import java.util.Collections;
@@ -33,7 +33,7 @@ import org.springframework.integration.channel.interceptor.WireTap;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.xd.dirt.integration.bus.MessageBus.Capability;
import org.springframework.cloud.stream.binder.Binder.Capability;
import org.springframework.xd.dirt.integration.bus.serializer.MultiTypeCodec;
import org.springframework.xd.dirt.integration.bus.serializer.kryo.PojoCodec;
@@ -49,92 +49,92 @@ import static org.junit.Assert.fail;
* @author Ilayaperumal Gopinathan
* @author David Turanski
*/
public abstract class AbstractMessageBusTests {
public abstract class AbstractBinderTests {
protected static final Collection<MediaType> ALL = Collections.singletonList(MediaType.ALL);
protected AbstractTestMessageBus<?> testMessageBus;
protected AbstractTestBinder<?> testBinder;
@Test
public void testClean() throws Exception {
MessageBus messageBus = getMessageBus();
messageBus.bindProducer("foo.0", new DirectChannel(), null);
messageBus.bindConsumer("foo.0", new DirectChannel(), null);
messageBus.bindProducer("foo.1", new DirectChannel(), null);
messageBus.bindConsumer("foo.1", new DirectChannel(), null);
messageBus.bindProducer("foo.2", new DirectChannel(), null);
Collection<?> bindings = getBindings(messageBus);
Binder binder = getBinder();
binder.bindProducer("foo.0", new DirectChannel(), null);
binder.bindConsumer("foo.0", new DirectChannel(), null);
binder.bindProducer("foo.1", new DirectChannel(), null);
binder.bindConsumer("foo.1", new DirectChannel(), null);
binder.bindProducer("foo.2", new DirectChannel(), null);
Collection<?> bindings = getBindings(binder);
assertEquals(5, bindings.size());
messageBus.unbindProducers("foo.0");
binder.unbindProducers("foo.0");
assertEquals(4, bindings.size());
messageBus.unbindConsumers("foo.0");
messageBus.unbindProducers("foo.1");
binder.unbindConsumers("foo.0");
binder.unbindProducers("foo.1");
assertEquals(2, bindings.size());
messageBus.unbindConsumers("foo.1");
messageBus.unbindProducers("foo.2");
binder.unbindConsumers("foo.1");
binder.unbindProducers("foo.2");
assertTrue(bindings.isEmpty());
}
@Test
public void testSendAndReceive() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
messageBus.bindProducer("foo.0", moduleOutputChannel, null);
messageBus.bindConsumer("foo.0", moduleInputChannel, null);
binder.bindProducer("foo.0", moduleOutputChannel, null);
binder.bindConsumer("foo.0", moduleInputChannel, null);
Message<?> message = MessageBuilder.withPayload("foo").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
// Let the consumer actually bind to the producer before sending a msg
busBindUnbindLatency();
binderBindUnbindLatency();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(5000);
assertNotNull(inbound);
assertEquals("foo", inbound.getPayload());
assertNull(inbound.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(inbound.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", inbound.getHeaders().get(MessageHeaders.CONTENT_TYPE));
messageBus.unbindProducers("foo.0");
messageBus.unbindConsumers("foo.0");
binder.unbindProducers("foo.0");
binder.unbindConsumers("foo.0");
}
@Test
public void testSendAndReceiveNoOriginalContentType() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
messageBus.bindProducer("bar.0", moduleOutputChannel, null);
messageBus.bindConsumer("bar.0", moduleInputChannel, null);
busBindUnbindLatency();
binder.bindProducer("bar.0", moduleOutputChannel, null);
binder.bindConsumer("bar.0", moduleInputChannel, null);
binderBindUnbindLatency();
Message<?> message = MessageBuilder.withPayload("foo").build();
moduleOutputChannel.send(message);
Message<?> inbound = moduleInputChannel.receive(5000);
assertNotNull(inbound);
assertEquals("foo", inbound.getPayload());
assertNull(inbound.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(inbound.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertNull(inbound.getHeaders().get(MessageHeaders.CONTENT_TYPE));
messageBus.unbindProducers("bar.0");
messageBus.unbindConsumers("bar.0");
binder.unbindProducers("bar.0");
binder.unbindConsumers("bar.0");
}
@Test
public void testSendAndReceivePubSub() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
// Test pub/sub by emulating how StreamPlugin handles taps
DirectChannel tapChannel = new DirectChannel();
QueueChannel moduleInputChannel = new QueueChannel();
QueueChannel module2InputChannel = new QueueChannel();
QueueChannel module3InputChannel = new QueueChannel();
messageBus.bindProducer("baz.0", moduleOutputChannel, null);
messageBus.bindConsumer("baz.0", moduleInputChannel, null);
binder.bindProducer("baz.0", moduleOutputChannel, null);
binder.bindConsumer("baz.0", moduleInputChannel, null);
moduleOutputChannel.addInterceptor(new WireTap(tapChannel));
messageBus.bindPubSubProducer("tap:baz.http", tapChannel, null);
binder.bindPubSubProducer("tap:baz.http", tapChannel, null);
// A new module is using the tap as an input channel
String fooTapName = messageBus.isCapable(Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(fooTapName, module2InputChannel, null);
String fooTapName = binder.isCapable(Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(fooTapName, module2InputChannel, null);
// Another new module is using tap as an input channel
String barTapName = messageBus.isCapable(Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(barTapName, module3InputChannel, null);
String barTapName = binder.isCapable(Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(barTapName, module3InputChannel, null);
Message<?> message = MessageBuilder.withPayload("foo").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
boolean success = false;
@@ -144,7 +144,7 @@ public abstract class AbstractMessageBusTests {
Message<?> inbound = moduleInputChannel.receive(5000);
assertNotNull(inbound);
assertEquals("foo", inbound.getPayload());
assertNull(inbound.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(inbound.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", inbound.getHeaders().get(MessageHeaders.CONTENT_TYPE));
Message<?> tapped1 = module2InputChannel.receive(5000);
Message<?> tapped2 = module3InputChannel.receive(5000);
@@ -156,14 +156,14 @@ public abstract class AbstractMessageBusTests {
}
success = true;
assertEquals("foo", tapped1.getPayload());
assertNull(tapped1.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(tapped1.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", tapped1.getHeaders().get(MessageHeaders.CONTENT_TYPE));
assertEquals("foo", tapped2.getPayload());
assertNull(tapped2.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(tapped2.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", tapped2.getHeaders().get(MessageHeaders.CONTENT_TYPE));
}
// delete one tap stream is deleted
messageBus.unbindConsumer(barTapName, module3InputChannel);
binder.unbindConsumer(barTapName, module3InputChannel);
Message<?> message2 = MessageBuilder.withPayload("bar").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
moduleOutputChannel.send(message2);
@@ -176,17 +176,17 @@ public abstract class AbstractMessageBusTests {
assertNull(module3InputChannel.receive(1000));
// when other tap stream is deleted
messageBus.unbindConsumer(fooTapName, module2InputChannel);
binder.unbindConsumer(fooTapName, module2InputChannel);
// Clean up as StreamPlugin would
messageBus.unbindConsumer("baz.0", moduleInputChannel);
messageBus.unbindProducer("baz.0", moduleOutputChannel);
messageBus.unbindProducers("tap:baz.http");
assertTrue(getBindings(messageBus).isEmpty());
binder.unbindConsumer("baz.0", moduleInputChannel);
binder.unbindProducer("baz.0", moduleOutputChannel);
binder.unbindProducers("tap:baz.http");
assertTrue(getBindings(binder).isEmpty());
}
@Test
public void createInboundPubSubBeforeOutboundPubSub() throws Exception {
MessageBus messageBus = getMessageBus();
Binder binder = getBinder();
DirectChannel moduleOutputChannel = new DirectChannel();
// Test pub/sub by emulating how StreamPlugin handles taps
DirectChannel tapChannel = new DirectChannel();
@@ -194,18 +194,18 @@ public abstract class AbstractMessageBusTests {
QueueChannel module2InputChannel = new QueueChannel();
QueueChannel module3InputChannel = new QueueChannel();
// Create the tap first
String fooTapName = messageBus.isCapable(Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(fooTapName, module2InputChannel, null);
String fooTapName = binder.isCapable(Capability.DURABLE_PUBSUB) ? "foo.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(fooTapName, module2InputChannel, null);
// Then create the stream
messageBus.bindProducer("baz.0", moduleOutputChannel, null);
messageBus.bindConsumer("baz.0", moduleInputChannel, null);
binder.bindProducer("baz.0", moduleOutputChannel, null);
binder.bindConsumer("baz.0", moduleInputChannel, null);
moduleOutputChannel.addInterceptor(new WireTap(tapChannel));
messageBus.bindPubSubProducer("tap:baz.http", tapChannel, null);
binder.bindPubSubProducer("tap:baz.http", tapChannel, null);
// Another new module is using tap as an input channel
String barTapName = messageBus.isCapable(Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
messageBus.bindPubSubConsumer(barTapName, module3InputChannel, null);
String barTapName = binder.isCapable(Capability.DURABLE_PUBSUB) ? "bar.tap:baz.http" : "tap:baz.http";
binder.bindPubSubConsumer(barTapName, module3InputChannel, null);
Message<?> message = MessageBuilder.withPayload("foo").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
boolean success = false;
@@ -215,7 +215,7 @@ public abstract class AbstractMessageBusTests {
Message<?> inbound = moduleInputChannel.receive(5000);
assertNotNull(inbound);
assertEquals("foo", inbound.getPayload());
assertNull(inbound.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(inbound.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", inbound.getHeaders().get(MessageHeaders.CONTENT_TYPE));
Message<?> tapped1 = module2InputChannel.receive(5000);
Message<?> tapped2 = module3InputChannel.receive(5000);
@@ -227,14 +227,14 @@ public abstract class AbstractMessageBusTests {
}
success = true;
assertEquals("foo", tapped1.getPayload());
assertNull(tapped1.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(tapped1.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", tapped1.getHeaders().get(MessageHeaders.CONTENT_TYPE));
assertEquals("foo", tapped2.getPayload());
assertNull(tapped2.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(tapped2.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
assertEquals("foo/bar", tapped2.getHeaders().get(MessageHeaders.CONTENT_TYPE));
}
// delete one tap stream is deleted
messageBus.unbindConsumer(barTapName, module3InputChannel);
binder.unbindConsumer(barTapName, module3InputChannel);
Message<?> message2 = MessageBuilder.withPayload("bar").setHeader(MessageHeaders.CONTENT_TYPE,
"foo/bar").build();
moduleOutputChannel.send(message2);
@@ -247,43 +247,43 @@ public abstract class AbstractMessageBusTests {
assertNull(module3InputChannel.receive(1000));
// when other tap stream is deleted
messageBus.unbindConsumer(fooTapName, module2InputChannel);
binder.unbindConsumer(fooTapName, module2InputChannel);
// Clean up as StreamPlugin would
messageBus.unbindConsumer("baz.0", moduleInputChannel);
messageBus.unbindProducer("baz.0", moduleOutputChannel);
messageBus.unbindProducers("tap:baz.http");
assertTrue(getBindings(messageBus).isEmpty());
binder.unbindConsumer("baz.0", moduleInputChannel);
binder.unbindProducer("baz.0", moduleOutputChannel);
binder.unbindProducers("tap:baz.http");
assertTrue(getBindings(binder).isEmpty());
}
@Test
public void testBadDynamic() throws Exception {
Properties properties = new Properties();
properties.setProperty(BusProperties.PARTITION_KEY_EXPRESSION, "'foo'");
MessageBus messageBus = getMessageBus();
properties.setProperty(BinderProperties.PARTITION_KEY_EXPRESSION, "'foo'");
Binder binder = getBinder();
try {
messageBus.bindDynamicProducer("queue:foo", properties);
binder.bindDynamicProducer("queue:foo", properties);
fail("Exception expected");
}
catch (MessageBusException mbe) {
catch (BinderException mbe) {
Assert.assertEquals("Failed to bind dynamic channel 'queue:foo' with properties " +
"{partitionKeyExpression='foo'}",
mbe.getMessage());
if (messageBus instanceof AbstractTestMessageBus) {
messageBus = ((AbstractTestMessageBus) messageBus).getCoreMessageBus();
if (binder instanceof AbstractTestBinder) {
binder = ((AbstractTestBinder) binder).getCoreBinder();
}
assertFalse(((MessageBusSupport) messageBus).getApplicationContext().containsBean("queue:foo"));
assertFalse(((MessageChannelBinderSupport) binder).getApplicationContext().containsBean("queue:foo"));
}
}
protected Collection<?> getBindings(MessageBus testMessageBus) {
if (testMessageBus instanceof AbstractTestMessageBus) {
return getBindingsFromMsgBus(((AbstractTestMessageBus) testMessageBus).getCoreMessageBus());
protected Collection<?> getBindings(Binder testBinder) {
if (testBinder instanceof AbstractTestBinder) {
return getBindingsFromBinder(((AbstractTestBinder) testBinder).getCoreBinder());
}
return Collections.EMPTY_LIST;
}
protected Collection<?> getBindingsFromMsgBus(MessageBus messageBus) {
DirectFieldAccessor accessor = new DirectFieldAccessor(messageBus);
protected Collection<?> getBindingsFromBinder(Binder binder) {
DirectFieldAccessor accessor = new DirectFieldAccessor(binder);
return (List<?>) accessor.getPropertyValue("bindings");
}
@@ -292,19 +292,19 @@ public abstract class AbstractMessageBusTests {
return new PojoCodec();
}
protected abstract MessageBus getMessageBus() throws Exception;
protected abstract Binder getBinder() throws Exception;
@After
public void cleanup() {
if (testMessageBus != null) {
testMessageBus.cleanup();
if (testBinder != null) {
testBinder.cleanup();
}
}
/**
* If appropriate, let the bus middleware settle down a bit while binding/unbinding actually happens.
* If appropriate, let the binder middleware settle down a bit while binding/unbinding actually happens.
*/
protected void busBindUnbindLatency() throws InterruptedException {
protected void binderBindUnbindLatency() throws InterruptedException {
// default none
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.HashSet;
import java.util.Properties;
@@ -25,65 +25,65 @@ import org.springframework.messaging.MessageChannel;
/**
* Abstract class that adds test support for {@link MessageBus}.
* Abstract class that adds test support for {@link Binder}.
*
* @author Ilayaperumal Gopinathan
* @author Gary Russell
*/
public abstract class AbstractTestMessageBus<C extends MessageBusSupport> implements MessageBus {
public abstract class AbstractTestBinder<C extends MessageChannelBinderSupport> implements Binder<MessageChannel> {
protected Set<String> queues = new HashSet<String>();
protected Set<String> topics = new HashSet<String>();
private C messageBus;
private C binder;
public void setMessageBus(C messageBus) {
messageBus.setIntegrationEvaluationContext(new StandardEvaluationContext());
public void setBinder(C binder) {
binder.setIntegrationEvaluationContext(new StandardEvaluationContext());
try {
messageBus.afterPropertiesSet();
binder.afterPropertiesSet();
}
catch (Exception e) {
throw new RuntimeException("Failed to initialize message bus", e);
throw new RuntimeException("Failed to initialize binder", e);
}
this.messageBus = messageBus;
this.binder = binder;
}
@Override
public void bindConsumer(String name, MessageChannel moduleInputChannel, Properties properties) {
messageBus.bindConsumer(name, moduleInputChannel, properties);
binder.bindConsumer(name, moduleInputChannel, properties);
queues.add(name);
}
@Override
public void bindPubSubConsumer(String name, MessageChannel inputChannel, Properties properties) {
messageBus.bindPubSubConsumer(name, inputChannel, properties);
binder.bindPubSubConsumer(name, inputChannel, properties);
addTopic(name);
}
@Override
public void bindProducer(String name, MessageChannel moduleOutputChannel, Properties properties) {
messageBus.bindProducer(name, moduleOutputChannel, properties);
binder.bindProducer(name, moduleOutputChannel, properties);
queues.add(name);
}
@Override
public void bindPubSubProducer(String name, MessageChannel outputChannel, Properties properties) {
messageBus.bindPubSubProducer(name, outputChannel, properties);
binder.bindPubSubProducer(name, outputChannel, properties);
addTopic(name);
}
@Override
public void bindRequestor(String name, MessageChannel requests, MessageChannel replies,
Properties properties) {
messageBus.bindRequestor(name, requests, replies, properties);
binder.bindRequestor(name, requests, replies, properties);
queues.add(name + ".requests");
}
@Override
public void bindReplier(String name, MessageChannel requests, MessageChannel replies,
Properties properties) {
messageBus.bindReplier(name, requests, replies, properties);
binder.bindReplier(name, requests, replies, properties);
queues.add(name + ".requests");
}
@@ -91,51 +91,51 @@ public abstract class AbstractTestMessageBus<C extends MessageBusSupport> implem
topics.add("topic." + topicName);
}
public C getCoreMessageBus() {
return messageBus;
public C getCoreBinder() {
return binder;
}
public abstract void cleanup();
@Override
public void unbindConsumers(String name) {
messageBus.unbindConsumers(name);
binder.unbindConsumers(name);
}
@Override
public void unbindProducers(String name) {
messageBus.unbindProducers(name);
binder.unbindProducers(name);
}
@Override
public void unbindConsumer(String name, MessageChannel channel) {
messageBus.unbindConsumer(name, channel);
binder.unbindConsumer(name, channel);
}
@Override
public void unbindProducer(String name, MessageChannel channel) {
messageBus.unbindProducer(name, channel);
binder.unbindProducer(name, channel);
}
@Override
public MessageChannel bindDynamicProducer(String name, Properties properties) {
this.queues.add(name);
return this.messageBus.bindDynamicProducer(name, properties);
return this.binder.bindDynamicProducer(name, properties);
}
@Override
public MessageChannel bindDynamicPubSubProducer(String name, Properties properties) {
this.topics.add(name);
return this.messageBus.bindDynamicPubSubProducer(name, properties);
return this.binder.bindDynamicPubSubProducer(name, properties);
}
@Override
public boolean isCapable(Capability capability) {
return this.messageBus.isCapable(capability);
return this.binder.isCapable(capability);
}
public MessageBus getMessageBus() {
return this.messageBus;
public Binder getBinder() {
return this.binder;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -30,7 +30,7 @@ import org.springframework.integration.support.utils.IntegrationUtils;
*
* @author Gary Russell
*/
public class BusTestUtils {
public class BinderTestUtils {
private static final MessageBuilderFactory mbf = new DefaultMessageBuilderFactory();

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -35,25 +35,25 @@ import org.springframework.messaging.support.GenericMessage;
/**
* Tests for buses that use an external broker.
* Tests for binders that use an external broker.
*
* @author Gary Russell
*/
public abstract class BrokerBusTests extends
AbstractMessageBusTests {
public abstract class BrokerBinderTests extends
AbstractBinderTests {
@Test
public void testDirectBinding() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.setProperty(BusProperties.DIRECT_BINDING_ALLOWED, "true");
properties.setProperty(BinderProperties.DIRECT_BINDING_ALLOWED, "true");
DirectChannel moduleInputChannel = new DirectChannel();
moduleInputChannel.setBeanName("direct.input");
DirectChannel moduleOutputChannel = new DirectChannel();
moduleOutputChannel.setBeanName("direct.output");
bus.bindConsumer("direct.0", moduleInputChannel, null);
bus.bindProducer("direct.0", moduleOutputChannel, properties);
binder.bindConsumer("direct.0", moduleInputChannel, null);
binder.bindProducer("direct.0", moduleOutputChannel, properties);
final AtomicReference<Thread> caller = new AtomicReference<Thread>();
final AtomicInteger count = new AtomicInteger();
@@ -74,9 +74,9 @@ AbstractMessageBusTests {
assertEquals(2, count.get());
assertNull(spyOn("direct.0").receive(true));
// Remove direct binding and bind producer to the bus
bus.unbindConsumers("direct.0");
busBindUnbindLatency();
// Remove direct binding and bind producer to the binder
binder.unbindConsumers("direct.0");
binderBindUnbindLatency();
Spy spy = spyOn("direct.0");
count.set(0);
@@ -88,9 +88,9 @@ AbstractMessageBusTests {
assertEquals("baz", baz);
assertEquals(0, count.get());
// Unbind producer from bus and bind directly again
// Unbind producer from binder and bind directly again
caller.set(null);
bus.bindConsumer("direct.0", moduleInputChannel, null);
binder.bindConsumer("direct.0", moduleInputChannel, null);
moduleOutputChannel.send(new GenericMessage<String>("foo"));
moduleOutputChannel.send(new GenericMessage<String>("foo"));
assertNotNull(caller.get());
@@ -98,8 +98,8 @@ AbstractMessageBusTests {
assertEquals(2, count.get());
assertNull(spy.receive(true));
bus.unbindProducers("direct.0");
bus.unbindConsumers("direct.0");
binder.unbindProducers("direct.0");
binder.unbindConsumers("direct.0");
}
/**

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -41,30 +41,29 @@ import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.xd.test.TestUtils;
/**
* Tests for buses that support partitioning.
* Tests for binders that support partitioning.
*
* @author Gary Russell
*/
abstract public class PartitionCapableBusTests extends BrokerBusTests {
abstract public class PartitionCapableBinderTests extends BrokerBinderTests {
@Test
public void testBadProperties() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("foo", "bar");
properties.put("baz", "qux");
DirectChannel output = new DirectChannel();
try {
bus.bindProducer("badprops.0", output, properties);
binder.bindProducer("badprops.0", output, properties);
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), allOf(Matchers.containsString(bus.getClass().getSimpleName().replace("Test", "")
+ " does not support producer "),
assertThat(e.getMessage(), allOf(Matchers.containsString(getClassUnderTestName()
+ " does not support producer "),
containsString("foo"),
containsString("baz"),
containsString(" for badprops.0.")));
@@ -72,28 +71,28 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
properties.remove("baz");
try {
bus.bindConsumer("badprops.0", output, properties);
binder.bindConsumer("badprops.0", output, properties);
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage(), equalTo(bus.getClass().getSimpleName().replace("Test", "")
assertThat(e.getMessage(), equalTo(getClassUnderTestName()
+ " does not support consumer property: foo for badprops.0."));
}
}
@Test
public void testPartitionedModuleSpEL() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("partitionKeyExpression", "payload");
properties.put("partitionSelectorExpression", "hashCode()");
properties.put(BusProperties.NEXT_MODULE_COUNT, "3");
properties.put(BusProperties.NEXT_MODULE_CONCURRENCY, "2");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "3");
properties.put(BinderProperties.NEXT_MODULE_CONCURRENCY, "2");
DirectChannel output = new DirectChannel();
output.setBeanName("test.output");
bus.bindProducer("part.0", output, properties);
binder.bindProducer("part.0", output, properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
try {
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
@@ -109,21 +108,21 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
properties.put("count","3");
QueueChannel input0 = new QueueChannel();
input0.setBeanName("test.input0S");
bus.bindConsumer("part.0", input0, properties);
binder.bindConsumer("part.0", input0, properties);
properties.put("partitionIndex", "1");
QueueChannel input1 = new QueueChannel();
input1.setBeanName("test.input1S");
bus.bindConsumer("part.0", input1, properties);
binder.bindConsumer("part.0", input1, properties);
properties.put("partitionIndex", "2");
QueueChannel input2 = new QueueChannel();
input2.setBeanName("test.input2S");
bus.bindConsumer("part.0", input2, properties);
binder.bindConsumer("part.0", input2, properties);
Message<Integer> message2 = MessageBuilder.withPayload(2)
.setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "foo")
.setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 42)
.setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 43)
.setHeader("xdReplyChannel", "bar")
.setHeader(BinderHeaders.BINDER_REPLY_CHANNEL, "bar")
.build();
output.send(message2);
output.send(new GenericMessage<Integer>(1));
@@ -144,7 +143,7 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
boolean result = "foo".equals(accessor.getCorrelationId()) &&
42 == accessor.getSequenceNumber() &&
43 == accessor.getSequenceSize() &&
"bar".equals(accessor.getHeader("xdReplyChannel"));
"bar".equals(accessor.getHeader(BinderHeaders.BINDER_REPLY_CHANNEL));
return result;
}
};
@@ -177,24 +176,24 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
}
bus.unbindConsumers("part.0");
bus.unbindProducers("part.0");
binder.unbindConsumers("part.0");
binder.unbindProducers("part.0");
}
@Test
public void testPartitionedModuleJava() throws Exception {
MessageBus bus = getMessageBus();
Binder binder = getBinder();
Properties properties = new Properties();
properties.put("partitionKeyExtractorClass", "org.springframework.xd.dirt.integration.bus.PartitionTestSupport");
properties.put("partitionSelectorClass", "org.springframework.xd.dirt.integration.bus.PartitionTestSupport");
properties.put(BusProperties.NEXT_MODULE_COUNT, "3");
properties.put(BusProperties.NEXT_MODULE_CONCURRENCY, "2");
properties.put("partitionKeyExtractorClass", "org.springframework.cloud.stream.binder.PartitionTestSupport");
properties.put("partitionSelectorClass", "org.springframework.cloud.stream.binder.PartitionTestSupport");
properties.put(BinderProperties.NEXT_MODULE_COUNT, "3");
properties.put(BinderProperties.NEXT_MODULE_CONCURRENCY, "2");
DirectChannel output = new DirectChannel();
output.setBeanName("test.output");
bus.bindProducer("partJ.0", output, properties);
binder.bindProducer("partJ.0", output, properties);
@SuppressWarnings("unchecked")
List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class);
List<Binding> bindings = TestUtils.getPropertyValue(binder, "binder.bindings", List.class);
assertEquals(1, bindings.size());
if (usesExplicitRouting()) {
AbstractEndpoint endpoint = bindings.get(0).getEndpoint();
@@ -207,15 +206,15 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
properties.put("partitionIndex", "0");
QueueChannel input0 = new QueueChannel();
input0.setBeanName("test.input0J");
bus.bindConsumer("partJ.0", input0, properties);
binder.bindConsumer("partJ.0", input0, properties);
properties.put("partitionIndex", "1");
QueueChannel input1 = new QueueChannel();
input1.setBeanName("test.input1J");
bus.bindConsumer("partJ.0", input1, properties);
binder.bindConsumer("partJ.0", input1, properties);
properties.put("partitionIndex", "2");
QueueChannel input2 = new QueueChannel();
input2.setBeanName("test.input2J");
bus.bindConsumer("partJ.0", input2, properties);
binder.bindConsumer("partJ.0", input2, properties);
output.send(new GenericMessage<Integer>(2));
output.send(new GenericMessage<Integer>(1));
@@ -242,12 +241,12 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
containsInAnyOrder(0, 1, 2));
}
bus.unbindConsumers("partJ.0");
bus.unbindProducers("partJ.0");
binder.unbindConsumers("partJ.0");
binder.unbindProducers("partJ.0");
}
/**
* Implementations should return whether the bus under test uses "explicit" routing (e.g. Rabbit)
* Implementations should return whether the binder under test uses "explicit" routing (e.g. Rabbit)
* whereby XD is responsible for assigning a partition and knows which exact consumer will receive the
* message (i.e. honor "partitionIndex") or "implicit" routing (e.g. Kafka) whereby the only guarantee
* is that messages will be spread, but we don't control exactly which consumer gets which message.
@@ -267,5 +266,7 @@ abstract public class PartitionCapableBusTests extends BrokerBusTests {
protected String getPubSubEndpointRouting(AbstractEndpoint endpoint) {
throw new UnsupportedOperationException();
}
protected abstract String getClassUnderTestName();
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import org.springframework.messaging.Message;

View File

@@ -1,4 +1,4 @@
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
/**
* Represents an out-of-band connection to the underlying middleware,

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.test;
package org.springframework.cloud.stream.binder;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.util.Assert;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.io.IOException;
import java.util.Collections;
@@ -31,7 +31,7 @@ import org.springframework.messaging.converter.ContentTypeResolver;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.xd.dirt.integration.bus.MessageBusSupport.JavaClassMimeTypeConversion;
import org.springframework.cloud.stream.binder.MessageChannelBinderSupport.JavaClassMimeTypeConversion;
import org.springframework.xd.dirt.integration.bus.serializer.kryo.PojoCodec;
import org.springframework.xd.tuple.DefaultTuple;
import org.springframework.xd.tuple.Tuple;
@@ -46,33 +46,33 @@ import static org.junit.Assert.assertSame;
* @author Gary Russell
* @author David Turanski
*/
public class MessageBusSupportTests {
public class MessageChannelBinderSupportTests {
private ContentTypeResolver contentTypeResolver = new StringConvertingContentTypeResolver();
private final TestMessageBus messageBus = new TestMessageBus();
private final TestMessageChannelBinder binder = new TestMessageChannelBinder();
@SuppressWarnings({"unchecked", "rawtypes"})
@Before
public void setUp() {
messageBus.setCodec(new PojoCodec(new TupleKryoRegistrar()));
binder.setCodec(new PojoCodec(new TupleKryoRegistrar()));
}
@Test
public void testBytesPassThru() {
byte[] payload = "foo".getBytes();
Message<byte[]> message = MessageBuilder.withPayload(payload).build();
MessageValues converted = messageBus.serializePayloadIfNecessary(message
MessageValues converted = binder.serializePayloadIfNecessary(message
);
assertSame(payload, converted.getPayload());
Message<?> convertedMessage = converted.toMessage();
assertSame(payload, convertedMessage.getPayload());
assertEquals(MimeTypeUtils.APPLICATION_OCTET_STREAM,
contentTypeResolver.resolve(convertedMessage.getHeaders()));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(convertedMessage);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(convertedMessage);
payload = (byte[]) reconstructed.getPayload();
assertSame(converted.getPayload(), payload);
assertNull(reconstructed.get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(reconstructed.get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
}
@Test
@@ -81,29 +81,29 @@ public class MessageBusSupportTests {
Message<byte[]> message = MessageBuilder.withPayload(payload)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE)
.build();
MessageValues messageValues = messageBus.serializePayloadIfNecessary(message
MessageValues messageValues = binder.serializePayloadIfNecessary(message
);
Message<?> converted = messageValues.toMessage();
assertSame(payload, converted.getPayload());
assertEquals(MimeTypeUtils.APPLICATION_OCTET_STREAM,
contentTypeResolver.resolve(converted.getHeaders()));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
payload = (byte[]) reconstructed.getPayload();
assertSame(converted.getPayload(), payload);
assertEquals(MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE,
reconstructed.get(MessageHeaders.CONTENT_TYPE));
assertNull(reconstructed.get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
assertNull(reconstructed.get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
}
@Test
public void testString() throws IOException {
MessageValues convertedValues = messageBus.serializePayloadIfNecessary(
MessageValues convertedValues = binder.serializePayloadIfNecessary(
new GenericMessage<String>("foo"));
Message<?> converted = convertedValues.toMessage();
assertEquals(MimeTypeUtils.TEXT_PLAIN,
contentTypeResolver.resolve(converted.getHeaders()));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
assertEquals("foo", reconstructed.getPayload());
assertNull(reconstructed.get(MessageHeaders.CONTENT_TYPE));
}
@@ -113,7 +113,7 @@ public class MessageBusSupportTests {
Message<String> inbound = MessageBuilder.withPayload("{\"foo\":\"foo\"}")
.copyHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON))
.build();
MessageValues convertedValues = messageBus.serializePayloadIfNecessary(
MessageValues convertedValues = binder.serializePayloadIfNecessary(
inbound);
Message<?> converted = convertedValues.toMessage();
@@ -121,15 +121,15 @@ public class MessageBusSupportTests {
assertEquals(MimeTypeUtils.TEXT_PLAIN,
contentTypeResolver.resolve(converted.getHeaders()));
assertEquals(MimeTypeUtils.APPLICATION_JSON,
converted.getHeaders().get(XdHeaders.XD_ORIGINAL_CONTENT_TYPE));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
converted.getHeaders().get(BinderHeaders.BINDER_ORIGINAL_CONTENT_TYPE));
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
assertEquals("{\"foo\":\"foo\"}", reconstructed.getPayload());
assertEquals(MimeTypeUtils.APPLICATION_JSON, reconstructed.get(MessageHeaders.CONTENT_TYPE));
}
@Test
public void testPojoSerialization() {
MessageValues convertedValues = messageBus.serializePayloadIfNecessary(
MessageValues convertedValues = binder.serializePayloadIfNecessary(
new GenericMessage<Foo>(new Foo("bar"))
);
Message<?> converted = convertedValues.toMessage();
@@ -138,14 +138,14 @@ public class MessageBusSupportTests {
assertEquals("x-java-object", mimeType.getSubtype());
assertEquals(Foo.class.getName(), mimeType.getParameter("type"));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
assertEquals("bar", ((Foo) reconstructed.getPayload()).getBar());
assertNull(reconstructed.get(MessageHeaders.CONTENT_TYPE));
}
@Test
public void testPojoWithXJavaObjectMimeTypeNoType() {
MessageValues convertedValues = messageBus.serializePayloadIfNecessary(
MessageValues convertedValues = binder.serializePayloadIfNecessary(
new GenericMessage<Foo>(new Foo("bar"))
);
Message<?> converted = convertedValues.toMessage();
@@ -154,14 +154,14 @@ public class MessageBusSupportTests {
assertEquals("x-java-object", mimeType.getSubtype());
assertEquals(Foo.class.getName(), mimeType.getParameter("type"));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
assertEquals("bar", ((Foo) reconstructed.getPayload()).getBar());
assertNull(reconstructed.get(MessageHeaders.CONTENT_TYPE));
}
@Test
public void testPojoWithXJavaObjectMimeTypeExplicitType() {
MessageValues convertedValues = messageBus.serializePayloadIfNecessary(
MessageValues convertedValues = binder.serializePayloadIfNecessary(
new GenericMessage<Foo>(new Foo("bar"))
);
Message<?> converted = convertedValues.toMessage();
@@ -170,7 +170,7 @@ public class MessageBusSupportTests {
assertEquals("x-java-object", mimeType.getSubtype());
assertEquals(Foo.class.getName(), mimeType.getParameter("type"));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
assertEquals("bar", ((Foo) reconstructed.getPayload()).getBar());
assertNull(reconstructed.get(MessageHeaders.CONTENT_TYPE));
}
@@ -178,7 +178,7 @@ public class MessageBusSupportTests {
@Test
public void testTupleSerialization() {
Tuple payload = TupleBuilder.tuple().of("foo", "bar");
MessageValues convertedValues = messageBus.serializePayloadIfNecessary(new GenericMessage<Tuple>(payload)
MessageValues convertedValues = binder.serializePayloadIfNecessary(new GenericMessage<Tuple>(payload)
);
Message<?> converted = convertedValues.toMessage();
MimeType mimeType = contentTypeResolver.resolve(converted.getHeaders());
@@ -186,7 +186,7 @@ public class MessageBusSupportTests {
assertEquals("x-java-object", mimeType.getSubtype());
assertEquals(DefaultTuple.class.getName(), mimeType.getParameter("type"));
MessageValues reconstructed = messageBus.deserializePayloadIfNecessary(converted);
MessageValues reconstructed = binder.deserializePayloadIfNecessary(converted);
assertEquals("bar", ((Tuple) reconstructed.getPayload()).getString("foo"));
assertNull(reconstructed.get(MessageHeaders.CONTENT_TYPE));
}
@@ -268,7 +268,7 @@ public class MessageBusSupportTests {
}
public class TestMessageBus extends MessageBusSupport {
public class TestMessageChannelBinder extends MessageChannelBinderSupport {
@Override
public void bindConsumer(String name, MessageChannel channel, Properties properties) {

View File

@@ -1,5 +0,0 @@
/**
* This package contains an implementation of the {@link org.springframework.xd.dirt.integration.bus.MessageBus} for RabbitMQ.
*/
package org.springframework.xd.dirt.integration.rabbit;

View File

@@ -1,5 +0,0 @@
/**
* This package contains an implementation of the {@link org.springframework.xd.dirt.integration.bus.MessageBus} for Redis.
*/
package org.springframework.xd.dirt.integration.redis;

View File

@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-test</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cloud-stream-binding-test</name>
<description>Test support for binding implementations</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-bindings-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-amqp.version>1.4.5.RELEASE</spring-amqp.version>
</properties>
<dependencies>
<!-- There's no comparison with gradle's syntax, but I think we'll be happy sticking with
maven for the superior dependency and project management -->
<!--
compile ("org.springframework.integration:spring-integration-test"){
exclude group: 'org.apache.avro', module: 'avro-compiler'
}
compile "org.springframework.integration:spring-integration-amqp"
compile "org.springframework.integration:spring-integration-redis"
compile "org.springframework.integration:spring-integration-mqtt"
compile ("org.springframework.integration:spring-integration-kafka:$springIntegrationKafkaVersion") {
exclude group: 'org.apache.avro', module: 'avro-compiler'
}
-->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-test</artifactId>
<version>${spring-integration.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.avro</groupId>
<artifactId>avro-compiler</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.integration</groupId>-->
<!--<artifactId>spring-integration-redis</artifactId>-->
<!--<version>${spring-integration.version}</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework.integration</groupId>-->
<!--<artifactId>spring-integration-mqtt</artifactId>-->
<!--<version>${spring-integration.version}</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework.integration</groupId>-->
<!--<artifactId>spring-integration-kafka</artifactId>-->
<!--<version>1.1.2.RELEASE</version>-->
<!--<exclusions>-->
<!--<exclusion>-->
<!--<groupId>org.apache.avro</groupId>-->
<!--<artifactId>avro-compiler</artifactId>-->
<!--</exclusion>-->
<!--</exclusions>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.kafka</groupId>-->
<!--<artifactId>kafka_2.10</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.kafka</groupId>-->
<!--<artifactId>kafka_2.10</artifactId>-->
<!--<classifier>test</classifier>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.kafka</groupId>-->
<!--<artifactId>kafka-clients</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.curator</groupId>-->
<!--<artifactId>curator-test</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.amqp</groupId>-->
<!--<artifactId>spring-rabbit</artifactId>-->
<!--<version>${spring-amqp.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.xd</groupId>
<artifactId>spring-xd-tuple</artifactId>
<version>${spring-xd.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.xd</groupId>
<artifactId>spring-xd-codec</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-spi</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-codec</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -19,10 +19,6 @@
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-common</artifactId>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo-shaded</artifactId>

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus.serializer;
import org.springframework.cloud.stream.exception.CloudStreamsRuntimeException;
/**
* Thrown when something goes wrong with inter-module communication.
*
* @author David Turanski
*/
@SuppressWarnings("serial")
public class SerializationException extends CloudStreamsRuntimeException {
public SerializationException(String message) {
super(message);
}
public SerializationException(String message, Throwable t) {
super(message, t);
}
}

View File

@@ -22,7 +22,7 @@ import com.esotericsoftware.kryo.Registration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.xd.dirt.integration.bus.serializer.SerializationException;
import org.springframework.core.serializer.support.SerializationFailedException;
/**
* @author David Turanski
@@ -38,7 +38,7 @@ public abstract class AbstractKryoRegistrar implements KryoRegistrar {
register(kryo, registration);
}
}
public abstract List<Registration> getRegistrations();
protected void register(Kryo kryo, Registration registration) {
@@ -47,11 +47,11 @@ public abstract class AbstractKryoRegistrar implements KryoRegistrar {
Registration existing = kryo.getRegistration(id);
if (existing != null) {
throw new SerializationException(String.format("registration already exists %s", existing));
throw new SerializationFailedException(String.format("registration already exists %s", existing));
}
log.info("registering {} with serializer {}", registration, registration.getSerializer().getClass()
.getName());
.getName());
kryo.register(registration);
}

View File

@@ -20,9 +20,9 @@ import java.util.List;
import com.esotericsoftware.kryo.Registration;
import org.springframework.core.serializer.support.SerializationFailedException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.xd.dirt.integration.bus.serializer.SerializationException;
/**
* A {@link KryoRegistrar} that delegates and validates
@@ -37,7 +37,7 @@ public class CompositeKryoRegistrar extends AbstractKryoRegistrar {
public CompositeKryoRegistrar(List<KryoRegistrar> delegates) {
super();
this.delegates = delegates;
if (!CollectionUtils.isEmpty(this.delegates)) {
validateRegistrations();
}
@@ -60,18 +60,18 @@ public class CompositeKryoRegistrar extends AbstractKryoRegistrar {
Assert.isTrue(registration.getId() >= MIN_REGISTRATION_VALUE, "registration ID must be >= " +
MIN_REGISTRATION_VALUE);
if (ids.contains(registration.getId())) {
throw new SerializationException(String.format("Duplicate registration ID found: %d",
throw new SerializationFailedException(String.format("Duplicate registration ID found: %d",
registration.getId()));
}
ids.add(registration.getId());
if (types.contains(registration.getType())) {
throw new SerializationException(String.format("Duplicate registration found for type: %s",
throw new SerializationFailedException(String.format("Duplicate registration found for type: %s",
registration.getType()));
}
types.add(registration.getType());
log.info("configured Kryo registration {} with serializer {}", registration,
log.info("configured Kryo registration {} with serializer {}", registration,
registration.getSerializer().getClass().getName());
}

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-stream-common</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-stream-common</name>
<description>Spring Cloud Streams common components</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
</dependencies>
</project>

View File

@@ -1,31 +0,0 @@
/*
* Copyright 2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.stream.exception;
/**
* @author David Turanski
*/
public class CloudStreamsRuntimeException extends RuntimeException {
public CloudStreamsRuntimeException(String message, Throwable cause) {
super(message, cause);
}
public CloudStreamsRuntimeException(String message) {
super(message);
}
}

View File

@@ -28,7 +28,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -39,7 +39,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -27,7 +27,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -27,7 +27,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -27,7 +27,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -28,7 +28,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -50,16 +50,16 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-local</artifactId>
<artifactId>spring-cloud-stream-binder-local</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-redis</artifactId>
<artifactId>spring-cloud-stream-binder-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binding-rabbit</artifactId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
<optional>true</optional>
</dependency>
<dependency>

View File

@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.cloud.stream.binder.BinderHeaders;
import org.springframework.cloud.stream.config.ChannelBindingProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -49,11 +50,10 @@ import org.springframework.messaging.core.DestinationResolver;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.XdHeaders;
import org.springframework.cloud.stream.binder.Binder;
/**
* Binds input/output channels to the bus.
* Binds input/output channels to the binder.
*
* @author Mark Fisher
* @author Dave Syer
@@ -64,7 +64,8 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
private static Logger logger = LoggerFactory.getLogger(ChannelBindingAdapter.class);
private MessageBus messageBus;
private Binder<MessageChannel> binder;
private MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
private Collection<OutputChannelBinding> outputChannels = Collections.emptySet();
@@ -86,9 +87,9 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
private Map<String, String> bindings = new HashMap<String, String>();
public ChannelBindingAdapter(ChannelBindingProperties module, MessageBus messageBus) {
public ChannelBindingAdapter(ChannelBindingProperties module, Binder<MessageChannel> binder) {
this.module = module;
this.messageBus = messageBus;
this.binder = binder;
this.channelLocator = new DefaultChannelLocator(module);
}
@@ -179,7 +180,7 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
return;
}
String tapChannelName = channel.getTapChannelName();
this.messageBus.unbindProducers(tapChannelName);
this.binder.unbindProducers(tapChannelName);
channel.setTapped(false);
}
@@ -239,17 +240,17 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
if (name == null) {
continue;
}
this.messageBus.unbindConsumers(name);
this.binder.unbindConsumers(name);
}
for (OutputChannelBinding binding : this.outputChannels) {
String name = this.bindings.get(binding.getRemoteName());
if (name == null) {
continue;
}
this.messageBus.unbindProducers(name);
this.binder.unbindProducers(name);
if (binding.isTapped()) {
String tapChannelName = binding.getTapChannelName();
this.messageBus.unbindProducers(tapChannelName);
this.binder.unbindProducers(tapChannelName);
}
}
}
@@ -322,20 +323,20 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
private void bindMessageConsumer(MessageChannel inputChannel,
String inputChannelName, Properties consumerProperties) {
if (isChannelPubSub(inputChannelName)) {
this.messageBus.bindPubSubConsumer(inputChannelName, inputChannel, consumerProperties);
this.binder.bindPubSubConsumer(inputChannelName, inputChannel, consumerProperties);
}
else {
this.messageBus.bindConsumer(inputChannelName, inputChannel, consumerProperties);
this.binder.bindConsumer(inputChannelName, inputChannel, consumerProperties);
}
}
private void bindMessageProducer(MessageChannel outputChannel,
String outputChannelName, Properties producerProperties) {
if (isChannelPubSub(outputChannelName)) {
this.messageBus.bindPubSubProducer(outputChannelName, outputChannel, producerProperties);
this.binder.bindPubSubProducer(outputChannelName, outputChannel, producerProperties);
}
else {
this.messageBus.bindProducer(outputChannelName, outputChannel, producerProperties);
this.binder.bindProducer(outputChannelName, outputChannel, producerProperties);
}
}
@@ -346,7 +347,7 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
/**
* Creates a wiretap on the output channel and binds the tap channel to
* {@link MessageBus}'s message target.
* {@link org.springframework.cloud.stream.binder.Binder}'s message target.
*
* @param tapChannelName the name of the tap channel
* @param localName the channel to tap
@@ -357,7 +358,7 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
if (channel instanceof ChannelInterceptorAware) {
DirectChannel tapChannel = new DirectChannel();
tapChannel.setBeanName(tapChannelName + ".tap.bridge");
this.messageBus.bindPubSubProducer(tapChannelName, tapChannel, null); // TODO
this.binder.bindPubSubProducer(tapChannelName, tapChannel, null); // TODO
// tap
// producer
// props
@@ -384,7 +385,7 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
public Message<?> preSend(Message<?> message, MessageChannel channel) {
@SuppressWarnings("unchecked")
Collection<Map<String, Object>> history = (Collection<Map<String, Object>>) message
.getHeaders().get(XdHeaders.XD_HISTORY);
.getHeaders().get(BinderHeaders.BINDER_HISTORY);
if (history == null) {
history = new ArrayList<Map<String, Object>>(1);
}
@@ -396,7 +397,7 @@ public class ChannelBindingAdapter implements Lifecycle, ApplicationContextAware
map.put("thread", Thread.currentThread().getName());
history.add(map);
Message<?> out = ChannelBindingAdapter.this.messageBuilderFactory.fromMessage(message)
.setHeader(XdHeaders.XD_HISTORY, history).build();
.setHeader(BinderHeaders.BINDER_HISTORY, history).build();
return out;
}
});

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Properties;
@@ -24,19 +24,19 @@ import org.springframework.messaging.core.DestinationResolutionException;
/**
* A {@link org.springframework.messaging.core.DestinationResolver} implementation that first checks for any channel
* whose name begins with a colon in the {@link MessageBus}.
* whose name begins with a colon in the {@link Binder}.
*
* @author Mark Fisher
* @author Gary Russell
*/
public class MessageBusAwareChannelResolver extends BeanFactoryMessageChannelDestinationResolver {
public class BinderAwareChannelResolver extends BeanFactoryMessageChannelDestinationResolver {
private final MessageBus messageBus;
private final Binder<MessageChannel> binder;
private final Properties producerProperties;
public MessageBusAwareChannelResolver(MessageBus messageBus, Properties producerProperties) {
this.messageBus = messageBus;
public BinderAwareChannelResolver(Binder<MessageChannel> binder, Properties producerProperties) {
this.binder = binder;
this.producerProperties = producerProperties;
}
@@ -49,14 +49,14 @@ public class MessageBusAwareChannelResolver extends BeanFactoryMessageChannelDes
catch (DestinationResolutionException e) {
}
if (name.indexOf(":") != -1) {
if (messageBus != null) {
if (binder != null) {
String[] tokens = name.split(":", 2);
String type = tokens[0];
if ("queue".equals(type)) {
channel = this.messageBus.bindDynamicProducer(name, this.producerProperties);
channel = this.binder.bindDynamicProducer(name, this.producerProperties);
}
else if ("topic".equals(type)) {
channel = this.messageBus.bindDynamicPubSubProducer(name, this.producerProperties);
channel = this.binder.bindDynamicPubSubProducer(name, this.producerProperties);
}
else {
throw new IllegalArgumentException("unrecognized channel type: " + type);

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import java.util.Properties;
@@ -25,18 +25,18 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.integration.router.AbstractMappingMessageRouter;
/**
* A {@link BeanPostProcessor} that sets a {@link MessageBusAwareChannelResolver} on any bean of type
* A {@link BeanPostProcessor} that sets a {@link BinderAwareChannelResolver} on any bean of type
* {@link AbstractMappingMessageRouter} within the context.
*
* @author Mark Fisher
* @author Gary Russell
*/
public class MessageBusAwareRouterBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
public class BinderAwareRouterBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private final MessageBusAwareChannelResolver channelResolver;
private final BinderAwareChannelResolver channelResolver;
public MessageBusAwareRouterBeanPostProcessor(MessageBus messageBus, Properties producerProperties) {
this.channelResolver = new MessageBusAwareChannelResolver(messageBus, producerProperties);
public BinderAwareRouterBeanPostProcessor(Binder binder, Properties producerProperties) {
this.channelResolver = new BinderAwareChannelResolver(binder, producerProperties);
}
@Override

View File

@@ -37,13 +37,13 @@ import org.springframework.cloud.stream.adapter.InputChannelBinding;
import org.springframework.cloud.stream.adapter.OutputChannelBinding;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.binder.BinderAwareRouterBeanPostProcessor;
import org.springframework.cloud.stream.endpoint.ChannelsEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.MessageChannel;
import org.springframework.util.Assert;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.integration.bus.MessageBusAwareRouterBeanPostProcessor;
import org.springframework.cloud.stream.binder.Binder;
/**
* @author Dave Syer
@@ -62,11 +62,11 @@ public class ChannelBindingAdapterConfiguration {
private ChannelLocator channelLocator;
@Autowired
private MessageBus messageBus;
private Binder<MessageChannel> binder;
@Bean
public ChannelBindingAdapter messageBusAdapter() {
ChannelBindingAdapter adapter = new ChannelBindingAdapter(this.module, this.messageBus);
public ChannelBindingAdapter binderAdapter() {
ChannelBindingAdapter adapter = new ChannelBindingAdapter(this.module, this.binder);
adapter.setOutputChannels(getOutputChannels());
adapter.setInputChannels(getInputChannels());
if (this.channelLocator != null) {
@@ -81,7 +81,7 @@ public class ChannelBindingAdapterConfiguration {
}
public void refresh() {
ChannelBindingAdapter adapter = messageBusAdapter();
ChannelBindingAdapter adapter = binderAdapter();
adapter.setOutputChannels(getOutputChannels());
adapter.setInputChannels(getInputChannels());
}
@@ -116,23 +116,23 @@ public class ChannelBindingAdapterConfiguration {
// Nested class to avoid instantiating all of the above early
@Configuration
protected static class MessageBusAwareRouterConfiguration {
protected static class BinderAwareRouterConfiguration {
@Autowired
private ListableBeanFactory beanFactory;
@Bean
public MessageBusAwareRouterBeanPostProcessor messageBusAwareRouterBeanPostProcessor() {
public BinderAwareRouterBeanPostProcessor binderAwareRouterBeanPostProcessor() {
return new MessageBusAwareRouterBeanPostProcessor(createLazyProxy(
this.beanFactory, MessageBus.class), new Properties());
return new BinderAwareRouterBeanPostProcessor(createLazyProxy(
this.beanFactory, Binder.class), new Properties());
}
private <T> T createLazyProxy(ListableBeanFactory beanFactory, Class<T> type) {
ProxyFactory factory = new ProxyFactory();
LazyInitTargetSource source = new LazyInitTargetSource();
source.setTargetClass(type);
source.setTargetBeanName(getBeanNameFor(beanFactory, MessageBus.class));
source.setTargetBeanName(getBeanNameFor(beanFactory, Binder.class));
source.setBeanFactory(beanFactory);
factory.setTargetSource(source);
factory.addAdvice(new PassthruAdvice());
@@ -145,7 +145,7 @@ public class ChannelBindingAdapterConfiguration {
private String getBeanNameFor(ListableBeanFactory beanFactory, Class<?> type) {
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
beanFactory, type, false, false);
Assert.state(names.length == 1, "No unique MessageBus (found " + names.length
Assert.state(names.length == 1, "No unique Binder (found " + names.length
+ ": " + Arrays.asList(names) + ")");
return names[0];
}

View File

@@ -26,7 +26,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.xd.dirt.integration.rabbit.RabbitMessageBus;
import org.springframework.cloud.stream.binder.rabbit.RabbitMessageChannelBinder;
/**
* Bind to services, either locally or in a Lattice environment.
@@ -36,11 +36,11 @@ import org.springframework.xd.dirt.integration.rabbit.RabbitMessageBus;
* @author Glenn Renfro
*/
@Configuration
@ConditionalOnClass(RabbitMessageBus.class)
@ConditionalOnMissingBean(RabbitMessageBus.class)
@ImportResource({ "classpath*:/META-INF/spring-xd/bus/rabbit-bus.xml",
@ConditionalOnClass(RabbitMessageChannelBinder.class)
@ConditionalOnMissingBean(RabbitMessageChannelBinder.class)
@ImportResource({ "classpath*:/META-INF/spring-cloud-stream/binder/rabbit-binder.xml",
"classpath*:/META-INF/spring-xd/analytics/rabbit-analytics.xml" })
@PropertySource("classpath:/META-INF/spring-cloud-streams/rabbit-bus.properties")
@PropertySource("classpath:/META-INF/spring-cloud-stream/rabbit-binder.properties")
public class RabbitServiceConfiguration {
@Configuration
@Profile("cloud")

View File

@@ -20,13 +20,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.Cloud;
import org.springframework.cloud.CloudFactory;
import org.springframework.cloud.stream.binder.redis.RedisMessageChannelBinder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.xd.dirt.integration.redis.RedisMessageBus;
/**
* Bind to services, either locally or in a Lattice environment.
@@ -35,11 +35,11 @@ import org.springframework.xd.dirt.integration.redis.RedisMessageBus;
* @author Dave Syer
*/
@Configuration
@ConditionalOnClass(RedisMessageBus.class)
@ConditionalOnMissingBean(RedisMessageBus.class)
@ImportResource({ "classpath*:/META-INF/spring-xd/bus/redis-bus.xml",
@ConditionalOnClass(RedisMessageChannelBinder.class)
@ConditionalOnMissingBean(RedisMessageChannelBinder.class)
@ImportResource({ "classpath*:/META-INF/spring-cloud-stream/binder/redis-binder.xml",
"classpath*:/META-INF/spring-xd/analytics/redis-analytics.xml" })
@PropertySource("classpath:/META-INF/spring-cloud-streams/redis-bus.properties")
@PropertySource("classpath:/META-INF/spring-cloud-stream/redis-binder.properties")
public class RedisServiceConfiguration {
@Configuration

View File

@@ -1,3 +1,4 @@
#TODO: New naming convention
xd.messagebus.rabbit.default.ackMode: AUTO
xd.messagebus.rabbit.default.autoBindDLQ: false
xd.messagebus.rabbit.default.backOffInitialInterval: 1000

View File

@@ -1,3 +1,4 @@
#TODO: New naming convention
xd.messagebus.redis.default.backOffInitialInterval: 1000
xd.messagebus.redis.default.backOffMaxInterval: 10000
xd.messagebus.redis.default.backOffMultiplier: 2.0

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.xd.dirt.integration.bus;
package org.springframework.cloud.stream.binder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
@@ -35,6 +35,7 @@ import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cloud.stream.binder.local.LocalMessageChannelBinder;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
@@ -48,26 +49,25 @@ import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.xd.dirt.integration.bus.local.LocalMessageBus;
/**
* @author Mark Fisher
* @author Gary Russell
*/
public class MessageBusAwareChannelResolverTests {
public class BinderAwareChannelResolverTests {
private final StaticApplicationContext context = new StaticApplicationContext();
private volatile MessageBusAwareChannelResolver resolver;
private volatile BinderAwareChannelResolver resolver;
private volatile LocalMessageBus bus;
private volatile LocalMessageChannelBinder binder;
@Before
public void setupContext() throws Exception {
this.bus = new LocalMessageBus();
this.bus.setApplicationContext(context);
this.bus.afterPropertiesSet();
this.resolver = new MessageBusAwareChannelResolver(this.bus, null);
this.binder = new LocalMessageChannelBinder();
this.binder.setApplicationContext(context);
this.binder.afterPropertiesSet();
this.resolver = new BinderAwareChannelResolver(this.binder, null);
this.resolver.setBeanFactory(context);
context.getBeanFactory().registerSingleton("channelResolver",
this.resolver);
@@ -79,7 +79,7 @@ public class MessageBusAwareChannelResolverTests {
PollerMetadata poller = new PollerMetadata();
poller.setTrigger(new PeriodicTrigger(1000));
bus.setPoller(poller);
binder.setPoller(poller);
}
@Test
@@ -96,7 +96,7 @@ public class MessageBusAwareChannelResolverTests {
latch.countDown();
}
});
bus.bindConsumer("queue:foo", testChannel, null);
binder.bindConsumer("queue:foo", testChannel, null);
assertEquals(0, received.size());
registered.send(MessageBuilder.withPayload("hello").build());
try {
@@ -128,7 +128,7 @@ public class MessageBusAwareChannelResolverTests {
latch.countDown();
}
});
bus.bindPubSubConsumer("topic:bar", testChannel, null);
binder.bindPubSubConsumer("topic:bar", testChannel, null);
}
assertEquals(0, received.size());
registered.send(MessageBuilder.withPayload("hello").build());
@@ -155,16 +155,16 @@ public class MessageBusAwareChannelResolverTests {
@Test
public void propertyPassthrough() {
Properties properties = new Properties();
MessageBus bus = mock(MessageBus.class);
doReturn(new DirectChannel()).when(bus).bindDynamicProducer("queue:foo", properties);
doReturn(new DirectChannel()).when(bus).bindDynamicPubSubProducer("topic:bar", properties);
MessageBusAwareChannelResolver resolver = new MessageBusAwareChannelResolver(bus, properties);
Binder binder = mock(Binder.class);
doReturn(new DirectChannel()).when(binder).bindDynamicProducer("queue:foo", properties);
doReturn(new DirectChannel()).when(binder).bindDynamicPubSubProducer("topic:bar", properties);
BinderAwareChannelResolver resolver = new BinderAwareChannelResolver(binder, properties);
BeanFactory beanFactory = new DefaultListableBeanFactory();
resolver.setBeanFactory(beanFactory);
resolver.resolveDestination("queue:foo");
resolver.resolveDestination("topic:bar");
verify(bus).bindDynamicProducer("queue:foo", properties);
verify(bus).bindDynamicPubSubProducer("topic:bar", properties);
verify(binder).bindDynamicProducer("queue:foo", properties);
verify(binder).bindDynamicPubSubProducer("topic:bar", properties);
}
}

Some files were not shown because too many files have changed in this diff Show More