INT-3468 MQTT Async Client

JIRA: https://jira.spring.io/browse/INT-3468

Provide an option to not block when sending and emit
events for sends and delivery confirmations.

Also use the async client for the inbound adapter; while
it doesn't make any performance difference, it does
allow us to timeout the disconnect, which we have seen
to cause hangs on the CI servers.

INT-3468 Polishing - Use Events; Add Docs

INT-3468 Doc Polishing

INT-3468 More Polishing - PR Comments

- Only emit delivered event if async
- Add clientId and a new instance counter to events

INT-3468 Polishing

- Pull client instance up to the abstract class and remove references to the Paho implementation from the events
- Improve tests to include a second client

INT-3468 Fix Test Case

Incorrect classname meant the default location for the application
context config was not found on case-sensitive file systems.

Also, don't auto-start the adapters in the context, in case
the broker is not running.

INT-3468: Polishing

INT-3468 Fix Package Tangle; Add 'async-events'

Add an option (default false) to emit events when async is true.
This commit is contained in:
Gary Russell
2014-07-14 10:13:52 +03:00
committed by Artem Bilan
parent 95d81d4949
commit dcdaafc075
25 changed files with 829 additions and 182 deletions

View File

@@ -7,7 +7,7 @@
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/mqtt http://www.springframework.org/schema/integration/mqtt/spring-integration-mqtt.xsd">
<int-mqtt:outbound-channel-adapter id="out" client-id="multiOut"
<int-mqtt:outbound-channel-adapter id="out" client-id="multiOut"
client-factory="multiUriClientFactory"
default-topic="multiServerTests" />

View File

