Fix issue #30 rewind of message ByteBuffer
This commit is contained in:
+5
-3
@@ -245,15 +245,15 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
|||||||
* */
|
* */
|
||||||
private void publish2Subscribers(String topic, AbstractMessage.QOSType qos, ByteBuffer message, boolean retain, Integer messageID) {
|
private void publish2Subscribers(String topic, AbstractMessage.QOSType qos, ByteBuffer message, boolean retain, Integer messageID) {
|
||||||
LOG.debug("publish2Subscribers republishing to existing subscribers that matches the topic {}, content", topic);
|
LOG.debug("publish2Subscribers republishing to existing subscribers that matches the topic {}, content", topic);
|
||||||
LOG.debug("content <{}>", new String(message.array()));
|
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("content <{}>", DebugUtils.payload2Str(message));
|
||||||
LOG.debug("subscription tree {}", subscriptions.dumpTree());
|
LOG.debug("subscription tree {}", subscriptions.dumpTree());
|
||||||
}
|
}
|
||||||
for (final Subscription sub : subscriptions.matches(topic)) {
|
for (final Subscription sub : subscriptions.matches(topic)) {
|
||||||
if (qos.ordinal() > sub.getRequestedQos().ordinal()) {
|
if (qos.ordinal() > sub.getRequestedQos().ordinal()) {
|
||||||
qos = sub.getRequestedQos();
|
qos = sub.getRequestedQos();
|
||||||
}
|
}
|
||||||
|
message.rewind();
|
||||||
LOG.debug("Broker republishing to client <{}> topic <{}> qos <{}>, active {}",
|
LOG.debug("Broker republishing to client <{}> topic <{}> qos <{}>, active {}",
|
||||||
sub.getClientId(), sub.getTopic(), qos, sub.isActive());
|
sub.getClientId(), sub.getTopic(), qos, sub.isActive());
|
||||||
|
|
||||||
@@ -298,7 +298,9 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
|||||||
pubMessage.setPayload(message);
|
pubMessage.setPayload(message);
|
||||||
|
|
||||||
LOG.info("send publish message to <{}> on topic <{}>", clientId, topic);
|
LOG.info("send publish message to <{}> on topic <{}>", clientId, topic);
|
||||||
LOG.debug("content <{}>", new String(message.array()));
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("content <{}>", DebugUtils.payload2Str(message));
|
||||||
|
}
|
||||||
if (pubMessage.getQos() != AbstractMessage.QOSType.MOST_ONE) {
|
if (pubMessage.getQos() != AbstractMessage.QOSType.MOST_ONE) {
|
||||||
pubMessage.setMessageID(messageID);
|
pubMessage.setMessageID(messageID);
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-3
@@ -22,7 +22,6 @@ import org.dna.mqtt.moquette.server.ServerChannel;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +30,7 @@ import org.junit.Test;
|
|||||||
*/
|
*/
|
||||||
public class ProtocolProcessorTest {
|
public class ProtocolProcessorTest {
|
||||||
final static String FAKE_CLIENT_ID = "FAKE_123";
|
final static String FAKE_CLIENT_ID = "FAKE_123";
|
||||||
|
final static String FAKE_CLIENT_ID2 = "FAKE_456";
|
||||||
final static String FAKE_PUBLISHER_ID = "Publisher";
|
final static String FAKE_PUBLISHER_ID = "Publisher";
|
||||||
final static String FAKE_TOPIC = "/news";
|
final static String FAKE_TOPIC = "/news";
|
||||||
|
|
||||||
@@ -76,6 +76,45 @@ public class ProtocolProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MockReceiverChannel implements ServerChannel {
|
||||||
|
// byte m_returnCode;
|
||||||
|
AbstractMessage m_receivedMessage;
|
||||||
|
private Map<Object, Object> m_attributes = new HashMap<Object, Object>();
|
||||||
|
|
||||||
|
public Object getAttribute(Object key) {
|
||||||
|
return m_attributes.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttribute(Object key, Object value) {
|
||||||
|
m_attributes.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdleTime(int idleTime) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close(boolean immediately) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractMessage getMessage() {
|
||||||
|
return this.m_receivedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public byte getReturnCode() {
|
||||||
|
// return this.m_returnCode;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void write(Object value) {
|
||||||
|
try {
|
||||||
|
this.m_receivedMessage = (AbstractMessage) value;
|
||||||
|
// if (this.m_receivedMessage instanceof PublishMessage) {
|
||||||
|
// T buf = (T) this.m_receivedMessage;
|
||||||
|
// }
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new AssertionError("Wrong return code");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws InterruptedException {
|
public void setUp() throws InterruptedException {
|
||||||
connMsg = new ConnectMessage();
|
connMsg = new ConnectMessage();
|
||||||
@@ -151,8 +190,6 @@ public class ProtocolProcessorTest {
|
|||||||
throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//simulate a connect that register a clientID to an IoSession
|
//simulate a connect that register a clientID to an IoSession
|
||||||
@@ -175,6 +212,62 @@ public class ProtocolProcessorTest {
|
|||||||
//TODO check received message attributes
|
//TODO check received message attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPublishToMultipleSubscribers() throws InterruptedException {
|
||||||
|
final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
|
||||||
|
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, true);
|
||||||
|
final Subscription subscriptionClient2 = new Subscription(FAKE_CLIENT_ID2,
|
||||||
|
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, true);
|
||||||
|
|
||||||
|
//subscriptions.matches(topic) redefine the method to return true
|
||||||
|
SubscriptionsStore subs = new SubscriptionsStore() {
|
||||||
|
@Override
|
||||||
|
public List<Subscription> matches(String topic) {
|
||||||
|
if (topic.equals(FAKE_TOPIC)) {
|
||||||
|
return Arrays.asList(subscription, subscriptionClient2);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//simulate a connect that register a clientID to an IoSession
|
||||||
|
subs.init(m_storageService);
|
||||||
|
m_processor.init(subs, m_storageService);
|
||||||
|
|
||||||
|
MockReceiverChannel firstReceiverSession = new MockReceiverChannel();
|
||||||
|
ConnectMessage connectMessage = new ConnectMessage();
|
||||||
|
connectMessage.setProcotolVersion((byte)3);
|
||||||
|
connectMessage.setClientID(FAKE_CLIENT_ID);
|
||||||
|
connectMessage.setCleanSession(subscription.isCleanSession());
|
||||||
|
m_processor.processConnect(firstReceiverSession, connectMessage);
|
||||||
|
|
||||||
|
//connect the second fake subscriber
|
||||||
|
MockReceiverChannel secondReceiverSession = new MockReceiverChannel();
|
||||||
|
ConnectMessage connectMessage2 = new ConnectMessage();
|
||||||
|
connectMessage2.setProcotolVersion((byte)3);
|
||||||
|
connectMessage2.setClientID(FAKE_CLIENT_ID2);
|
||||||
|
connectMessage2.setCleanSession(subscription.isCleanSession());
|
||||||
|
m_processor.processConnect(secondReceiverSession, connectMessage2);
|
||||||
|
|
||||||
|
//Exercise
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
|
||||||
|
PublishEvent pubEvt = new PublishEvent(FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, buffer, false, "FakeCLI", null);
|
||||||
|
m_processor.processPublish(pubEvt);
|
||||||
|
|
||||||
|
//Verify
|
||||||
|
Thread.sleep(100); //ugly but we dependend on the asynch that pull data from back disruptor
|
||||||
|
PublishMessage pub2FirstSubscriber = (PublishMessage) firstReceiverSession.getMessage();
|
||||||
|
assertNotNull(pub2FirstSubscriber);
|
||||||
|
String firstMessageContent = DebugUtils.payload2Str(pub2FirstSubscriber.getPayload());
|
||||||
|
assertEquals("Hello", firstMessageContent);
|
||||||
|
|
||||||
|
PublishMessage pub2SecondSubscriber = (PublishMessage) secondReceiverSession.getMessage();
|
||||||
|
assertNotNull(pub2SecondSubscriber);
|
||||||
|
String secondMessageContent = DebugUtils.payload2Str(pub2SecondSubscriber.getPayload());
|
||||||
|
assertEquals("Hello", secondMessageContent);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSubscribe() {
|
public void testSubscribe() {
|
||||||
//Exercise
|
//Exercise
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ MqttMessage message = new MqttMessage('Hello world!!'.bytes)
|
|||||||
message.setQos(0)
|
message.setQos(0)
|
||||||
print "publishing.."
|
print "publishing.."
|
||||||
long startTime = System.currentTimeMillis()
|
long startTime = System.currentTimeMillis()
|
||||||
(1..100000).each {
|
(1..10).each {
|
||||||
client.publish('topic', 'Hello world!!'.bytes, 0, false)
|
client.publish('topic', 'Hello world!!'.bytes, 0, false)
|
||||||
}
|
}
|
||||||
client.publish('/exit', 'Exit'.bytes, 0, false)
|
client.publish('/exit', 'Exit'.bytes, 0, false)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import java.util.concurrent.CountDownLatch
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SubscriberCallback implements MqttCallback {
|
class SubscriberCallback implements MqttCallback {
|
||||||
|
|
||||||
int m_numReceived = 0
|
int m_numReceived = 0
|
||||||
@@ -42,6 +41,7 @@ class SubscriberCallback implements MqttCallback {
|
|||||||
client.disconnect()
|
client.disconnect()
|
||||||
m_latch.countDown()
|
m_latch.countDown()
|
||||||
} else {
|
} else {
|
||||||
|
println "-received ${message} on ${topic} with QoS ${message.qos}"
|
||||||
m_numReceived++
|
m_numReceived++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,11 +51,18 @@ class SubscriberCallback implements MqttCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
println "Usage subscriber <host> <QoS>"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
String host = args[0]
|
String host = args[0]
|
||||||
|
int qos = args[1] as int
|
||||||
String tmpDir = System.getProperty("java.io.tmpdir")
|
String tmpDir = System.getProperty("java.io.tmpdir")
|
||||||
MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(tmpDir)
|
MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(tmpDir)
|
||||||
|
|
||||||
MqttClient client = new MqttClient("tcp://${host}:1883", "SubscriberClient", dataStore)
|
int rnd = (Math.random() * 100) as int
|
||||||
|
MqttClient client = new MqttClient("tcp://${host}:1883", "SubscriberClient${rnd}", dataStore)
|
||||||
def callback = new SubscriberCallback()
|
def callback = new SubscriberCallback()
|
||||||
client.callback = callback
|
client.callback = callback
|
||||||
client.connect()
|
client.connect()
|
||||||
|
|||||||
Reference in New Issue
Block a user