Merge the switch from byte[] to ByteBuffer
This commit is contained in:
+1
-1
@@ -41,7 +41,7 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.4</version>
|
||||
<version>1.7.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.subscriptions.Subscription;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.events.PublishEvent;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
@@ -18,7 +19,7 @@ public interface IStorageService {
|
||||
* */
|
||||
void initStore();
|
||||
|
||||
void storeRetained(String topic, byte[] message, AbstractMessage.QOSType qos);
|
||||
void storeRetained(String topic, ByteBuffer message, AbstractMessage.QOSType qos);
|
||||
|
||||
Collection<StoredMessage> searchMatching(IMatchingCondition condition);
|
||||
|
||||
|
||||
+57
-30
@@ -1,9 +1,15 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import org.dna.mqtt.moquette.MQTTException;
|
||||
import org.dna.mqtt.moquette.messaging.spi.IMatchingCondition;
|
||||
import org.dna.mqtt.moquette.messaging.spi.IStorageService;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.events.PublishEvent;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.storage.StoredPublishEvent;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.subscriptions.Subscription;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
import org.dna.mqtt.moquette.server.Server;
|
||||
@@ -12,11 +18,6 @@ import org.fusesource.hawtdb.api.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of IStorageService backed by HawtDB
|
||||
@@ -38,8 +39,8 @@ public class HawtDBStorageService implements IStorageService {
|
||||
return m_qos;
|
||||
}
|
||||
|
||||
byte[] getPayload() {
|
||||
return m_payload;
|
||||
ByteBuffer getPayload() {
|
||||
return (ByteBuffer) ByteBuffer.allocate(m_payload.length).put(m_payload).flip();
|
||||
}
|
||||
|
||||
String getTopic() {
|
||||
@@ -54,12 +55,12 @@ public class HawtDBStorageService implements IStorageService {
|
||||
private PageFileFactory pageFactory;
|
||||
|
||||
//maps clientID to the list of pending messages stored
|
||||
private SortedIndex<String, List<PublishEvent>> m_persistentMessageStore;
|
||||
private SortedIndex<String, List<StoredPublishEvent>> m_persistentMessageStore;
|
||||
private SortedIndex<String, StoredMessage> m_retainedStore;
|
||||
//bind clientID+MsgID -> evt message published
|
||||
private SortedIndex<String, PublishEvent> m_inflightStore;
|
||||
private SortedIndex<String, StoredPublishEvent> m_inflightStore;
|
||||
//bind clientID+MsgID -> evt message published
|
||||
private SortedIndex<String, PublishEvent> m_qos2Store;
|
||||
private SortedIndex<String, StoredPublishEvent> m_qos2Store;
|
||||
|
||||
//persistent Map of clientID, set of Subscriptions
|
||||
private SortedIndex<String, Set<Subscription>> m_persistentSubscriptions;
|
||||
@@ -101,10 +102,10 @@ public class HawtDBStorageService implements IStorageService {
|
||||
|
||||
|
||||
private void initPersistentMessageStore() {
|
||||
BTreeIndexFactory<String, List<PublishEvent>> indexFactory = new BTreeIndexFactory<String, List<PublishEvent>>();
|
||||
BTreeIndexFactory<String, List<StoredPublishEvent>> indexFactory = new BTreeIndexFactory<String, List<StoredPublishEvent>>();
|
||||
indexFactory.setKeyCodec(StringCodec.INSTANCE);
|
||||
|
||||
m_persistentMessageStore = (SortedIndex<String, List<PublishEvent>>) m_multiIndexFactory.openOrCreate("persistedMessages", indexFactory);
|
||||
m_persistentMessageStore = (SortedIndex<String, List<StoredPublishEvent>>) m_multiIndexFactory.openOrCreate("persistedMessages", indexFactory);
|
||||
}
|
||||
|
||||
private void initPersistentSubscriptions() {
|
||||
@@ -119,31 +120,33 @@ public class HawtDBStorageService implements IStorageService {
|
||||
* messages in flight.
|
||||
*/
|
||||
private void initInflightMessageStore() {
|
||||
BTreeIndexFactory<String, PublishEvent> indexFactory = new BTreeIndexFactory<String, PublishEvent>();
|
||||
BTreeIndexFactory<String, StoredPublishEvent> indexFactory = new BTreeIndexFactory<String, StoredPublishEvent>();
|
||||
indexFactory.setKeyCodec(StringCodec.INSTANCE);
|
||||
|
||||
m_inflightStore = (SortedIndex<String, PublishEvent>) m_multiIndexFactory.openOrCreate("inflight", indexFactory);
|
||||
m_inflightStore = (SortedIndex<String, StoredPublishEvent>) m_multiIndexFactory.openOrCreate("inflight", indexFactory);
|
||||
}
|
||||
|
||||
private void initPersistentQoS2MessageStore() {
|
||||
BTreeIndexFactory<String, PublishEvent> indexFactory = new BTreeIndexFactory<String, PublishEvent>();
|
||||
BTreeIndexFactory<String, StoredPublishEvent> indexFactory = new BTreeIndexFactory<String, StoredPublishEvent>();
|
||||
indexFactory.setKeyCodec(StringCodec.INSTANCE);
|
||||
|
||||
m_qos2Store = (SortedIndex<String, PublishEvent>) m_multiIndexFactory.openOrCreate("qos2Store", indexFactory);
|
||||
m_qos2Store = (SortedIndex<String, StoredPublishEvent>) m_multiIndexFactory.openOrCreate("qos2Store", indexFactory);
|
||||
}
|
||||
|
||||
public void storeRetained(String topic, byte[] message, AbstractMessage.QOSType qos) {
|
||||
if (message.length == 0) {
|
||||
public void storeRetained(String topic, ByteBuffer message, AbstractMessage.QOSType qos) {
|
||||
if (!message.hasRemaining()) {
|
||||
//clean the message from topic
|
||||
m_retainedStore.remove(topic);
|
||||
} else {
|
||||
//store the message to the topic
|
||||
m_retainedStore.put(topic, new StoredMessage(message, qos, topic));
|
||||
byte[] raw = new byte[message.remaining()];
|
||||
message.get(raw);
|
||||
m_retainedStore.put(topic, new StoredMessage(raw, qos, topic));
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<StoredMessage> searchMatching(IMatchingCondition condition) {
|
||||
LOG.debug("searchMatching scanning all retained messages, presents are " + m_retainedStore.size());
|
||||
LOG.debug("searchMatching scanning all retained messages, presents are {}", m_retainedStore.size());
|
||||
|
||||
List<StoredMessage> results = new ArrayList<StoredMessage>();
|
||||
|
||||
@@ -158,21 +161,29 @@ public class HawtDBStorageService implements IStorageService {
|
||||
}
|
||||
|
||||
public void storePublishForFuture(PublishEvent evt) {
|
||||
List<PublishEvent> storedEvents;
|
||||
List<StoredPublishEvent> storedEvents;
|
||||
String clientID = evt.getClientID();
|
||||
if (!m_persistentMessageStore.containsKey(clientID)) {
|
||||
storedEvents = new ArrayList<PublishEvent>();
|
||||
storedEvents = new ArrayList<StoredPublishEvent>();
|
||||
} else {
|
||||
storedEvents = m_persistentMessageStore.get(clientID);
|
||||
}
|
||||
storedEvents.add(evt);
|
||||
storedEvents.add(convertToStored(evt));
|
||||
m_persistentMessageStore.put(clientID, storedEvents);
|
||||
LOG.debug(String.format("Stored published message for client <%s> on topic <%s>, content %s",
|
||||
clientID, evt.getTopic(), new String(evt.getMessage())));
|
||||
//NB rewind the evt message content
|
||||
LOG.debug("Stored published message for client <{}> on topic <{}>", clientID, evt.getTopic());
|
||||
}
|
||||
|
||||
public List<PublishEvent> retrivePersistedPublishes(String clientID) {
|
||||
return m_persistentMessageStore.get(clientID);
|
||||
List<StoredPublishEvent> storedEvts = m_persistentMessageStore.get(clientID);
|
||||
if (storedEvts == null) {
|
||||
return null;
|
||||
}
|
||||
List<PublishEvent> liveEvts = new ArrayList<PublishEvent>();
|
||||
for (StoredPublishEvent storedEvt : storedEvts) {
|
||||
liveEvts.add(convertFromStored(storedEvt));
|
||||
}
|
||||
return liveEvts;
|
||||
}
|
||||
|
||||
public void cleanPersistedPublishes(String clientID) {
|
||||
@@ -184,7 +195,8 @@ public class HawtDBStorageService implements IStorageService {
|
||||
}
|
||||
|
||||
public void addInFlight(PublishEvent evt, String publishKey) {
|
||||
m_inflightStore.put(publishKey, evt);
|
||||
StoredPublishEvent storedEvt = convertToStored(evt);
|
||||
m_inflightStore.put(publishKey, storedEvt);
|
||||
}
|
||||
|
||||
public void addNewSubscription(Subscription newSubscription, String clientID) {
|
||||
@@ -221,8 +233,8 @@ public class HawtDBStorageService implements IStorageService {
|
||||
|
||||
/*-------- QoS 2 storage management --------------*/
|
||||
public void persistQoS2Message(String publishKey, PublishEvent evt) {
|
||||
LOG.debug(String.format("persistQoS2Message store pubKey %s, evt %s", publishKey, evt));
|
||||
m_qos2Store.put(publishKey, evt);
|
||||
LOG.debug("persistQoS2Message store pubKey {}, evt {}", publishKey, evt);
|
||||
m_qos2Store.put(publishKey, convertToStored(evt));
|
||||
}
|
||||
|
||||
public void removeQoS2Message(String publishKey) {
|
||||
@@ -230,6 +242,21 @@ public class HawtDBStorageService implements IStorageService {
|
||||
}
|
||||
|
||||
public PublishEvent retrieveQoS2Message(String publishKey) {
|
||||
return m_qos2Store.get(publishKey);
|
||||
StoredPublishEvent storedEvt = m_qos2Store.get(publishKey);
|
||||
return convertFromStored(storedEvt);
|
||||
}
|
||||
|
||||
private StoredPublishEvent convertToStored(PublishEvent evt) {
|
||||
StoredPublishEvent storedEvt = new StoredPublishEvent(evt);
|
||||
return storedEvt;
|
||||
}
|
||||
|
||||
private PublishEvent convertFromStored(StoredPublishEvent evt) {
|
||||
byte[] message = evt.getMessage();
|
||||
ByteBuffer bbmessage = ByteBuffer.wrap(message);
|
||||
//bbmessage.flip();
|
||||
PublishEvent liveEvt = new PublishEvent(evt.getTopic(), evt.getQos(),
|
||||
bbmessage, evt.isRetain(), evt.getClientID(), evt.getMessageID(), null);
|
||||
return liveEvt;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -1,5 +1,6 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import org.dna.mqtt.moquette.messaging.spi.IMatchingCondition;
|
||||
import org.dna.mqtt.moquette.messaging.spi.IStorageService;
|
||||
@@ -32,18 +33,20 @@ public class MemoryStorageService implements IStorageService {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
public void storeRetained(String topic, byte[] message, AbstractMessage.QOSType qos) {
|
||||
if (message.length == 0) {
|
||||
public void storeRetained(String topic, ByteBuffer message, AbstractMessage.QOSType qos) {
|
||||
if (!message.hasRemaining()) {
|
||||
//clean the message from topic
|
||||
m_retainedStore.remove(topic);
|
||||
} else {
|
||||
//store the message to the topic
|
||||
m_retainedStore.put(topic, new HawtDBStorageService.StoredMessage(message, qos, topic));
|
||||
byte[] raw = new byte[message.remaining()];
|
||||
message.get(raw);
|
||||
m_retainedStore.put(topic, new HawtDBStorageService.StoredMessage(raw, qos, topic));
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<HawtDBStorageService.StoredMessage> searchMatching(IMatchingCondition condition) {
|
||||
LOG.debug("searchMatching scanning all retained messages, presents are " + m_retainedStore.size());
|
||||
LOG.debug("searchMatching scanning all retained messages, presents are {}", m_retainedStore.size());
|
||||
|
||||
List<HawtDBStorageService.StoredMessage> results = new ArrayList<HawtDBStorageService.StoredMessage>();
|
||||
|
||||
@@ -58,7 +61,7 @@ public class MemoryStorageService implements IStorageService {
|
||||
}
|
||||
|
||||
public void storePublishForFuture(PublishEvent evt) {
|
||||
LOG.debug("storePublishForFuture store evt " + evt);
|
||||
LOG.debug("storePublishForFuture store evt {}", evt);
|
||||
List<PublishEvent> storedEvents;
|
||||
String clientID = evt.getClientID();
|
||||
if (!m_persistentMessageStore.containsKey(clientID)) {
|
||||
@@ -115,7 +118,7 @@ public class MemoryStorageService implements IStorageService {
|
||||
}
|
||||
|
||||
public void persistQoS2Message(String publishKey, PublishEvent evt) {
|
||||
LOG.debug(String.format("persistQoS2Message store pubKey %s, evt %s", publishKey, evt));
|
||||
LOG.debug("persistQoS2Message store pubKey {}, evt {}", publishKey, evt);
|
||||
m_qos2Store.put(publishKey, evt);
|
||||
}
|
||||
|
||||
|
||||
+43
-42
@@ -4,6 +4,7 @@ import com.lmax.disruptor.BatchEventProcessor;
|
||||
import com.lmax.disruptor.EventHandler;
|
||||
import com.lmax.disruptor.RingBuffer;
|
||||
import com.lmax.disruptor.SequenceBarrier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -78,7 +79,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
}
|
||||
|
||||
void processConnect(ServerChannel session, ConnectMessage msg) {
|
||||
LOG.debug("processConnect for client " + msg.getClientID());
|
||||
LOG.debug("processConnect for client {}", msg.getClientID());
|
||||
if (msg.getProcotolVersion() != 0x03) {
|
||||
ConnAckMessage badProto = new ConnAckMessage();
|
||||
badProto.setReturnCode(ConnAckMessage.UNNACEPTABLE_PROTOCOL_VERSION);
|
||||
@@ -112,7 +113,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
m_clientIDs.put(msg.getClientID(), connDescr);
|
||||
|
||||
int keepAlive = msg.getKeepAlive();
|
||||
LOG.debug(String.format("Connect with keepAlive %d s", keepAlive));
|
||||
LOG.debug("Connect with keepAlive {} s", keepAlive);
|
||||
session.setAttribute(Constants.KEEP_ALIVE, keepAlive);
|
||||
session.setAttribute(Constants.CLEAN_SESSION, msg.isCleanSession());
|
||||
//used to track the client in the subscription and publishing phases.
|
||||
@@ -123,8 +124,10 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
//Handle will flag
|
||||
if (msg.isWillFlag()) {
|
||||
AbstractMessage.QOSType willQos = AbstractMessage.QOSType.values()[msg.getWillQos()];
|
||||
PublishEvent pubEvt = new PublishEvent(msg.getWillTopic(), willQos, msg.getWillMessage().getBytes(),
|
||||
msg.isWillRetain(), msg.getClientID(), session);
|
||||
byte[] willPayload = msg.getWillMessage().getBytes();
|
||||
ByteBuffer bb = (ByteBuffer) ByteBuffer.allocate(willPayload.length).put(willPayload).flip();
|
||||
PublishEvent pubEvt = new PublishEvent(msg.getWillTopic(), willQos,
|
||||
bb, msg.isWillRetain(), msg.getClientID(), session);
|
||||
processPublish(pubEvt);
|
||||
}
|
||||
|
||||
@@ -155,7 +158,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
okResp.setReturnCode(ConnAckMessage.CONNECTION_ACCEPTED);
|
||||
LOG.debug("processConnect sent OK ConnAck");
|
||||
session.write(okResp);
|
||||
LOG.info(String.format("Connected client ID <%s> with clean session %s", msg.getClientID(), msg.isCleanSession()));
|
||||
LOG.info("Connected client ID <{}> with clean session {}", msg.getClientID(), msg.isCleanSession());
|
||||
|
||||
if (!msg.isCleanSession()) {
|
||||
//force the republish of stored QoS1 and QoS2
|
||||
@@ -167,11 +170,11 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
LOG.debug("republishStored invoked");
|
||||
List<PublishEvent> publishedEvents = m_storageService.retrivePersistedPublishes(clientID);
|
||||
if (publishedEvents == null) {
|
||||
LOG.info(String.format("No stored messages for client <%s>", clientID));
|
||||
LOG.info("No stored messages for client <{}>", clientID);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info(String.format("republishing stored messages to client <%s>", clientID));
|
||||
LOG.info("republishing stored messages to client <{}>", clientID);
|
||||
for (PublishEvent pubEvt : publishedEvents) {
|
||||
sendPublish(pubEvt.getClientID(), pubEvt.getTopic(), pubEvt.getQos(),
|
||||
pubEvt.getMessage(), false, pubEvt.getMessageID());
|
||||
@@ -179,7 +182,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
}
|
||||
|
||||
private void processRemoveAllSubscriptions(String clientID) {
|
||||
LOG.info(String.format("cleaning old saved subscriptions for client <%s>", clientID));
|
||||
LOG.info("cleaning old saved subscriptions for client <{}>", clientID);
|
||||
subscriptions.removeForClient(clientID);
|
||||
|
||||
//remove also the messages stored of type QoS1/2
|
||||
@@ -190,11 +193,11 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
LOG.debug("processPublish invoked with " + evt);
|
||||
final String topic = evt.getTopic();
|
||||
final AbstractMessage.QOSType qos = evt.getQos();
|
||||
final byte[] message = evt.getMessage();
|
||||
final ByteBuffer message = evt.getMessage();
|
||||
boolean retain = evt.isRetain();
|
||||
|
||||
LOG.info(String.format("Publish recieved from clientID <%s> on topic <%s> with QoS %s",
|
||||
evt.getClientID(), evt.getTopic(), evt.getQos()));
|
||||
LOG.info("Publish recieved from clientID <{}> on topic <{}> with QoS {}",
|
||||
evt.getClientID(), evt.getTopic(), evt.getQos());
|
||||
|
||||
String publishKey = null;
|
||||
if (qos == AbstractMessage.QOSType.LEAST_ONE) {
|
||||
@@ -216,7 +219,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
}
|
||||
m_storageService.cleanInFlight(publishKey);
|
||||
sendPubAck(new PubAckEvent(evt.getMessageID(), evt.getClientID()));
|
||||
LOG.debug("replying with PubAck to MSG ID " + evt.getMessageID());
|
||||
LOG.debug("replying with PubAck to MSG ID {}", evt.getMessageID());
|
||||
}
|
||||
|
||||
if (retain) {
|
||||
@@ -227,11 +230,11 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
/**
|
||||
* Flood the subscribers with the message to notify. MessageID is optional and should only used for QoS 1 and 2
|
||||
* */
|
||||
private void publish2Subscribers(String topic, AbstractMessage.QOSType qos, byte[] message, boolean retain, Integer messageID) {
|
||||
LOG.debug("publish2Subscribers republishing to existing subscribers that matches the topic " + topic);
|
||||
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 {}", topic);
|
||||
for (final Subscription sub : subscriptions.matches(topic)) {
|
||||
LOG.debug(String.format("Broker publishing to client <%s> topic <%s> qos <%s>",
|
||||
sub.getClientId(), sub.getTopic(), qos));
|
||||
LOG.debug("Broker publishing to client <{}> topic <{}> qos <{}>",
|
||||
sub.getClientId(), sub.getTopic(), qos);
|
||||
if (qos == AbstractMessage.QOSType.MOST_ONE) {
|
||||
//QoS 0
|
||||
sendPublish(sub.getClientId(), topic, qos, message, false);
|
||||
@@ -256,19 +259,19 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPublish(String clientId, String topic, AbstractMessage.QOSType qos, byte[] message, boolean retained) {
|
||||
private void sendPublish(String clientId, String topic, AbstractMessage.QOSType qos, ByteBuffer message, boolean retained) {
|
||||
sendPublish(clientId, topic, qos, message, retained, 0);
|
||||
}
|
||||
|
||||
private void sendPublish(String clientId, String topic, AbstractMessage.QOSType qos, byte[] message, boolean retained, int messageID) {
|
||||
private void sendPublish(String clientId, String topic, AbstractMessage.QOSType qos, ByteBuffer message, boolean retained, int messageID) {
|
||||
LOG.debug("notify invoked with event ");
|
||||
PublishMessage pubMessage = new PublishMessage();
|
||||
pubMessage.setRetainFlag(retained);
|
||||
pubMessage.setTopicName(topic);
|
||||
pubMessage.setQos(qos);
|
||||
pubMessage.setPayload(message);
|
||||
LOG.info(String.format("send publish message to <%s> on topic <%s>, message is [%s]",
|
||||
clientId, topic, new String(message)));
|
||||
|
||||
LOG.info("send publish message to <{}> on topic <{}>", clientId, topic);
|
||||
if (pubMessage.getQos() != AbstractMessage.QOSType.MOST_ONE) {
|
||||
pubMessage.setMessageID(messageID);
|
||||
}
|
||||
@@ -277,11 +280,11 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
if (m_clientIDs == null) {
|
||||
throw new RuntimeException("Internal bad error, found m_clientIDs to null while it should be initialized, somewhere it's overwritten!!");
|
||||
}
|
||||
LOG.debug("clientIDs are " + m_clientIDs);
|
||||
LOG.debug("clientIDs are {}", m_clientIDs);
|
||||
if (m_clientIDs.get(clientId) == null) {
|
||||
throw new RuntimeException(String.format("Can't find a ConnectionDescriptor for client %s in cache %s", clientId, m_clientIDs));
|
||||
}
|
||||
LOG.debug("Session for clientId " + clientId + " is " + m_clientIDs.get(clientId).getSession());
|
||||
LOG.debug("Session for clientId {} is {}", clientId, m_clientIDs.get(clientId).getSession());
|
||||
// m_clientIDs.get(clientId).getSession().write(pubMessage);
|
||||
disruptorPublish(new OutputMessagingEvent(m_clientIDs.get(clientId).getSession(), pubMessage));
|
||||
}catch(Throwable t) {
|
||||
@@ -290,7 +293,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
}
|
||||
|
||||
private void sendPubRec(String clientID, int messageID) {
|
||||
LOG.debug(String.format("sendPubRec invoked for clientID %s ad messageID %d", clientID, messageID));
|
||||
LOG.debug("sendPubRec invoked for clientID {} with messageID {}", clientID, messageID);
|
||||
PubRecMessage pubRecMessage = new PubRecMessage();
|
||||
pubRecMessage.setMessageID(messageID);
|
||||
|
||||
@@ -310,11 +313,11 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
if (m_clientIDs == null) {
|
||||
throw new RuntimeException("Internal bad error, found m_clientIDs to null while it should be initialized, somewhere it's overwritten!!");
|
||||
}
|
||||
LOG.debug("clientIDs are " + m_clientIDs);
|
||||
if (m_clientIDs.get(clientId) == null) {
|
||||
LOG.debug("clientIDs are {}", m_clientIDs);
|
||||
if (m_clientIDs.get(clientId) == null) {
|
||||
throw new RuntimeException(String.format("Can't find a ConnectionDEwcriptor for client %s in cache %s", clientId, m_clientIDs));
|
||||
}
|
||||
LOG.debug("Session for clientId " + clientId + " is " + m_clientIDs.get(clientId).getSession());
|
||||
// LOG.debug("Session for clientId " + clientId + " is " + m_clientIDs.get(clientId).getSession());
|
||||
// m_clientIDs.get(clientId).getSession().write(pubAckMessage);
|
||||
disruptorPublish(new OutputMessagingEvent(m_clientIDs.get(clientId).getSession(), pubAckMessage));
|
||||
}catch(Throwable t) {
|
||||
@@ -332,22 +335,20 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
|
||||
final String topic = evt.getTopic();
|
||||
final AbstractMessage.QOSType qos = evt.getQos();
|
||||
final byte[] message = evt.getMessage();
|
||||
boolean retain = evt.isRetain();
|
||||
|
||||
publish2Subscribers(topic, qos, message, retain, evt.getMessageID());
|
||||
publish2Subscribers(topic, qos, evt.getMessage(), evt.isRetain(), evt.getMessageID());
|
||||
|
||||
m_storageService.removeQoS2Message(publishKey);
|
||||
|
||||
if (retain) {
|
||||
m_storageService.storeRetained(topic, message, qos);
|
||||
if (evt.isRetain()) {
|
||||
m_storageService.storeRetained(topic, evt.getMessage(), qos);
|
||||
}
|
||||
|
||||
sendPubComp(clientID, messageID);
|
||||
}
|
||||
|
||||
private void sendPubComp(String clientID, int messageID) {
|
||||
LOG.debug(String.format("sendPubComp invoked for clientID %s ad messageID %d", clientID, messageID));
|
||||
LOG.debug("sendPubComp invoked for clientID {} ad messageID {}", clientID, messageID);
|
||||
PubCompMessage pubCompMessage = new PubCompMessage();
|
||||
pubCompMessage.setMessageID(messageID);
|
||||
|
||||
@@ -357,7 +358,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
|
||||
void processPubRec(String clientID, int messageID) {
|
||||
//once received a PUBREC reply with a PUBREL(messageID)
|
||||
LOG.debug(String.format("processPubRec invoked for clientID %s ad messageID %d", clientID, messageID));
|
||||
LOG.debug("processPubRec invoked for clientID {} ad messageID {}", clientID, messageID);
|
||||
PubRelMessage pubRelMessage = new PubRelMessage();
|
||||
pubRelMessage.setMessageID(messageID);
|
||||
|
||||
@@ -383,7 +384,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
//de-activate the subscriptions for this ClientID
|
||||
// String clientID = (String) evt.getSession().getAttribute(Constants.ATTR_CLIENTID);
|
||||
subscriptions.deactivate(clientID);
|
||||
LOG.info(String.format("Disconnected client <%s> with clean session %s", clientID, cleanSession));
|
||||
LOG.info("Disconnected client <{}> with clean session {}", clientID, cleanSession);
|
||||
}
|
||||
|
||||
void proccessConnectionLost(String clientID) {
|
||||
@@ -392,7 +393,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
|
||||
//de-activate the subscriptions for this ClientID
|
||||
subscriptions.deactivate(clientID);
|
||||
LOG.info(String.format("Lost connection with client <%s>", clientID));
|
||||
LOG.info("Lost connection with client <{}>", clientID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,13 +411,13 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
UnsubAckMessage ackMessage = new UnsubAckMessage();
|
||||
ackMessage.setMessageID(messageID);
|
||||
|
||||
LOG.info(String.format("replying with UnsubAck to MSG ID %s", messageID));
|
||||
LOG.info("replying with UnsubAck to MSG ID {}", messageID);
|
||||
session.write(ackMessage);
|
||||
}
|
||||
|
||||
|
||||
void processSubscribe(ServerChannel session, SubscribeMessage msg, String clientID, boolean cleanSession) {
|
||||
LOG.debug(String.format("processSubscribe invoked from client %s with msgID %d", clientID, msg.getMessageID()));
|
||||
LOG.debug("processSubscribe invoked from client {} with msgID {}", clientID, msg.getMessageID());
|
||||
|
||||
for (SubscribeMessage.Couple req : msg.subscriptions()) {
|
||||
AbstractMessage.QOSType qos = AbstractMessage.QOSType.values()[req.getQos()];
|
||||
@@ -432,14 +433,14 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
for (int i = 0; i < msg.subscriptions().size(); i++) {
|
||||
ackMessage.addType(AbstractMessage.QOSType.MOST_ONE);
|
||||
}
|
||||
LOG.debug("replying with SubAck to MSG ID " + msg.getMessageID());
|
||||
LOG.debug("replying with SubAck to MSG ID {}", msg.getMessageID());
|
||||
session.write(ackMessage);
|
||||
}
|
||||
|
||||
private void subscribeSingleTopic(Subscription newSubscription, final String topic) {
|
||||
LOG.info(String.format("<%s> subscribed to topic <%s> with QoS %s",
|
||||
LOG.info("<{}> subscribed to topic <{}> with QoS {}",
|
||||
newSubscription.getClientId(), topic,
|
||||
AbstractMessage.QOSType.formatQoS(newSubscription.getRequestedQos())));
|
||||
AbstractMessage.QOSType.formatQoS(newSubscription.getRequestedQos()));
|
||||
subscriptions.add(newSubscription);
|
||||
|
||||
//scans retained messages to be published to the new subscription
|
||||
@@ -451,13 +452,13 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
|
||||
for (HawtDBStorageService.StoredMessage storedMsg : messages) {
|
||||
//fire the as retained the message
|
||||
LOG.debug("send publish message for topic " + topic);
|
||||
LOG.debug("send publish message for topic {}", topic);
|
||||
sendPublish(newSubscription.getClientId(), storedMsg.getTopic(), storedMsg.getQos(), storedMsg.getPayload(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private void disruptorPublish(OutputMessagingEvent msgEvent) {
|
||||
LOG.debug("disruptorPublish publishing event on output " + msgEvent);
|
||||
LOG.debug("disruptorPublish publishing event on output {}", msgEvent);
|
||||
long sequence = m_ringBuffer.next();
|
||||
ValueEvent event = m_ringBuffer.get(sequence);
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ public class SimpleMessaging implements IMessaging, EventHandler<ValueEvent> {
|
||||
|
||||
|
||||
private void disruptorPublish(MessagingEvent msgEvent) {
|
||||
LOG.debug("disruptorPublish publishing event " + msgEvent);
|
||||
LOG.debug("disruptorPublish publishing event {}", msgEvent);
|
||||
long sequence = m_ringBuffer.next();
|
||||
ValueEvent event = m_ringBuffer.get(sequence);
|
||||
|
||||
@@ -97,7 +97,7 @@ public class SimpleMessaging implements IMessaging, EventHandler<ValueEvent> {
|
||||
|
||||
public void onEvent(ValueEvent t, long l, boolean bln) throws Exception {
|
||||
MessagingEvent evt = t.getEvent();
|
||||
LOG.info("onEvent processing messaging event from input ringbuffer" + evt);
|
||||
LOG.info("onEvent processing messaging event from input ringbuffer {}", evt);
|
||||
if (evt instanceof PublishEvent) {
|
||||
m_processor.processPublish((PublishEvent) evt);
|
||||
} else if (evt instanceof StopEvent) {
|
||||
@@ -112,17 +112,15 @@ public class SimpleMessaging implements IMessaging, EventHandler<ValueEvent> {
|
||||
if (message instanceof ConnectMessage) {
|
||||
m_processor.processConnect(session, (ConnectMessage) message);
|
||||
} else if (message instanceof PublishMessage) {
|
||||
PublishMessage pubMsg = (PublishMessage) message;
|
||||
PublishEvent pubEvt;
|
||||
|
||||
String clientID = (String) session.getAttribute(Constants.ATTR_CLIENTID);
|
||||
|
||||
if (message.getQos() == QOSType.MOST_ONE) {
|
||||
pubEvt = new PublishEvent(pubMsg.getTopicName(), pubMsg.getQos(), pubMsg.getPayload(), pubMsg.isRetainFlag(), clientID, session);
|
||||
|
||||
} else {
|
||||
pubEvt = new PublishEvent(pubMsg.getTopicName(), pubMsg.getQos(), pubMsg.getPayload(), pubMsg.isRetainFlag(), clientID, pubMsg.getMessageID(), session);
|
||||
}
|
||||
pubEvt = new PublishEvent((PublishMessage) message, clientID, session);
|
||||
// if (message.getQos() == QOSType.MOST_ONE) {
|
||||
// pubEvt = new PublishEvent(pubMsg.getTopicName(), pubMsg.getQos(), pubMsg.getPayload(), pubMsg.isRetainFlag(), clientID, session);
|
||||
//
|
||||
// } else {
|
||||
// pubEvt = new PublishEvent(pubMsg.getTopicName(), pubMsg.getQos(), pubMsg.getPayload(), pubMsg.isRetainFlag(), clientID, pubMsg.getMessageID(), session);
|
||||
// }
|
||||
m_processor.processPublish(pubEvt);
|
||||
} else if (message instanceof DisconnectMessage) {
|
||||
String clientID = (String) session.getAttribute(Constants.ATTR_CLIENTID);
|
||||
|
||||
+20
-6
@@ -2,25 +2,39 @@ package org.dna.mqtt.moquette.messaging.spi.impl.events;
|
||||
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
|
||||
import org.dna.mqtt.moquette.server.ServerChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class PublishEvent extends MessagingEvent implements Serializable {
|
||||
public class PublishEvent extends MessagingEvent {
|
||||
String m_topic;
|
||||
QOSType m_qos;
|
||||
byte[] m_message;
|
||||
//byte[] m_message;
|
||||
ByteBuffer m_message;
|
||||
boolean m_retain;
|
||||
String m_clientID;
|
||||
//Optional attribute, available only fo QoS 1 and 2
|
||||
int m_msgID;
|
||||
|
||||
transient ServerChannel m_session;
|
||||
|
||||
public PublishEvent(PublishMessage pubMsg, String clientID, ServerChannel session) {
|
||||
m_topic = pubMsg.getTopicName();
|
||||
m_qos = pubMsg.getQos();
|
||||
m_message = pubMsg.getPayload();
|
||||
m_retain = pubMsg.isRetainFlag();
|
||||
m_clientID = clientID;
|
||||
m_session = session;
|
||||
if (pubMsg.getQos() != QOSType.MOST_ONE) {
|
||||
m_msgID = pubMsg.getMessageID();
|
||||
}
|
||||
}
|
||||
|
||||
public PublishEvent(String topic, QOSType qos, byte[] message, boolean retain,
|
||||
public PublishEvent(String topic, QOSType qos, ByteBuffer message, boolean retain,
|
||||
String clientID, ServerChannel session) {
|
||||
m_topic = topic;
|
||||
m_qos = qos;
|
||||
@@ -30,7 +44,7 @@ public class PublishEvent extends MessagingEvent implements Serializable {
|
||||
m_session = session;
|
||||
}
|
||||
|
||||
public PublishEvent(String topic, QOSType qos, byte[] message, boolean retain,
|
||||
public PublishEvent(String topic, QOSType qos, ByteBuffer message, boolean retain,
|
||||
String clientID, int msgID, ServerChannel session) {
|
||||
this(topic, qos, message, retain, clientID, session);
|
||||
m_msgID = msgID;
|
||||
@@ -44,7 +58,7 @@ public class PublishEvent extends MessagingEvent implements Serializable {
|
||||
return m_qos;
|
||||
}
|
||||
|
||||
public byte[] getMessage() {
|
||||
public ByteBuffer getMessage() {
|
||||
return m_message;
|
||||
}
|
||||
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi.impl.storage;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.events.PublishEvent;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
|
||||
|
||||
/**
|
||||
* Publish event serialized to the DB.
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class StoredPublishEvent implements Serializable {
|
||||
String m_topic;
|
||||
QOSType m_qos;
|
||||
byte[] m_message;
|
||||
boolean m_retain;
|
||||
String m_clientID;
|
||||
//Optional attribute, available only fo QoS 1 and 2
|
||||
int m_msgID;
|
||||
|
||||
public StoredPublishEvent(PublishEvent wrapped) {
|
||||
m_topic = wrapped.getTopic();
|
||||
m_qos = wrapped.getQos();
|
||||
m_retain = wrapped.isRetain();
|
||||
m_clientID = wrapped.getClientID();
|
||||
m_msgID = wrapped.getMessageID();
|
||||
|
||||
ByteBuffer buffer = wrapped.getMessage();
|
||||
m_message = new byte[buffer.remaining()];
|
||||
buffer.get(m_message);
|
||||
buffer.rewind();
|
||||
}
|
||||
|
||||
public String getTopic() {
|
||||
return m_topic;
|
||||
}
|
||||
|
||||
public QOSType getQos() {
|
||||
return m_qos;
|
||||
}
|
||||
|
||||
public byte[] getMessage() {
|
||||
return m_message;
|
||||
}
|
||||
|
||||
public boolean isRetain() {
|
||||
return m_retain;
|
||||
}
|
||||
|
||||
public String getClientID() {
|
||||
return m_clientID;
|
||||
}
|
||||
|
||||
public int getMessageID() {
|
||||
return m_msgID;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -72,7 +72,7 @@ public class SubscriptionsStore {
|
||||
//reload any subscriptions persisted
|
||||
LOG.debug("Reloading all stored subscriptions...");
|
||||
for (Subscription subscription : m_storageService.retrieveAllSubscriptions()) {
|
||||
LOG.debug("Re-subscribing " + subscription.getClientId() + " to topic " + subscription.getTopic());
|
||||
LOG.debug("Re-subscribing {} to topic {}", subscription.getClientId(), subscription.getTopic());
|
||||
addDirect(subscription);
|
||||
}
|
||||
LOG.debug("Finished loading");
|
||||
@@ -166,7 +166,7 @@ public class SubscriptionsStore {
|
||||
}
|
||||
|
||||
public void activate(String clientID) {
|
||||
LOG.debug(String.format("Activating subscriptions for clientID <%s>", clientID));
|
||||
LOG.debug("Activating subscriptions for clientID <{}>", clientID);
|
||||
subscriptions.activate(clientID);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ public class SubscriptionsStore {
|
||||
* listeners subscriptions, and not topic publishing.
|
||||
*/
|
||||
public List<Subscription> matches(String topic) {
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
List<Token> tokens;
|
||||
try {
|
||||
tokens = splitTopic(topic);
|
||||
} catch (ParseException ex) {
|
||||
|
||||
@@ -85,7 +85,7 @@ public class NettyAcceptor implements ServerAcceptor {
|
||||
|
||||
MessageMetrics metrics = m_metricsCollector.computeMetrics();
|
||||
//LOG.info(String.format("Bytes read: %d, bytes wrote: %d", metrics.readBytes(), metrics.wroteBytes()));
|
||||
LOG.info(String.format("Msg read: %d, msg wrote: %d", metrics.messagesRead(), metrics.messagesWrote()));
|
||||
LOG.info("Msg read: {}, msg wrote: {}", metrics.messagesRead(), metrics.messagesWrote());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class NettyMQTTHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object message) {
|
||||
AbstractMessage msg = (AbstractMessage) message;
|
||||
LOG.info(String.format("Received a message of type %s", Utils.msgType2String(msg.getMessageType())));
|
||||
LOG.info("Received a message of type {}", Utils.msgType2String(msg.getMessageType()));
|
||||
try {
|
||||
switch (msg.getMessageType()) {
|
||||
case CONNECT:
|
||||
|
||||
+5
-2
@@ -1,5 +1,6 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -168,7 +169,8 @@ public class ProtocolProcessorTest {
|
||||
|
||||
|
||||
//Exercise
|
||||
PublishEvent pubEvt = new PublishEvent(FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, "Hello".getBytes(), false, "FakeCLI", null);
|
||||
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
|
||||
@@ -254,7 +256,8 @@ public class ProtocolProcessorTest {
|
||||
connectMessage.setProcotolVersion((byte)3);
|
||||
connectMessage.setCleanSession(subscription.isCleanSession());
|
||||
m_processor.processConnect(m_session, connectMessage);
|
||||
PublishEvent pubEvt = new PublishEvent(FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, "Hello".getBytes(), true, "FakeCLI", null);
|
||||
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
|
||||
PublishEvent pubEvt = new PublishEvent(FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, buffer, true, "FakeCLI", null);
|
||||
m_processor.processPublish(pubEvt);
|
||||
|
||||
//Exercise
|
||||
|
||||
@@ -306,6 +306,7 @@ public class ServerIntegrationPahoTest {
|
||||
anotherClient.disconnect();
|
||||
}
|
||||
|
||||
//BUG
|
||||
@Test
|
||||
public void testPublishWithQoS2() throws Exception {
|
||||
LOG.info("*** testPublishWithQoS2 ***");
|
||||
@@ -324,6 +325,7 @@ public class ServerIntegrationPahoTest {
|
||||
assertEquals(2, m_callback.getMessage().getQos());
|
||||
}
|
||||
|
||||
//BUG
|
||||
@Test
|
||||
public void testPublishReceiveWithQoS2() throws Exception {
|
||||
LOG.info("*** testPublishReceiveWithQoS2 ***");
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>org.dna.mqtt</groupId>
|
||||
<artifactId>moquette-parser-commons</artifactId>
|
||||
<version>0.2</version>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dna.mqtt.moquette.parser.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import java.util.List;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
@@ -18,14 +19,14 @@ class PublishDecoder extends DemuxDecoder {
|
||||
|
||||
@Override
|
||||
void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
LOG.info("decode invoked with buffer " + in);
|
||||
LOG.info("decode invoked with buffer {}", in);
|
||||
in.resetReaderIndex();
|
||||
int startPos = in.readerIndex();
|
||||
|
||||
//Common decoding part
|
||||
PublishMessage message = new PublishMessage();
|
||||
if (!decodeCommonHeader(message, in)) {
|
||||
LOG.info("decode ask for more data after " + in);
|
||||
LOG.info("decode ask for more data after {}", in);
|
||||
in.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
@@ -51,9 +52,10 @@ class PublishDecoder extends DemuxDecoder {
|
||||
in.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
byte[] b = new byte[payloadSize];
|
||||
in.readBytes(b);
|
||||
message.setPayload(b);
|
||||
// byte[] b = new byte[payloadSize];
|
||||
ByteBuf bb = Unpooled.buffer(payloadSize);
|
||||
in.readBytes(bb);
|
||||
message.setPayload(bb.nioBuffer());
|
||||
|
||||
out.add(message);
|
||||
}
|
||||
|
||||
+19
-3
@@ -2,6 +2,8 @@ package org.dna.mqtt.moquette.parser.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
@@ -65,7 +67,8 @@ public class PublishDecoderTest {
|
||||
public void testHeaderWithMessageID_Payload() throws Exception {
|
||||
m_buff = Unpooled.buffer(14);
|
||||
int messageID = 123;
|
||||
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
// byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
ByteBuffer payload = ByteBuffer.allocate(3).put(new byte[]{0x0A, 0x0B, 0x0C});
|
||||
initHeaderWithMessageID_Payload(m_buff, messageID, payload);
|
||||
|
||||
//Exercise
|
||||
@@ -76,7 +79,8 @@ public class PublishDecoderTest {
|
||||
assertNotNull(message);
|
||||
assertEquals("Fake Topic", message.getTopicName());
|
||||
assertEquals(messageID, (int) message.getMessageID());
|
||||
TestUtils.verifyEquals(payload, message.getPayload());
|
||||
// TestUtils.verifyEquals(payload, message.getPayload());
|
||||
assertEquals(payload, message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -141,7 +145,9 @@ public class PublishDecoderTest {
|
||||
PublishMessage message = (PublishMessage)m_results.get(0);
|
||||
assertNotNull(message);
|
||||
assertEquals("/topic", message.getTopicName());
|
||||
assertEquals("Test my payload", new String(message.getPayload()));
|
||||
// assertEquals("Test my payload", new String(message.getPayload()));
|
||||
Buffer expectedPayload = ByteBuffer.allocate(15).put("Test my payload".getBytes()).flip();
|
||||
assertEquals(expectedPayload, message.getPayload());
|
||||
}
|
||||
|
||||
private void initHeader(ByteBuf buff) throws IllegalAccessException {
|
||||
@@ -170,6 +176,16 @@ public class PublishDecoderTest {
|
||||
buff.writeBytes(tmp);
|
||||
}
|
||||
|
||||
private void initHeaderWithMessageID_Payload(ByteBuf buff, int messageID, ByteBuffer payload) throws IllegalAccessException {
|
||||
ByteBuf tmp = Unpooled.buffer(4).writeBytes(Utils.encodeString("Fake Topic"));
|
||||
tmp.writeShort(messageID);
|
||||
tmp.writeBytes(payload);
|
||||
buff.clear().writeByte(AbstractMessage.PUBLISH << 4 | 0x02) //set Qos to 1
|
||||
.writeBytes(Utils.encodeRemainingLength(tmp.readableBytes()));
|
||||
//topic name
|
||||
buff.writeBytes(tmp);
|
||||
}
|
||||
|
||||
private ByteBuf generatePublishQoS0(ByteBuf payload) throws IllegalAccessException {
|
||||
int size = payload.capacity();
|
||||
ByteBuf messageBody = Unpooled.buffer(size);
|
||||
|
||||
+18
-10
@@ -3,6 +3,7 @@ package org.dna.mqtt.moquette.parser.netty;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
@@ -35,7 +36,8 @@ public class PublishEncoderTest {
|
||||
msg.setTopicName(topic);
|
||||
|
||||
//variable part
|
||||
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
byte[] bpayload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
ByteBuffer payload = (ByteBuffer) ByteBuffer.allocate(3).put(bpayload).flip();
|
||||
msg.setPayload(payload);
|
||||
|
||||
//Exercise
|
||||
@@ -48,7 +50,8 @@ public class PublishEncoderTest {
|
||||
|
||||
//Variable part
|
||||
verifyString(topic, m_out);
|
||||
verifyBuff(payload.length, payload, m_out);
|
||||
payload.rewind();
|
||||
verifyBuff(bpayload.length, payload, m_out);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +64,8 @@ public class PublishEncoderTest {
|
||||
msg.setTopicName(topic);
|
||||
|
||||
//variable part
|
||||
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
byte[] bpayload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
ByteBuffer payload = (ByteBuffer) ByteBuffer.allocate(3).put(bpayload).flip();
|
||||
msg.setPayload(payload);
|
||||
|
||||
//Exercise
|
||||
@@ -76,7 +80,8 @@ public class PublishEncoderTest {
|
||||
verifyString(topic, m_out);
|
||||
assertEquals(0, m_out.readByte()); //MessageID MSB
|
||||
assertEquals(1, m_out.readByte()); //MessageID LSB
|
||||
verifyBuff(payload.length, payload, m_out);
|
||||
payload.rewind();
|
||||
verifyBuff(bpayload.length, payload, m_out);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -120,7 +125,8 @@ public class PublishEncoderTest {
|
||||
msg.setTopicName(null);
|
||||
|
||||
//variable part
|
||||
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
byte[] bpayload = new byte[]{0x0A, 0x0B, 0x0C};
|
||||
ByteBuffer payload = (ByteBuffer) ByteBuffer.allocate(3).put(bpayload).flip();
|
||||
msg.setPayload(payload);
|
||||
ByteBuf out = Unpooled.buffer();
|
||||
|
||||
@@ -136,7 +142,8 @@ public class PublishEncoderTest {
|
||||
msg.setTopicName(topic);
|
||||
|
||||
//variable part
|
||||
byte[] payload = "Test my payload".getBytes();
|
||||
byte[] bpayload = "Test my payload".getBytes();
|
||||
ByteBuffer payload = (ByteBuffer) ByteBuffer.allocate(bpayload.length).put(bpayload).flip();
|
||||
msg.setPayload(payload);
|
||||
|
||||
//Exercise
|
||||
@@ -145,16 +152,17 @@ public class PublishEncoderTest {
|
||||
//Verify
|
||||
//2 byte header + (2+6) topic name + [2 message ID if QoQ <> 0]+ payload
|
||||
int size = m_out.readableBytes();
|
||||
assertEquals(10+payload.length, size);
|
||||
assertEquals(10 + bpayload.length, size);
|
||||
assertEquals(0x30, m_out.readByte()); //1 byte
|
||||
assertEquals(23, m_out.readByte()); //1 byte the length
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBigMessage() throws Exception {
|
||||
byte[] payload = new byte[256];
|
||||
byte[] bpayload = new byte[256];
|
||||
|
||||
TestUtils.generateRandomPayload(256).readBytes(payload);
|
||||
TestUtils.generateRandomPayload(256).readBytes(bpayload);
|
||||
ByteBuffer payload = (ByteBuffer) ByteBuffer.allocate(bpayload.length).put(bpayload).flip();
|
||||
|
||||
String topic = "/topic";
|
||||
PublishMessage msg = new PublishMessage();
|
||||
@@ -168,7 +176,7 @@ public class PublishEncoderTest {
|
||||
m_encoder.encode(m_mockedContext, msg, m_out);
|
||||
|
||||
int size = m_out.readableBytes();
|
||||
assertEquals(11+payload.length, size);
|
||||
assertEquals(11 + bpayload.length, size);
|
||||
assertEquals(0x30, m_out.readByte()); //1 byte
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.*;
|
||||
@@ -31,6 +32,11 @@ public class TestUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static void verifyBuff(int numBytes, ByteBuffer bytes, ByteBuf buff) {
|
||||
assertTrue(numBytes <= buff.readableBytes());
|
||||
assertEquals(bytes, buff.nioBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the presence of the given string starting from the current position
|
||||
* inside the buffer.
|
||||
|
||||
+5
-3
@@ -1,5 +1,7 @@
|
||||
package org.dna.mqtt.moquette.proto.messages;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
@@ -8,7 +10,7 @@ public class PublishMessage extends MessageIDMessage {
|
||||
|
||||
private String m_topicName;
|
||||
// private Integer m_messageID; //could be null if Qos is == 0
|
||||
private byte[] m_payload;
|
||||
private ByteBuffer m_payload;
|
||||
|
||||
/*public Integer getMessageID() {
|
||||
return m_messageID;
|
||||
@@ -30,11 +32,11 @@ public class PublishMessage extends MessageIDMessage {
|
||||
this.m_topicName = topicName;
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
public ByteBuffer getPayload() {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
public void setPayload(byte[] payload) {
|
||||
public void setPayload(ByteBuffer payload) {
|
||||
this.m_payload = payload;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
@Grab(group='org.fusesource.mqtt-client', module='mqtt-client', version='1.5')
|
||||
|
||||
import java.net.URISyntaxException
|
||||
|
||||
import org.fusesource.mqtt.client.BlockingConnection
|
||||
import org.fusesource.mqtt.client.MQTT
|
||||
import org.fusesource.mqtt.client.QoS
|
||||
|
||||
String host = args[0]
|
||||
|
||||
MQTT mqtt = new MQTT()
|
||||
//mqtt.setHost("test.mosquitto.org", 1883);
|
||||
mqtt.setHost(host, 1883)
|
||||
BlockingConnection connection = mqtt.blockingConnection()
|
||||
connection.connect()
|
||||
|
||||
print "publishing.."
|
||||
long startTime = System.currentTimeMillis()
|
||||
(1..100000).each {
|
||||
connection.publish("/topic", 'Hello world!!'.bytes, QoS.AT_MOST_ONCE, false)
|
||||
}
|
||||
connection.publish('/exit', 'Exit'.bytes, QoS.AT_MOST_ONCE, false)
|
||||
long stopTime = System.currentTimeMillis()
|
||||
long spentTime = stopTime -startTime
|
||||
println "published in ${spentTime} ms"
|
||||
connection.disconnect()
|
||||
println "disconnected"
|
||||
@@ -0,0 +1,51 @@
|
||||
@Grab(group='org.fusesource.mqtt-client', module='mqtt-client', version='1.5')
|
||||
|
||||
import java.net.URISyntaxException
|
||||
|
||||
import org.fusesource.mqtt.client.BlockingConnection
|
||||
import org.fusesource.mqtt.client.MQTT
|
||||
import org.fusesource.mqtt.client.Message
|
||||
import org.fusesource.mqtt.client.QoS
|
||||
import org.fusesource.mqtt.client.Topic
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
String host = args[0]
|
||||
MQTT mqtt = new MQTT()
|
||||
//mqtt.setHost("test.mosquitto.org", 1883);
|
||||
mqtt.setHost(host, 1883)
|
||||
mqtt.setCleanSession(true)
|
||||
mqtt.setHost(host, 1883)
|
||||
|
||||
mqtt.setClientId("SubscriberClient")
|
||||
BlockingConnection connection = mqtt.blockingConnection()
|
||||
connection.connect()
|
||||
println "Connected to ${host}"
|
||||
|
||||
Topic[] topics = [new Topic("/topic", QoS.AT_MOST_ONCE), new Topic("/exit", QoS.AT_MOST_ONCE)]
|
||||
byte[] qoses = connection.subscribe(topics)
|
||||
println "subscribed to /topic qos: ${qoses[0]}"
|
||||
println "subscribed to /exit qos: ${qoses[1]}"
|
||||
|
||||
int numReceived = 0
|
||||
long startTime = System.currentTimeMillis()
|
||||
boolean exit = false
|
||||
|
||||
while(!exit) {
|
||||
Message message = connection.receive()
|
||||
if (message.topic == "/exit") {
|
||||
exit = true
|
||||
} else {
|
||||
numReceived++
|
||||
// if ((numReceived % 10000) == 0) {
|
||||
// print '.'
|
||||
// }
|
||||
}
|
||||
message.ack()
|
||||
}
|
||||
connection.disconnect()
|
||||
long stopTime = System.currentTimeMillis()
|
||||
long spentTime = stopTime - startTime
|
||||
println "/exit received"
|
||||
println "subscriber disconnected, received ${numReceived} messages in ${spentTime} ms"
|
||||
|
||||
Reference in New Issue
Block a user