@@ -0,0 +1,293 @@
/*
* Copyright 2002-2014 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.integration.mqtt;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.event.MqttMessageDeliveredEvent;
import org.springframework.integration.mqtt.event.MqttMessageSentEvent;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gary Russell
* @since 4.0
*
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class BackToBackAdapterTests {
@ClassRule
public static final BrokerRunning brokerRunning = BrokerRunning.isRunning(1883);
@Autowired
private MessageChannel out;
@Autowired
private PollableChannel in;
@Test
public void testSingleTopic() {
MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out");
adapter.setDefaultTopic("mqtt-foo");
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.afterPropertiesSet();
adapter.start();
MqttPahoMessageDrivenChannelAdapter inbound = new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883",
"si-test-in", "mqtt-foo");
QueueChannel outputChannel = new QueueChannel();
inbound.setOutputChannel(outputChannel);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
inbound.setTaskScheduler(taskScheduler);
inbound.setBeanFactory(mock(BeanFactory.class));
inbound.afterPropertiesSet();
inbound.start();
adapter.handleMessage(new GenericMessage<String>("foo"));
adapter.stop();
Message<?> out = outputChannel.receive(1000);
assertNotNull(out);
inbound.stop();
assertEquals("foo", out.getPayload());
assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC));
}
@Test
public void testTwoTopics() {
MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out");
adapter.setDefaultTopic("mqtt-foo");
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.afterPropertiesSet();
adapter.start();
MqttPahoMessageDrivenChannelAdapter inbound = new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883",
"si-test-in", "mqtt-foo", "mqtt-bar");
QueueChannel outputChannel = new QueueChannel();
inbound.setOutputChannel(outputChannel);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
inbound.setTaskScheduler(taskScheduler);
inbound.setBeanFactory(mock(BeanFactory.class));
inbound.afterPropertiesSet();
inbound.start();
adapter.handleMessage(new GenericMessage<String>("foo"));
Message<?> message = MessageBuilder.withPayload("bar").setHeader(MqttHeaders.TOPIC, "mqtt-bar").build();
adapter.handleMessage(message);
adapter.stop();
Message<?> out = outputChannel.receive(1000);
assertNotNull(out);
inbound.stop();
assertEquals("foo", out.getPayload());
assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC));
out = outputChannel.receive(1000);
assertNotNull(out);
inbound.stop();
assertEquals("bar", out.getPayload());
assertEquals("mqtt-bar", out.getHeaders().get(MqttHeaders.TOPIC));
}
@Test
public void testAsync() throws Exception {
MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out");
adapter.setDefaultTopic("mqtt-foo");
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.setAsync(true);
adapter.setAsyncEvents(true);
EventPublisher publisher = new EventPublisher();
adapter.setApplicationEventPublisher(publisher);
adapter.afterPropertiesSet();
adapter.start();
MqttPahoMessageDrivenChannelAdapter inbound =
new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "si-test-in", "mqtt-foo");
QueueChannel outputChannel = new QueueChannel();
inbound.setOutputChannel(outputChannel);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
inbound.setTaskScheduler(taskScheduler);
inbound.setBeanFactory(mock(BeanFactory.class));
inbound.afterPropertiesSet();
inbound.start();
GenericMessage<String> message = new GenericMessage<String>("foo");
adapter.handleMessage(message);
verifyEvents(adapter, publisher, message);
adapter.stop();
Message<?> out = outputChannel.receive(10000);
assertNotNull(out);
inbound.stop();
assertEquals("foo", out.getPayload());
assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC));
}
@Test
public void testAsyncPersisted() throws Exception {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
String tmpDir = System.getProperty("java.io.tmpdir") + File.separator + "mqtt_persist";
new File(tmpDir).mkdirs();
MqttClientPersistence persistence = new MqttDefaultFilePersistence(tmpDir);
factory.setPersistence(persistence);
MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out", factory);
adapter.setDefaultTopic("mqtt-foo");
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.setAsync(true);
adapter.setAsyncEvents(true);
adapter.setDefaultQos(1);
EventPublisher publisher1 = new EventPublisher();
adapter.setApplicationEventPublisher(publisher1);
adapter.afterPropertiesSet();
adapter.start();
MqttPahoMessageDrivenChannelAdapter inbound =
new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "si-test-in", "mqtt-foo", "mqtt-bar");
QueueChannel outputChannel = new QueueChannel();
inbound.setOutputChannel(outputChannel);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
inbound.setTaskScheduler(taskScheduler);
inbound.setBeanFactory(mock(BeanFactory.class));
inbound.afterPropertiesSet();
inbound.start();
Message<String> message1 = new GenericMessage<String>("foo");
adapter.handleMessage(message1);
verifyEvents(adapter, publisher1, message1);
Message<String> message2 = MessageBuilder.withPayload("bar")
.setHeader(MqttHeaders.TOPIC, "mqtt-bar")
.build();
EventPublisher publisher2 = new EventPublisher();
adapter.setApplicationEventPublisher(publisher2);
adapter.handleMessage(message2);
verifyEvents(adapter, publisher2, message2);
verifyMessageIds(publisher1, publisher2);
int clientInstance = publisher1.delivered.getClientInstance();
adapter.stop();
adapter.start(); // new client instance
publisher1 = new EventPublisher();
adapter.setApplicationEventPublisher(publisher1);
adapter.handleMessage(message1);
verifyEvents(adapter, publisher1, message1);
publisher2 = new EventPublisher();
adapter.setApplicationEventPublisher(publisher2);
adapter.handleMessage(message2);
verifyEvents(adapter, publisher2, message2);
verifyMessageIds(publisher1, publisher2);
assertNotEquals(clientInstance, publisher1.delivered.getClientInstance());
adapter.stop();
Message<?> out = null;
for (int i = 0; i < 4; i++) {
out = outputChannel.receive(10000);
assertNotNull(out);
if ("foo".equals(out.getPayload())) {
assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC));
}
else if ("bar".equals(out.getPayload())) {
assertEquals("mqtt-bar", out.getHeaders().get(MqttHeaders.TOPIC));
}
else {
fail("unexpected payload " + out.getPayload());
}
}
inbound.stop();
}
private void verifyEvents(MqttPahoMessageHandler adapter, EventPublisher publisher1, Message<String> message1)
throws InterruptedException {
assertTrue(publisher1.latch.await(10, TimeUnit.SECONDS));
assertNotNull(publisher1.sent);
assertNotNull(publisher1.delivered);
assertEquals(publisher1.sent.getMessageId(), publisher1.delivered.getMessageId());
assertEquals(adapter.getClientId(), publisher1.sent.getClientId());
assertEquals(adapter.getClientId(), publisher1.delivered.getClientId());
assertEquals(adapter.getClientInstance(), publisher1.sent.getClientInstance());
assertEquals(adapter.getClientInstance(), publisher1.delivered.getClientInstance());
assertSame(message1, publisher1.sent.getMessage());
}
private void verifyMessageIds(EventPublisher publisher1, EventPublisher publisher2) {
assertNotEquals(publisher1.delivered.getMessageId(), publisher2.delivered.getMessageId());
assertEquals(publisher1.delivered.getClientId(), publisher2.delivered.getClientId());
assertEquals(publisher1.delivered.getClientInstance(), publisher2.delivered.getClientInstance());
}
@Test
public void testMultiURIs() {
out.send(new GenericMessage<String>("foo"));
Message<?> message = in.receive(10000);
assertNotNull(message);
assertEquals("foo", message.getPayload());
}
private class EventPublisher implements ApplicationEventPublisher {
private volatile MqttMessageDeliveredEvent delivered;
private MqttMessageSentEvent sent;
private final CountDownLatch latch = new CountDownLatch(2);
@Override
public void publishEvent(ApplicationEvent event) {
if (event instanceof MqttMessageSentEvent) {
this.sent = (MqttMessageSentEvent) event;
}
else if (event instanceof MqttMessageDeliveredEvent){
this.delivered = (MqttMessageDeliveredEvent) event;
}
latch.countDown();
}
}
}

View File

@@ -1,129 +0,0 @@
/*
* Copyright 2002-2014 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.integration.mqtt;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gary Russell
* @since 4.0
*
*/
@Ignore //TODO transiently
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class BackTobackAdapterTests {
@Rule
public final BrokerRunning brokerRunning = BrokerRunning.isRunning(1883);
@Autowired
public MessageChannel out;
@Autowired
public PollableChannel in;
@Test
public void testSingleTopic() {
MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out");
adapter.setDefaultTopic("mqtt-foo");
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.afterPropertiesSet();
adapter.start();
MqttPahoMessageDrivenChannelAdapter inbound = new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "si-test-in", "mqtt-foo");
QueueChannel outputChannel = new QueueChannel();
inbound.setOutputChannel(outputChannel);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
inbound.setTaskScheduler(taskScheduler);
inbound.setBeanFactory(mock(BeanFactory.class));
inbound.afterPropertiesSet();
inbound.start();
adapter.handleMessage(new GenericMessage<String>("foo"));
adapter.stop();
Message<?> out = outputChannel.receive(1000);
assertNotNull(out);
inbound.stop();
assertEquals("foo", out.getPayload());
assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC));
adapter.stop();
}
@Test
public void testTwoTopics() {
MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out");
adapter.setDefaultTopic("mqtt-foo");
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.afterPropertiesSet();
adapter.start();
MqttPahoMessageDrivenChannelAdapter inbound = new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "si-test-in", "mqtt-foo", "mqtt-bar");
QueueChannel outputChannel = new QueueChannel();
inbound.setOutputChannel(outputChannel);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
inbound.setTaskScheduler(taskScheduler);
inbound.setBeanFactory(mock(BeanFactory.class));
inbound.afterPropertiesSet();
inbound.start();
adapter.handleMessage(new GenericMessage<String>("foo"));
Message<?> message = MessageBuilder.withPayload("bar").setHeader(MqttHeaders.TOPIC, "mqtt-bar").build();
adapter.handleMessage(message);
adapter.stop();
Message<?> out = outputChannel.receive(1000);
assertNotNull(out);
inbound.stop();
assertEquals("foo", out.getPayload());
assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC));
out = outputChannel.receive(1000);
assertNotNull(out);
inbound.stop();
assertEquals("bar", out.getPayload());
assertEquals("mqtt-bar", out.getHeaders().get(MqttHeaders.TOPIC));
adapter.stop();
}
@Test
public void testMultiURIs() {
out.send(new GenericMessage<String>("foo"));
Message<?> message = in.receive(10000);
assertNotNull(message);
assertEquals("foo", message.getPayload());
}
}

View File

@@ -32,7 +32,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
@@ -58,7 +57,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
@Ignore //TODO transiently
public class DownstreamExceptionTests {
@ClassRule

View File

@@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -34,10 +35,12 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.net.SocketFactory;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttToken;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -107,25 +110,27 @@ public class MqttAdapterTests {
factory.setWill(will);
factory = spy(factory);
final MqttClient client = mock(MqttClient.class);
doAnswer(new Answer<MqttClient>() {
final MqttAsyncClient client = mock(MqttAsyncClient.class);
doAnswer(new Answer<MqttAsyncClient>() {
@Override
public MqttClient answer(InvocationOnMock invocation) throws Throwable {
public MqttAsyncClient answer(InvocationOnMock invocation) throws Throwable {
return client;
}
}).when(factory).getClientInstance(anyString(), anyString());
}).when(factory).getAsyncClientInstance(anyString(), anyString());
MqttPahoMessageHandler handler = new MqttPahoMessageHandler("foo", "bar", factory);
handler.setDefaultTopic("mqtt-foo");
handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet();
handler.start();
final MqttToken token = mock(MqttToken.class);
final AtomicBoolean connectCalled = new AtomicBoolean();
doAnswer(new Answer<Object>(){
doAnswer(new Answer<MqttToken>(){
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
public MqttToken answer(InvocationOnMock invocation) throws Throwable {
MqttConnectOptions options = (MqttConnectOptions) invocation.getArguments()[0];
assertEquals(23, options.getConnectionTimeout());
assertEquals(45, options.getKeepAliveInterval());
@@ -137,19 +142,22 @@ public class MqttAdapterTests {
assertEquals("bar", new String(options.getWillMessage().getPayload()));
assertEquals(2, options.getWillMessage().getQos());
connectCalled.set(true);
return null;
return token;
}
}).when(client).connect(any(MqttConnectOptions.class));
doReturn(token).when(client).subscribe(any(String[].class), any(int[].class));
final MqttDeliveryToken deliveryToken = mock(MqttDeliveryToken.class);
final AtomicBoolean publishCalled = new AtomicBoolean();
doAnswer(new Answer<Object>() {
doAnswer(new Answer<MqttDeliveryToken>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
public MqttDeliveryToken answer(InvocationOnMock invocation) throws Throwable {
assertEquals("mqtt-foo", invocation.getArguments()[0]);
MqttMessage message = (MqttMessage) invocation.getArguments()[1];
assertEquals("Hello, world!", new String(message.getPayload()));
publishCalled.set(true);
return null;
return deliveryToken;
}
}).when(client).publish(anyString(), any(MqttMessage.class));
@@ -177,15 +185,16 @@ public class MqttAdapterTests {
factory.setWill(will);
factory = spy(factory);
final MqttClient client = mock(MqttClient.class);
doAnswer(new Answer<MqttClient>() {
final MqttAsyncClient client = mock(MqttAsyncClient.class);
doAnswer(new Answer<MqttAsyncClient>() {
@Override
public MqttClient answer(InvocationOnMock invocation) throws Throwable {
public MqttAsyncClient answer(InvocationOnMock invocation) throws Throwable {
return client;
}
}).when(factory).getClientInstance(anyString(), anyString());
}).when(factory).getAsyncClientInstance(anyString(), anyString());
final MqttToken token = mock(MqttToken.class);
final AtomicBoolean connectCalled = new AtomicBoolean();
doAnswer(new Answer<Object>() {
@@ -202,9 +211,10 @@ public class MqttAdapterTests {
assertEquals("bar", new String(options.getWillMessage().getPayload()));
assertEquals(2, options.getWillMessage().getQos());
connectCalled.set(true);
return null;
return token;
}
}).when(client).connect(any(MqttConnectOptions.class));
doReturn(token).when(client).subscribe(any(String[].class), any(int[].class));
final AtomicReference<MqttCallback> callback = new AtomicReference<MqttCallback>();
doAnswer(new Answer<Object>() {

View File

@@ -28,6 +28,19 @@
client-id="foo"
url="tcp://localhost:1883"
topics="bar, baz"
qos="0, 2"
converter="myConverter"
client-factory="clientFactory"
send-timeout="123"
channel="out" />
<int-mqtt:message-driven-channel-adapter id="twoTopicsSingleQosAdapter"
auto-startup="false"
phase="25"
client-id="foo"
url="tcp://localhost:1883"
topics="bar, baz"
qos="0"
converter="myConverter"
client-factory="clientFactory"
send-timeout="123"

View File

@@ -46,6 +46,9 @@ public class MqttMessageDrivenChannelAdapterParserTests {
@Autowired
private MqttPahoMessageDrivenChannelAdapter twoTopicsAdapter;
@Autowired
private MqttPahoMessageDrivenChannelAdapter twoTopicsSingleQosAdapter;
@Autowired
private MessageChannel out;
@@ -65,6 +68,7 @@ public class MqttMessageDrivenChannelAdapterParserTests {
assertEquals(25, TestUtils.getPropertyValue(oneTopicAdapter, "phase"));
assertEquals("foo", TestUtils.getPropertyValue(oneTopicAdapter, "clientId"));
assertEquals("bar", TestUtils.getPropertyValue(oneTopicAdapter, "topic", String[].class)[0]);
assertEquals(1, TestUtils.getPropertyValue(oneTopicAdapter, "qos", int[].class)[0]);
assertSame(converter, TestUtils.getPropertyValue(oneTopicAdapter, "converter"));
assertEquals(123L, TestUtils.getPropertyValue(oneTopicAdapter, "messagingTemplate.sendTimeout"));
assertSame(out, TestUtils.getPropertyValue(oneTopicAdapter, "outputChannel"));
@@ -74,16 +78,26 @@ public class MqttMessageDrivenChannelAdapterParserTests {
@Test
public void testTwoTopics() {
assertEquals("tcp://localhost:1883", TestUtils.getPropertyValue(oneTopicAdapter, "url"));
assertEquals("tcp://localhost:1883", TestUtils.getPropertyValue(twoTopicsAdapter, "url"));
assertFalse(TestUtils.getPropertyValue(twoTopicsAdapter, "autoStartup", Boolean.class));
assertEquals(25, TestUtils.getPropertyValue(twoTopicsAdapter, "phase"));
assertEquals("foo", TestUtils.getPropertyValue(twoTopicsAdapter, "clientId"));
assertEquals("bar", TestUtils.getPropertyValue(twoTopicsAdapter, "topic", String[].class)[0]);
assertEquals("baz", TestUtils.getPropertyValue(twoTopicsAdapter, "topic", String[].class)[1]);
assertEquals(0, TestUtils.getPropertyValue(twoTopicsAdapter, "qos", int[].class)[0]);
assertEquals(2, TestUtils.getPropertyValue(twoTopicsAdapter, "qos", int[].class)[1]);
assertSame(converter, TestUtils.getPropertyValue(twoTopicsAdapter, "converter"));
assertEquals(123L, TestUtils.getPropertyValue(twoTopicsAdapter, "messagingTemplate.sendTimeout"));
assertSame(out, TestUtils.getPropertyValue(twoTopicsAdapter, "outputChannel"));
assertSame(clientFactory, TestUtils.getPropertyValue(twoTopicsAdapter, "clientFactory"));
}
@Test
public void testTwoTopicsSingleQos() {
assertEquals("bar", TestUtils.getPropertyValue(twoTopicsSingleQosAdapter, "topic", String[].class)[0]);
assertEquals("baz", TestUtils.getPropertyValue(twoTopicsSingleQosAdapter, "topic", String[].class)[1]);
assertEquals(0, TestUtils.getPropertyValue(twoTopicsSingleQosAdapter, "qos", int[].class)[0]);
assertEquals(0, TestUtils.getPropertyValue(twoTopicsSingleQosAdapter, "qos", int[].class)[1]);
}
}

View File

@@ -35,6 +35,8 @@
client-factory="clientFactory"
phase="25"
order="1"
async="true"
async-events="true"
channel="target" />
<bean id="myConverter" class="org.springframework.integration.mqtt.support.DefaultPahoMessageConverter" />

View File

@@ -16,7 +16,11 @@
package org.springframework.integration.mqtt.config.xml;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import org.hamcrest.Matchers;
import org.junit.Test;
@@ -70,6 +74,8 @@ public class MqttOutboundChannelAdapterParserTests {
assertEquals("bar", TestUtils.getPropertyValue(withConverterHandler, "defaultTopic"));
assertSame(converter, TestUtils.getPropertyValue(withConverterHandler, "converter"));
assertSame(clientFactory, TestUtils.getPropertyValue(withConverterHandler, "clientFactory"));
assertFalse(TestUtils.getPropertyValue(withConverterHandler, "async", Boolean.class));
assertFalse(TestUtils.getPropertyValue(withConverterHandler, "asyncEvents", Boolean.class));
Object handler = TestUtils.getPropertyValue(this.withConverterEndpoint, "handler");
@@ -96,6 +102,8 @@ public class MqttOutboundChannelAdapterParserTests {
assertEquals(1, TestUtils.getPropertyValue(defaultConverter, "defaultQos"));
assertTrue(TestUtils.getPropertyValue(defaultConverter, "defaultRetained", Boolean.class));
assertSame(clientFactory, TestUtils.getPropertyValue(withDefaultConverterHandler, "clientFactory"));
assertTrue(TestUtils.getPropertyValue(withDefaultConverterHandler, "async", Boolean.class));
assertTrue(TestUtils.getPropertyValue(withDefaultConverterHandler, "asyncEvents", Boolean.class));
}
}