Removed the Mina parser

This commit is contained in:
andrea
2013-11-24 11:52:10 +01:00
parent 1fa810362f
commit 9cec0af484
55 changed files with 0 additions and 3019 deletions
Binary file not shown.
-64
View File
@@ -1,64 +0,0 @@
Per Mina
- per gestire l'inattività su una sessione usare
acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
e
nell'implementazione del IoHandlerAdapter ridefinire il metodo
public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
Glossario:
QOS: presente solo per i messaggi PUBLISH, definisce 3 livelli
QoS0: at most once, cioe' viene notificato al piu' uno (il che' significa che
potrebbe anche non essere notificato) equivalente a messaggi non persistenti di JMS
QoS1: at least once, delivery equivalente ai messaggi persistenti di JMS
Q0S2: exactly once, delivery assicurato equivalente ai messagi persistenti di JMS + DUPS_OK_ACKNOWLEDGE
RETAIN: Usato solo per i messaggi di PUBLISH, se true dice di persistere il messaggio dopo esser stato notificato a tutti
i sottoscritori del topic. Se in un secondo momento un cliente si sottoscrive ad un
messaggio pubblicato con RETAIN = 1 allora anche il messaggio di notifica dovrà avere RETAIN = 1,
altrimenti non accade nulla. I messaggi notificati al momento del PUBLISH non hanno flag RETAIN = 1
serve solo per dire ai posteri che il messaggio che stanno ricevendo non è "live".
Un server PUO' eliminare un messaggio marcato con RETAIN se ne arriva un'altro sullo stesso topic con lunghezza = 0 e RETAIN = 1.
CLEAN SESSION: è un flag disponibile per il solo messaggio di CONNECT.
Se = 0 allora il server DEVE memorizzare(mantenere) le sottoscrizioni del client
dopo che si sia disconnesso. Questo prevede di continuare a salvare i messaggi
QOS1 e QOS2 per i topic sottoscritti cosicche' possano essere consegnati quando
il client si riconnetterà. Il server DEVE inoltre mantenere lo stato dei messaggi
che stavano per essere consegnati prima che la connessione fosse persa.
Questa informazione DEVE esser mantenuta finchè il client si ricconnetta.
Se flag = 1 allora il server DEVE scartare qualsiasi informazione precedentemente
memorizzata sul client e trattare la connessione come "pulita".
Il server DEVE anche scartare qualunque stato qualora il client di disconnetta.
Solitamente, un client opererà o in un modo o nell'altro. La scelta dipenderà dall'applicazione.
Un sessione cliente pulita non riceverà informazioni vecchie e DOVRA' ri-sottoscriversi
ogni volta che si connette. Una sessione cliente NON pulita non perderà nessun messaggio di
tipo QoS1 o QoS2 che sia stato pubblicato mentro esso era disconnesso. I messaggi
di tipo QoS0 NON vengono mai salvati. Un server deve fornire un meccanismo di
amministrazione per la pulizia delle informazione salvate su di un client e
che possa essere usata qualora si sappia che il client non si riconnetterà.
**** CONNECT ****
C S
CONNECT ->
<- CONNACK
**** PUBLISH ****
A client PUBLISH a message on a server QoS 1:
C S
PUBLISH ->
<- PUBACK
A server send a PUBLISH notification to a client QoS 1:
S C
PUBLISH ->
<- PUBACK
-85
View File
@@ -1,85 +0,0 @@
<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>
<parent>
<relativePath>../</relativePath>
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>moquette-parent</artifactId>
<groupId>org.dna.mqtt</groupId>
<version>0.4-SNAPSHOT</version>
</parent>
<artifactId>moquette-mina-parser</artifactId>
<packaging>jar</packaging>
<!--<version>${moquette-version}</version>-->
<name>Moquette - MINA Parser</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>${mina-version}</version>
</dependency>
<dependency>
<groupId>org.dna.mqtt</groupId>
<artifactId>moquette-parser-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<!-- needs extra dependencies: objenesis & hamcrest -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>org/dna/mqtt/moquette/proto/TestUtils.java</exclude>
<exclude>org/dna/mqtt/moquette/proto/TestUtils$*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
</repositories>
</project>
@@ -1,20 +0,0 @@
package org.dna.mqtt.commons;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* @author andrea
*/
public class MessageIDGenerator {
private AtomicInteger m_current;
public MessageIDGenerator() {
//NB we start at -1 because the first incAndGet has to return 0
m_current = new AtomicInteger(-1);
}
public int next() {
return m_current.incrementAndGet();
}
}
@@ -1,16 +0,0 @@
package org.dna.mqtt.moquette;
/**
*
* @author andrea
*/
public class ConnectionException extends MQTTException {
public ConnectionException(String msg) {
super(msg);
}
public ConnectionException(Throwable e) {
super(e);
}
}
@@ -1,16 +0,0 @@
package org.dna.mqtt.moquette;
/**
*
* @author andrea
*/
public class PublishException extends ConnectionException {
public PublishException(String msg) {
super(msg);
}
public PublishException(Throwable e) {
super(e);
}
}
@@ -1,16 +0,0 @@
package org.dna.mqtt.moquette;
/**
*
* @author andrea
*/
public class SubscribeException extends ConnectionException {
public SubscribeException(String msg) {
super(msg);
}
public SubscribeException(Throwable e) {
super(e);
}
}
@@ -1,35 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.ConnAckMessage;
/**
*
* @author andrea
*/
public class ConnAckDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.CONNACK, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
ConnAckMessage message = new ConnAckMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
//skip reserved byte
in.skip(1);
//read return code
message.setReturnCode(in.get());
out.write(message);
return OK;
}
}
@@ -1,24 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.ConnAckMessage;
/**
*
* @author andrea
*/
public class ConnAckEncoder implements MessageEncoder<ConnAckMessage> {
public void encode(IoSession session, ConnAckMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(4);
buff.put((byte) (AbstractMessage.CONNACK << 4));
buff.put(Utils.encodeRemainingLength(2));
buff.put((byte) 0);
buff.put(message.getReturnCode()).flip();
out.write(buff);
}
}
@@ -1,138 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.ConnectMessage;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
/**
* Decoder for the CONNECT message
*
* @author andrea
*/
public class ConnectDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.CONNECT, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
ConnectMessage message = new ConnectMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
int remainingLength = message.getRemainingLength();
int start = in.position();
//Connect specific decoding part
//ProtocolName 8 bytes
if (in.remaining() < 12) {
return NEED_DATA;
}
byte[] encProtoName = new byte[6];
in.skip(2); //size, is 0x06
in.get(encProtoName);
String protoName = new String(encProtoName, "UTF-8");
if (!"MQIsdp".equals(protoName)) {
return NOT_OK;
}
message.setProtocolName(protoName);
//ProtocolVersion 1 byte (value 0x03)
message.setProcotolVersion(in.get());
//Connection flag
byte connFlags = in.get();
boolean cleanSession = ((connFlags & 0x02) >> 1) == 1 ? true : false;
boolean willFlag = ((connFlags & 0x04) >> 2) == 1 ? true : false;
byte willQos = (byte) ((connFlags & 0x18) >> 3);
if (willQos > 2) {
return NOT_OK; //admitted values for willqos are 0, 1, 2
}
boolean willRetain = ((connFlags & 0x20) >> 5) == 1 ? true : false;
boolean passwordFlag = ((connFlags & 0x40) >> 6) == 1 ? true : false;
boolean userFlag = ((connFlags & 0x80) >> 7) == 1 ? true : false;
//a password is true iff user is true.
if (!userFlag && passwordFlag) {
return NOT_OK;
}
message.setCleanSession(cleanSession);
message.setWillFlag(willFlag);
message.setWillQos(willQos);
message.setWillRetain(willRetain);
message.setPasswordFlag(passwordFlag);
message.setUserFlag(userFlag);
//Keep Alive timer 2 bytes
int keepAlive = Utils.readWord(in);
message.setKeepAlive(keepAlive);
if (remainingLength == 12) {
out.write(message);
return OK;
}
//Decode the ClientID
String clientID = Utils.decodeString(in);
if (clientID == null) {
return NEED_DATA;
}
message.setClientID(clientID);
//Decode willTopic
if (willFlag) {
String willTopic = Utils.decodeString(in);
if (willTopic == null) {
return NEED_DATA;
}
message.setWillTopic(willTopic);
}
//Decode willMessage
if (willFlag) {
String willMessage = Utils.decodeString(in);
if (willMessage == null) {
return NEED_DATA;
}
message.setWillMessage(willMessage);
}
//Compatibility check wieth v3.0, remaining length has precedence over
//the user and password flags
int readed = in.position() - start;
if (readed == remainingLength) {
out.write(message);
return OK;
}
//Decode username
if (userFlag) {
String userName = Utils.decodeString(in);
if (userName == null) {
return NEED_DATA;
}
message.setUsername(userName);
}
readed = in.position() - start;
if (readed == remainingLength) {
out.write(message);
return OK;
}
//Decode password
if (passwordFlag) {
String password = Utils.decodeString(in);
if (password == null) {
return NEED_DATA;
}
message.setPassword(password);
}
out.write(message);
return OK;
}
}
@@ -1,72 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.ConnectMessage;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
/**
*
* @author andrea
*/
public class ConnectEncoder implements MessageEncoder<ConnectMessage> {
public void encode(IoSession session, ConnectMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer staticHeaderBuff = IoBuffer.allocate(12);
staticHeaderBuff.put(Utils.encodeString("MQIsdp"));
//version
staticHeaderBuff.put((byte)0x03);
//connection flags and Strings
byte connectionFlags = 0;
if (message.isCleanSession()) {
connectionFlags |= 0x02;
}
if (message.isWillFlag()) {
connectionFlags |= 0x04;
}
connectionFlags |= ((message.getWillQos() & 0x03) << 3);
if (message.isWillRetain()) {
connectionFlags |= 0x020;
}
if (message.isPasswordFlag()) {
connectionFlags |= 0x040;
}
if (message.isUserFlag()) {
connectionFlags |= 0x080;
}
staticHeaderBuff.put(connectionFlags);
//Keep alive timer
Utils.writeWord(staticHeaderBuff, message.getKeepAlive());
staticHeaderBuff.flip();
//Variable part
IoBuffer variableHeaderBuff = IoBuffer.allocate(12).setAutoExpand(true);
if (message.getClientID() != null) {
variableHeaderBuff.put(Utils.encodeString(message.getClientID()));
if (message.isWillFlag()) {
variableHeaderBuff.put(Utils.encodeString(message.getWillTopic()));
variableHeaderBuff.put(Utils.encodeString(message.getWillMessage()));
}
if (message.isUserFlag() && message.getUsername() != null) {
variableHeaderBuff.put(Utils.encodeString(message.getUsername()));
if (message.isPasswordFlag() && message.getPassword() != null) {
variableHeaderBuff.put(Utils.encodeString(message.getPassword()));
}
}
}
variableHeaderBuff.flip();
int variableHeaderSize = variableHeaderBuff.remaining();
IoBuffer buff = IoBuffer.allocate(14 + variableHeaderSize);
buff.put((byte) (AbstractMessage.CONNECT << 4));
buff.put(Utils.encodeRemainingLength(12 + variableHeaderSize));
buff.put(staticHeaderBuff).put(variableHeaderBuff).flip();
out.write(buff);
}
}
@@ -1,29 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.DisconnectMessage;
/**
*
* @author andrea
*/
public class DisconnectDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.DISCONNECT, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
DisconnectMessage message = new DisconnectMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
out.write(message);
return OK;
}
}
@@ -1,22 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.DisconnectMessage;
/**
*
* @author andrea
*/
public class DisconnectEncoder implements MessageEncoder<DisconnectMessage> {
public void encode(IoSession session, DisconnectMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(2);
buff.put((byte) (AbstractMessage.DISCONNECT << 4)).put((byte)0).flip();
out.write(buff);
}
}
@@ -1,158 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.AbstractIoBuffer;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;
import org.apache.mina.filter.logging.LogLevel;
import org.apache.mina.filter.logging.LoggingFilter;
import static org.dna.mqtt.moquette.proto.messages.AbstractMessage.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Apache MINA logging filter that pretty prints the header of messages
*
* @author andrea
*/
public class MQTTLoggingFilter extends LoggingFilter {
private final Logger log;
protected static String computeLoggerName(String name) {
return name == null ? MQTTLoggingFilter.class.getName() : name;
}
/**
* Default Constructor.
*/
public MQTTLoggingFilter() {
this(LoggingFilter.class.getName());
}
/**
* Create a new NoopFilter using a class name
*
* @param clazz the class which name will be used to create the logger
*/
public MQTTLoggingFilter(Class<?> clazz) {
this(clazz.getName());
}
/**
* Create a new NoopFilter using a name
*
* @param name the name used to create the logger. If null, will default to
* "NoopFilter"
*/
public MQTTLoggingFilter(String name) {
super(computeLoggerName(name));
log = LoggerFactory.getLogger(getName());
}
protected String decodeCommonHeader(IoBuffer in) {
StringBuilder sb = new StringBuilder();
byte h1 = in.get();
byte messageType = (byte) ((h1 & 0x00F0) >> 4);
boolean dupFlag = ((byte) ((h1 & 0x0008) >> 3) == 1);
byte qosLevel = (byte) ((h1 & 0x0006) >> 1);
boolean retainFlag = ((byte) (h1 & 0x0001) == 1);
int remainingLength = Utils.decodeRemainingLenght(in);
sb.append("type: ").append(decodeMessageType(messageType)).append(", ");
sb.append("dup: ").append(Boolean.toString(dupFlag)).append(", ");
sb.append("QoS: ").append(qosLevel).append(", ");
sb.append("retain: ").append(Boolean.toString(retainFlag));
if (remainingLength != -1) {
sb.append(", remainingLen: ").append(remainingLength);
}
in.rewind();
return sb.toString();
}
protected String decodeMessageType(byte type) {
switch (type) {
case CONNECT:
return "CONNECT";
case CONNACK:
return "CONNACK";
case PUBLISH:
return "PUBLISH";
case PUBACK:
return "PUBACK";
case PUBREC:
return "PUBREC";
case PUBREL:
return "PUBREL";
case PUBCOMP:
return "PUBCOMP";
case SUBSCRIBE:
return "SUBSCRIBE";
case SUBACK:
return "SUBACK";
case UNSUBSCRIBE:
return "UNSUBSCRIBE";
case UNSUBACK:
return "UNSUBACK";
case PINGREQ:
return "PINGREQ";
case PINGRESP:
return "PINGRESP";
case DISCONNECT:
return "DISCONNECT";
default:
return "undefined";
}
}
@Override
public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
if (message instanceof AbstractIoBuffer) {
IoBuffer buff = (AbstractIoBuffer) message;
log(getMessageReceivedLogLevel(), "-> RECEIVED: {}", decodeCommonHeader(buff) + "\n\t" + buff.getHexDump());
} else {
log(getMessageReceivedLogLevel(), "-> RECEIVED: {}", message);
}
nextFilter.messageReceived(session, message);
}
@Override
public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
Object message = writeRequest.getMessage();
if (message instanceof AbstractIoBuffer) {
IoBuffer buff = (AbstractIoBuffer) message;
log(getMessageReceivedLogLevel(), "<- SENT: {}", buff.getHexDump());
} else {
log(getMessageReceivedLogLevel(), "<- SENT: {}", message);
}
nextFilter.messageSent(session, writeRequest);
}
/**
* Copied by parent
*/
private void log(LogLevel eventLevel, String message, Object param) {
switch (eventLevel) {
case TRACE:
log.trace(message, param);
return;
case DEBUG:
log.debug(message, param);
return;
case INFO:
log.info(message, param);
return;
case WARN:
log.warn(message, param);
return;
case ERROR:
log.error(message, param);
return;
default:
return;
}
}
}
@@ -1,28 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.MessageIDMessage;
/**
*
* @author andrea
*/
public abstract class MessageIDDecoder extends MqttDecoder {
protected abstract MessageIDMessage createMessage();
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
MessageIDMessage message = createMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
//read messageIDs
message.setMessageID(Utils.readWord(in));
out.write(message);
return OK;
}
}
@@ -1,37 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoderAdapter;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
/**
* Contains common code for all mqtt decoders.
*
* @author andrea
*/
public abstract class MqttDecoder extends MessageDecoderAdapter {
protected MessageDecoderResult decodeCommonHeader(AbstractMessage message, IoBuffer in) {
//Common decoding part
if (in.remaining() < 2) {
return NEED_DATA;
}
byte h1 = in.get();
byte messageType = (byte) ((h1 & 0x00F0) >> 4);
boolean dupFlag = ((byte) ((h1 & 0x0008) >> 3) == 1);
byte qosLevel = (byte) ((h1 & 0x0006) >> 1);
boolean retainFlag = ((byte) (h1 & 0x0001) == 1);
int remainingLength = Utils.decodeRemainingLenght(in);
if (remainingLength == -1) {
return NEED_DATA;
}
message.setMessageType(messageType);
message.setDupFlag(dupFlag);
message.setQos(AbstractMessage.QOSType.values()[qosLevel]);
message.setRetainFlag(retainFlag);
message.setRemainingLength(remainingLength);
return OK;
}
}
@@ -1,29 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PingReqMessage;
/**
*
* @author andrea
*/
public class PingReqDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PINGREQ, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
PingReqMessage message = new PingReqMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
out.write(message);
return OK;
}
}
@@ -1,21 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PingReqMessage;
/**
*
* @author andrea
*/
public class PingReqEncoder implements MessageEncoder<PingReqMessage> {
public void encode(IoSession session, PingReqMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(2);
buff.put((byte) (AbstractMessage.PINGREQ << 4)).put((byte)0).flip();
out.write(buff);
}
}
@@ -1,33 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PingRespMessage;
/**
*
* @author andrea
*/
public class PingRespDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PINGRESP, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
PingRespMessage message = new PingRespMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
out.write(message);
return OK;
}
}
@@ -1,21 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PingRespMessage;
/**
*
* @author andrea
*/
public class PingRespEncoder implements MessageEncoder<PingRespMessage> {
public void encode(IoSession session, PingRespMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(2);
buff.put((byte) (AbstractMessage.PINGRESP << 4)).put((byte)0).flip();
out.write(buff);
}
}
@@ -1,25 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.MessageIDMessage;
import org.dna.mqtt.moquette.proto.messages.PubAckMessage;
/**
*
* @author andrea
*/
public class PubAckDecoder extends MessageIDDecoder {
@Override
protected MessageIDMessage createMessage() {
return new PubAckMessage();
}
@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PUBACK, in);
}
}
@@ -1,23 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PubAckMessage;
/**
*
* @author andrea
*/
public class PubAckEncoder implements MessageEncoder<PubAckMessage> {
public void encode(IoSession session, PubAckMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(4);
buff.put((byte) (AbstractMessage.PUBACK << 4));
buff.put(Utils.encodeRemainingLength(2));
Utils.writeWord(buff, message.getMessageID());
buff.flip();
out.write(buff);
}
}
@@ -1,25 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.PubCompMessage;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.MessageIDMessage;
/**
*
* @author andrea
*/
public class PubCompDecoder extends MessageIDDecoder {
@Override
protected MessageIDMessage createMessage() {
return new PubCompMessage();
}
@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PUBCOMP, in);
}
}
@@ -1,23 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PubCompMessage;
/**
*
* @author andrea
*/
public class PubCompEncoder implements MessageEncoder<PubCompMessage> {
public void encode(IoSession session, PubCompMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(4);
buff.put((byte) (AbstractMessage.PUBCOMP << 4));
buff.put(Utils.encodeRemainingLength(2));
Utils.writeWord(buff, message.getMessageID());
buff.flip();
out.write(buff);
}
}
@@ -1,25 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.MessageIDMessage;
import org.dna.mqtt.moquette.proto.messages.PubRecMessage;
/**
*
* @author andrea
*/
public class PubRecDecoder extends MessageIDDecoder {
@Override
protected MessageIDMessage createMessage() {
return new PubRecMessage();
}
@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PUBREC, in);
}
}
@@ -1,23 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PubRecMessage;
/**
*
* @author andrea
*/
public class PubRecEncoder implements MessageEncoder<PubRecMessage> {
public void encode(IoSession session, PubRecMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(4);
buff.put((byte) (AbstractMessage.PUBREC << 4));
buff.put(Utils.encodeRemainingLength(2));
Utils.writeWord(buff, message.getMessageID());
buff.flip();
out.write(buff);
}
}
@@ -1,26 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.MessageIDMessage;
import org.dna.mqtt.moquette.proto.messages.PubRelMessage;
/**
*
* @author andrea
*/
public class PubRelDecoder extends MessageIDDecoder {
@Override
protected MessageIDMessage createMessage() {
return new PubRelMessage();
}
@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PUBREL, in);
}
}
@@ -1,23 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PubRelMessage;
/**
*
* @author andrea
*/
public class PubRelEncoder implements MessageEncoder<PubRelMessage> {
public void encode(IoSession session, PubRelMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(4);
buff.put((byte) (AbstractMessage.PUBREL << 4));
buff.put(Utils.encodeRemainingLength(2));
Utils.writeWord(buff, message.getMessageID());
buff.flip();
out.write(buff);
}
}
@@ -1,63 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author andrea
*/
public class PublishDecoder extends MqttDecoder {
private static Logger LOG = LoggerFactory.getLogger(PublishDecoder.class);
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.PUBLISH, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
LOG.debug("decode invoked with buffer " + in);
int startPos = in.position();
//Common decoding part
PublishMessage message = new PublishMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
LOG.info("decode ask for more data after " + in);
return NEED_DATA;
}
int remainingLength = message.getRemainingLength();
//Topic name
String topic = Utils.decodeString(in);
if (topic == null) {
return NEED_DATA;
}
message.setTopicName(topic);
if (message.getQos() == QOSType.LEAST_ONE ||
message.getQos() == QOSType.EXACTLY_ONCE) {
message.setMessageID(Utils.readWord(in));
}
int stopPos = in.position();
//read the payload
int payloadSize = remainingLength - (stopPos - startPos - 2) + (Utils.numBytesToEncode(remainingLength) - 1);
if (in.remaining() < payloadSize) {
return NEED_DATA;
}
byte[] b = new byte[payloadSize];
in.get(b);
message.setPayload(b);
out.write(message);
return OK;
}
}
@@ -1,48 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
/**
*
* @author andrea
*/
public class PublishEncoder implements MessageEncoder<PublishMessage> {
public void encode(IoSession session, PublishMessage message, ProtocolEncoderOutput out) throws Exception {
if (message.getQos() == QOSType.RESERVED) {
throw new IllegalArgumentException("Found a message with RESERVED Qos");
}
if (message.getTopicName() == null || message.getTopicName().isEmpty()) {
throw new IllegalArgumentException("Found a message with empty or null topic name");
}
IoBuffer variableHeaderBuff = IoBuffer.allocate(2).setAutoExpand(true);
variableHeaderBuff.put(Utils.encodeString(message.getTopicName()));
if (message.getQos() == QOSType.LEAST_ONE ||
message.getQos() == QOSType.EXACTLY_ONCE ) {
if (message.getMessageID() == null) {
throw new IllegalArgumentException("Found a message with QOS 1 or 2 and not MessageID setted");
}
Utils.writeWord(variableHeaderBuff, message.getMessageID());
}
variableHeaderBuff.put(message.getPayload());
variableHeaderBuff.flip();
int variableHeaderSize = variableHeaderBuff.remaining();
byte flags = Utils.encodeFlags(message);
IoBuffer buff = IoBuffer.allocate(2 + variableHeaderSize).setAutoExpand(true);;
buff.put((byte) (AbstractMessage.PUBLISH << 4 | flags));
buff.put(Utils.encodeRemainingLength(variableHeaderSize));
buff.put(variableHeaderBuff).flip();
out.write(buff);
}
}
@@ -1,47 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
/**
* QoS, DUP and RETAIN are NOT used.
*
* @author andrea
*/
public class SubAckDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.SUBACK, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
SubAckMessage message = new SubAckMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
int remainingLength = message.getRemainingLength();
//MessageID
message.setMessageID(Utils.readWord(in));
remainingLength -= 2;
//Qos array
if (in.remaining() < remainingLength ) {
return NEED_DATA;
}
for (int i = 0; i < remainingLength; i++) {
byte qos = in.get();
message.addType(QOSType.values()[qos]);
}
out.write(message);
return OK;
}
}
@@ -1,39 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
/**
*
* @author andrea
*/
public class SubAckEncoder implements MessageEncoder<SubAckMessage> {
public void encode(IoSession session, SubAckMessage message, ProtocolEncoderOutput out) throws Exception {
if (message.types().isEmpty()) {
throw new IllegalArgumentException("Found a suback message with empty topics");
}
IoBuffer variableHeaderBuff = IoBuffer.allocate(4).setAutoExpand(true);
Utils.writeWord(variableHeaderBuff, message.getMessageID());
for (AbstractMessage.QOSType c : message.types()) {
byte ord = (byte) c.ordinal();
variableHeaderBuff.put((byte)c.ordinal());
}
variableHeaderBuff.flip();
int variableHeaderSize = variableHeaderBuff.remaining();
IoBuffer buff = IoBuffer.allocate(2 + variableHeaderSize);
buff.put((byte) (AbstractMessage.SUBACK << 4 ));
buff.put(Utils.encodeRemainingLength(variableHeaderSize));
buff.put(variableHeaderBuff).flip();
out.write(buff);
}
}
@@ -1,56 +0,0 @@
package org.dna.mqtt.moquette.proto;
import java.io.UnsupportedEncodingException;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage;
/**
*
* @author andrea
*/
public class SubscribeDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.SUBSCRIBE, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
SubscribeMessage message = new SubscribeMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
//check qos level
if (message.getQos() != QOSType.LEAST_ONE) {
return NOT_OK;
}
int start = in.position();
//read messageIDs
message.setMessageID(Utils.readWord(in));
int readed = in.position() - start;
while (readed < message.getRemainingLength()) {
decodeSubscription(in, message);
readed = in.position() - start;
}
out.write(message);
return OK;
}
/**
* Populate the message with couple of Qos, topic
*/
private void decodeSubscription(IoBuffer in, SubscribeMessage message) throws UnsupportedEncodingException {
String topic = Utils.decodeString(in);
byte qos = (byte)(in.get() & 0x03);
message.addSubscription(new SubscribeMessage.Couple(qos, topic));
}
}
@@ -1,45 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage.Couple;
/**
*
* @author andrea
*/
public class SubscribeEncoder implements MessageEncoder<SubscribeMessage> {
public void encode(IoSession session, SubscribeMessage message, ProtocolEncoderOutput out) throws Exception {
if (message.subscriptions().isEmpty()) {
throw new IllegalArgumentException("Found a subscribe message with empty topics");
}
if (message.getQos() != QOSType.LEAST_ONE) {
throw new IllegalArgumentException("Expected a message with QOS 1, found " + message.getQos());
}
IoBuffer variableHeaderBuff = IoBuffer.allocate(4).setAutoExpand(true);
Utils.writeWord(variableHeaderBuff, message.getMessageID());
for (Couple c : message.subscriptions()) {
variableHeaderBuff.put(Utils.encodeString(c.getTopic()));
variableHeaderBuff.put(c.getQos());
}
variableHeaderBuff.flip();
int variableHeaderSize = variableHeaderBuff.remaining();
byte flags = Utils.encodeFlags(message);
IoBuffer buff = IoBuffer.allocate(2 + variableHeaderSize);
buff.put((byte) (AbstractMessage.SUBSCRIBE << 4 | flags));
buff.put(Utils.encodeRemainingLength(variableHeaderSize));
buff.put(variableHeaderBuff).flip();
out.write(buff);
}
}
@@ -1,26 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.MessageIDMessage;
import org.dna.mqtt.moquette.proto.messages.UnsubAckMessage;
/**
*
* @author andrea
*/
public class UnsubAckDecoder extends MessageIDDecoder {
@Override
protected MessageIDMessage createMessage() {
return new UnsubAckMessage();
}
@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.UNSUBACK, in);
}
}
@@ -1,23 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.UnsubAckMessage;
/**
*
* @author andrea
*/
public class UnsubAckEncoder implements MessageEncoder<UnsubAckMessage> {
public void encode(IoSession session, UnsubAckMessage message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(4);
buff.put((byte) (AbstractMessage.UNSUBACK << 4));
buff.put(Utils.encodeRemainingLength(2));
Utils.writeWord(buff, message.getMessageID());
buff.flip();
out.write(buff);
}
}
@@ -1,46 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.UnsubscribeMessage;
/**
*
* @author andrea
*/
public class UnsubscribeDecoder extends MqttDecoder {
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
return Utils.checkDecodable(AbstractMessage.UNSUBSCRIBE, in);
}
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//Common decoding part
UnsubscribeMessage message = new UnsubscribeMessage();
if (decodeCommonHeader(message, in) == NEED_DATA) {
return NEED_DATA;
}
//check qos level
if (message.getQos() != QOSType.LEAST_ONE) {
return NOT_OK;
}
int start = in.position();
//read messageIDs
message.setMessageID(Utils.readWord(in));
int readed = in.position() - start;
while (readed < message.getRemainingLength()) {
message.addTopic(Utils.decodeString(in));
readed = in.position() - start;
}
out.write(message);
return OK;
}
}
@@ -1,43 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.UnsubscribeMessage;
/**
*
* @author andrea
*/
public class UnsubscribeEncoder implements MessageEncoder<UnsubscribeMessage> {
public void encode(IoSession session, UnsubscribeMessage message, ProtocolEncoderOutput out) throws Exception {
if (message.topics().isEmpty()) {
throw new IllegalArgumentException("Found an unsubscribe message with empty topics");
}
if (message.getQos() != QOSType.LEAST_ONE) {
throw new IllegalArgumentException("Expected a message with QOS 1, found " + message.getQos());
}
IoBuffer variableHeaderBuff = IoBuffer.allocate(4).setAutoExpand(true);
Utils.writeWord(variableHeaderBuff, message.getMessageID());
for (String topic : message.topics()) {
variableHeaderBuff.put(Utils.encodeString(topic));
}
variableHeaderBuff.flip();
int variableHeaderSize = variableHeaderBuff.remaining();
byte flags = Utils.encodeFlags(message);
IoBuffer buff = IoBuffer.allocate(2 + variableHeaderSize);
buff.put((byte) (AbstractMessage.UNSUBSCRIBE << 4 | flags));
buff.put(Utils.encodeRemainingLength(variableHeaderSize));
buff.put(variableHeaderBuff).flip();
out.write(buff);
}
}
@@ -1,67 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.ConnAckMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class ConnAckDecoderTest {
IoBuffer m_buff;
ConnAckDecoder m_msgdec;
MockProtocolDecoderOutput<ConnAckMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(4);
m_msgdec = new ConnAckDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<ConnAckMessage>();
}
@Test
public void testDecodable_OK() {
m_buff.put((byte)(AbstractMessage.CONNACK << 4))
.put((byte)0) //0 length
.flip();
assertEquals(MessageDecoder.OK , m_msgdec.decodable(null, m_buff));
}
@Test
public void testDecodable_NOT_OK() {
m_buff.put((byte)(AbstractMessage.CONNECT << 4))
.put((byte)0) //0 length
.flip();
assertEquals(MessageDecoder.NOT_OK , m_msgdec.decodable(null, m_buff));
}
@Test
public void testHeader() throws Exception {
m_buff = IoBuffer.allocate(14);
initHeader(m_buff);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
assertEquals(ConnAckMessage.CONNECTION_ACCEPTED, m_mockProtoDecoder.getMessage().getReturnCode());
assertEquals(AbstractMessage.CONNACK, m_mockProtoDecoder.getMessage().getMessageType());
}
private void initHeader(IoBuffer buff) {
buff.clear().put((byte)(AbstractMessage.CONNACK << 4)).put((byte)2);
//reserved
buff.put((byte)0);
//return code
buff.put(ConnAckMessage.CONNECTION_ACCEPTED);
}
}
@@ -1,27 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.ConnAckMessage;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author andrea
*/
public class ConnAckEncoderTest {
@Test
public void testHeaderEncode() throws Exception {
TestUtils.MockProtocolEncoderOutput mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
ConnAckEncoder encoder = new ConnAckEncoder();
ConnAckMessage msg = new ConnAckMessage();
//Exercise
encoder.encode(null, msg, mockProtoEncoder);
//Verify
assertEquals(0x20, mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(0x02, mockProtoEncoder.getBuffer().get()); //2 byte, length
assertEquals(ConnAckMessage.CONNECTION_ACCEPTED, mockProtoEncoder.getBuffer().skip(1).get());
}
}
@@ -1,190 +0,0 @@
package org.dna.mqtt.moquette.proto;
import java.io.UnsupportedEncodingException;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.ConnectMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class ConnectDecoderTest {
IoBuffer m_buff;
ConnectDecoder m_msgdec;
MockProtocolDecoderOutput<ConnectMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(4);
m_msgdec = new ConnectDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<ConnectMessage>();
}
@Test
public void testDecodable_OK() {
m_buff.put((byte)(AbstractMessage.CONNECT << 4))
.put((byte)0) //0 length
.flip();
assertEquals(MessageDecoder.OK , m_msgdec.decodable(null, m_buff));
}
@Test
public void testDecodable_NOT_OK() {
m_buff.put((byte)(AbstractMessage.CONNACK << 4))
.put((byte)0) //0 length
.flip();
assertEquals(MessageDecoder.NOT_OK , m_msgdec.decodable(null, m_buff));
}
@Test
public void testDecodable_NEED_DATA() {
m_buff = IoBuffer.allocate(0);
assertFalse(m_buff.hasRemaining());
assertEquals(MessageDecoder.NEED_DATA , m_msgdec.decodable(null, m_buff));
}
@Test
public void testDecodeRemainingLenght() {
//1 byte length
m_buff.put((byte)0x0).flip();
assertEquals(0, Utils.decodeRemainingLenght(m_buff));
m_buff.clear().put((byte) 0x007F).flip();
assertEquals(127, Utils.decodeRemainingLenght(m_buff));
//2 byte length
m_buff.clear().put((byte) 0x80).put((byte) 0x01).flip();
assertEquals(128, Utils.decodeRemainingLenght(m_buff));
m_buff.clear().put((byte) 0xFF).put((byte) 0x7F).flip();
assertEquals(16383, Utils.decodeRemainingLenght(m_buff));
//3 byte length
m_buff.clear().put((byte) 0x80).put((byte) 0x80).put((byte)0x01).flip();
assertEquals(16384, Utils.decodeRemainingLenght(m_buff));
m_buff.clear().put((byte) 0xFF).put((byte) 0xFF).put((byte)0x7F).flip();
assertEquals(2097151, Utils.decodeRemainingLenght(m_buff));
//4 byte length
m_buff.clear().put((byte) 0x80).put((byte) 0x80).put((byte)0x80).put((byte)0x01).flip();
assertEquals(2097152, Utils.decodeRemainingLenght(m_buff));
m_buff.clear().put((byte) 0xFF).put((byte) 0xFF).put((byte) 0xFF).put((byte)0x7F).flip();
assertEquals(268435455, Utils.decodeRemainingLenght(m_buff));
}
@Test
public void testBaseHeader() throws Exception {
m_buff = IoBuffer.allocate(14);
initBaseHeader(m_buff);
m_buff.flip();
//Excercise
m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
verifyBaseHeader(m_mockProtoDecoder.getMessage());
}
@Test
public void testBaseHeader_ClientID() throws UnsupportedEncodingException, Exception {
m_buff = IoBuffer.allocate(40);
initHeader(m_buff, (byte) 38);
encodeString(m_buff, "ABCDEFGH");
encodeString(m_buff, "Topic");
encodeString(m_buff, "Message");
m_buff.flip();
//Excercise
m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
verifyBaseHeader(m_mockProtoDecoder.getMessage());
assertEquals("ABCDEFGH", m_mockProtoDecoder.getMessage().getClientID());
assertEquals("Topic", m_mockProtoDecoder.getMessage().getWillTopic());
assertEquals("Message", m_mockProtoDecoder.getMessage().getWillMessage());
}
@Test
public void testBaseHeader_extra_with_user_pwd() throws UnsupportedEncodingException, Exception {
m_buff = IoBuffer.allocate(55);
initHeader(m_buff, (byte) 53);
encodeString(m_buff, "ABCDEFGH");
encodeString(m_buff, "Topic");
encodeString(m_buff, "Message");
encodeString(m_buff, "Fakeuser");
encodeString(m_buff, "pwd");
m_buff.flip();
//Excercise
m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
verifyBaseHeader(m_mockProtoDecoder.getMessage());
assertEquals(AbstractMessage.CONNECT, m_mockProtoDecoder.getMessage().getMessageType());
assertEquals("ABCDEFGH", m_mockProtoDecoder.getMessage().getClientID());
assertEquals("Topic", m_mockProtoDecoder.getMessage().getWillTopic());
assertEquals("Message", m_mockProtoDecoder.getMessage().getWillMessage());
assertEquals("Fakeuser", m_mockProtoDecoder.getMessage().getUsername());
assertEquals("pwd", m_mockProtoDecoder.getMessage().getPassword());
}
@Test
public void testBadFlagUserPwd() throws UnsupportedEncodingException, Exception {
m_buff = IoBuffer.allocate(14);
m_buff.clear().put((byte)(AbstractMessage.CONNECT << 4)).put((byte)12);
//Proto name
encodeString(m_buff, "MQIsdp");
//version
m_buff.put((byte)3);
//conn flags
m_buff.put((byte)0x4E); //sets user to false and password to true
//keepAlive
m_buff.put((byte)0).put((byte) 0x0A);
m_buff.flip();
//Excercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.NOT_OK, res);
}
/**
* Encode and insert the given string into the given buff
*/
private IoBuffer encodeString(IoBuffer buff, String str) throws UnsupportedEncodingException {
buff.put(Utils.encodeString(str));
return buff;
}
private void initBaseHeader(IoBuffer buff) throws UnsupportedEncodingException {
initHeader(buff, (byte)0x0C);
}
private void initHeader(IoBuffer buff, byte remaingLength) throws UnsupportedEncodingException {
buff.clear().put((byte)(AbstractMessage.CONNECT << 4)).put(remaingLength);
//Proto name
encodeString(buff, "MQIsdp");
//version
buff.put((byte)3);
//conn flags
buff.put((byte)0xCE);
//keepAlive
buff.put((byte)0).put((byte) 0x0A);
}
private void verifyBaseHeader(ConnectMessage connMessage) {
assertNotNull(connMessage);
assertEquals("MQIsdp", connMessage.getProtocolName());
assertEquals(3, connMessage.getProcotolVersion());
assertTrue(connMessage.isUserFlag());
assertTrue(connMessage.isPasswordFlag());
assertTrue(connMessage.isCleanSession());
assertEquals(10, connMessage.getKeepAlive());
assertTrue(connMessage.isWillFlag());
assertFalse(connMessage.isWillRetain());
assertEquals(1, connMessage.getWillQos());
}
}
@@ -1,147 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.ConnectEncoder;
import org.dna.mqtt.moquette.proto.Utils;
import org.dna.mqtt.moquette.proto.messages.ConnectMessage;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.dna.mqtt.moquette.proto.TestUtils.*;
/**
*
* @author andrea
*/
public class ConnectEncoderTest {
ConnectEncoder m_encoder;
TestUtils.MockProtocolEncoderOutput m_mockProtoEncoder;
@Before
public void setUp() {
m_encoder = new ConnectEncoder();
m_mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
}
@Test(expected=IllegalAccessException.class)
public void testEncodeRemainingLength_invalid_upper() throws IllegalAccessException {
Utils.encodeRemainingLength(Utils.MAX_LENGTH_LIMIT + 1);
}
@Test(expected=IllegalAccessException.class)
public void testEncodeRemainingLength_invalid_lower() throws IllegalAccessException {
Utils.encodeRemainingLength(-1);
}
@Test
public void testEncodeRemainingLenght() throws IllegalAccessException {
//1 byte length
verifyBuff(1, new byte[]{0}, Utils.encodeRemainingLength(0));
verifyBuff(1, new byte[]{0x7F}, Utils.encodeRemainingLength(127));
//2 byte length
verifyBuff(2, new byte[]{(byte)0x80, 0x01}, Utils.encodeRemainingLength(128));
verifyBuff(2, new byte[]{(byte)0xFF, 0x7F}, Utils.encodeRemainingLength(16383));
//3 byte length
verifyBuff(3, new byte[]{(byte)0x80, (byte)0x80, 0x01}, Utils.encodeRemainingLength(16384));
verifyBuff(3, new byte[]{(byte)0xFF, (byte)0xFF, 0x7F}, Utils.encodeRemainingLength(2097151));
//4 byte length
verifyBuff(4, new byte[]{(byte)0x80, (byte)0x80, (byte)0x80, 0x01}, Utils.encodeRemainingLength(2097152));
verifyBuff(4, new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, 0x7F}, Utils.encodeRemainingLength(268435455));
}
@Test
public void testBaseHeader() throws Exception {
ConnectMessage msg = new ConnectMessage();
msg.setWillRetain(true);
msg.setWillQos((byte)2);
msg.setWillFlag(false);
msg.setCleanSession(true);
msg.setKeepAlive(512);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals(0x10, m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(12, m_mockProtoEncoder.getBuffer().get()); //remaining length
verifyString("MQIsdp", m_mockProtoEncoder.getBuffer());
assertEquals(0x03, m_mockProtoEncoder.getBuffer().get()); //protocol version
assertEquals(0x32, m_mockProtoEncoder.getBuffer().get()); //flags
assertEquals(2, m_mockProtoEncoder.getBuffer().get()); //keepAliveTimer msb
assertEquals(0, m_mockProtoEncoder.getBuffer().get()); //keepAliveTimer lsb
}
@Test
public void testCompleteHeader() throws Exception {
ConnectMessage msg = new ConnectMessage();
msg.setWillRetain(true);
msg.setWillQos((byte)2);
msg.setWillFlag(true);
msg.setCleanSession(true);
msg.setKeepAlive(512);
//variable part
msg.setClientID("ABCDEF");
msg.setWillTopic("Topic");
msg.setWillMessage("Message");
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals(0x10, m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(36, m_mockProtoEncoder.getBuffer().get()); //remaining length
verifyString("MQIsdp", m_mockProtoEncoder.getBuffer());
assertEquals(0x03, m_mockProtoEncoder.getBuffer().get()); //protocol version
assertEquals(0x36, m_mockProtoEncoder.getBuffer().get()); //flags
assertEquals(2, m_mockProtoEncoder.getBuffer().get()); //keepAliveTimer msb
assertEquals(0, m_mockProtoEncoder.getBuffer().get()); //keepAliveTimer lsb
//Variable part
verifyString("ABCDEF", m_mockProtoEncoder.getBuffer());
verifyString("Topic", m_mockProtoEncoder.getBuffer());
verifyString("Message", m_mockProtoEncoder.getBuffer());
}
@Test
public void testCompleteHeaderWIthUser_password() throws Exception {
ConnectMessage msg = new ConnectMessage();
msg.setUserFlag(true);
msg.setPasswordFlag(true);
msg.setWillRetain(true);
msg.setWillQos((byte)2);
msg.setWillFlag(true);
msg.setCleanSession(true);
msg.setKeepAlive(512);
//variable part
msg.setClientID("ABCDEF");
msg.setWillTopic("Topic");
msg.setWillMessage("Message");
msg.setUsername("Pablo");
msg.setPassword("PBL");
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals(0x10, m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(48, m_mockProtoEncoder.getBuffer().get()); //remaining length
verifyString("MQIsdp", m_mockProtoEncoder.getBuffer());
assertEquals(0x03, m_mockProtoEncoder.getBuffer().get()); //protocol version
assertEquals((byte)0xF6, (byte)m_mockProtoEncoder.getBuffer().get()); //flags
assertEquals(2, m_mockProtoEncoder.getBuffer().get()); //keepAliveTimer msb
assertEquals(0, m_mockProtoEncoder.getBuffer().get()); //keepAliveTimer lsb
//Variable part
verifyString("ABCDEF", m_mockProtoEncoder.getBuffer());
verifyString("Topic", m_mockProtoEncoder.getBuffer());
verifyString("Message", m_mockProtoEncoder.getBuffer());
verifyString("Pablo", m_mockProtoEncoder.getBuffer());//username
verifyString("PBL", m_mockProtoEncoder.getBuffer());//password
}
}
@@ -1,51 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PubAckMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class PubAckDecoderTest {
IoBuffer m_buff;
PubAckDecoder m_msgdec;
MockProtocolDecoderOutput<PubAckMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(4);
m_msgdec = new PubAckDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<PubAckMessage>();
}
@Test
public void testHeader() throws Exception {
m_buff = IoBuffer.allocate(14);
int messageId = 0xAABB;
initHeader(m_buff, messageId);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
assertEquals(messageId, m_mockProtoDecoder.getMessage().getMessageID().intValue());
assertEquals(AbstractMessage.PUBACK, m_mockProtoDecoder.getMessage().getMessageType());
}
private void initHeader(IoBuffer buff, int messageID) {
buff.clear().put((byte)(AbstractMessage.PUBACK << 4)).put((byte)2);
//return code
Utils.writeWord(buff, messageID);
}
}
@@ -1,30 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.PubAckMessage;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author andrea
*/
public class PubAckEncoderTest {
@Test
public void testHeaderEncode() throws Exception {
int messageID = 0xAABB;
TestUtils.MockProtocolEncoderOutput mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
PubAckEncoder encoder = new PubAckEncoder();
PubAckMessage msg = new PubAckMessage();
msg.setMessageID(messageID);
//Exercise
encoder.encode(null, msg, mockProtoEncoder);
//Verify
assertEquals(0x40, mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(0x02, mockProtoEncoder.getBuffer().get()); //2 byte, length
assertEquals((byte)0xAA, mockProtoEncoder.getBuffer().get());
assertEquals((byte)0xBB, mockProtoEncoder.getBuffer().get());
}
}
@@ -1,175 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class PublishDecoderTest {
IoBuffer m_buff;
PublishDecoder m_msgdec;
MockProtocolDecoderOutput<PublishMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(4);
m_msgdec = new PublishDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<PublishMessage>();
}
@Test
public void testDecodable_OK() {
m_buff.put((byte) (AbstractMessage.PUBLISH << 4))
.put((byte) 0) //0 length
.flip();
assertEquals(MessageDecoder.OK, m_msgdec.decodable(null, m_buff));
}
@Test
public void testHeader() throws Exception {
m_buff = IoBuffer.allocate(14);
initHeader(m_buff);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
assertEquals("Fake Topic", m_mockProtoDecoder.getMessage().getTopicName());
assertNull(m_mockProtoDecoder.getMessage().getMessageID());
assertEquals(AbstractMessage.PUBLISH, m_mockProtoDecoder.getMessage().getMessageType());
}
@Test
public void testHeaderWithMessageID() throws Exception {
m_buff = IoBuffer.allocate(14).setAutoExpand(true);
int messageID = 123;
initHeaderWithMessageID(m_buff, messageID);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
assertEquals("Fake Topic", m_mockProtoDecoder.getMessage().getTopicName());
assertEquals(messageID, (int) m_mockProtoDecoder.getMessage().getMessageID());
}
@Test
public void testHeaderWithMessageID_Payload() throws Exception {
m_buff = IoBuffer.allocate(14).setAutoExpand(true);
int messageID = 123;
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
initHeaderWithMessageID_Payload(m_buff, messageID, payload);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
assertEquals("Fake Topic", m_mockProtoDecoder.getMessage().getTopicName());
assertEquals(messageID, (int) m_mockProtoDecoder.getMessage().getMessageID());
TestUtils.verifyEquals(payload, m_mockProtoDecoder.getMessage().getPayload());
}
@Test
public void testBugOnRealCase() throws Exception {
byte[] overallMessage = new byte[]{0x30, 0x17, //fixed header, 25 byte lenght
0x00, 0x06, 0x2f, 0x74, 0x6f, 0x70, 0x69, 0x63, //[/topic] string 2 len + 6 content
0x54, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x79, // [Test my payload] encoding
0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64};
m_buff = IoBuffer.allocate(overallMessage.length).setAutoExpand(true);
m_buff.put(overallMessage);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
}
@Test
public void testDecodeBigContent() throws Exception {
int size = 129;
IoBuffer payload = TestUtils.generateRandomPayload(size);
IoBuffer firstPublish = generatePublishQoS0(payload);
IoBuffer secondPublish = generatePublishQoS0(TestUtils.generateRandomPayload(size));
IoBuffer doubleMessageBuf = IoBuffer.allocate(size * 2).setAutoExpand(true);
doubleMessageBuf.put(firstPublish).put(secondPublish).flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, doubleMessageBuf, m_mockProtoDecoder);
assertEquals(MessageDecoder.OK, res);
PublishMessage pubMsg = m_mockProtoDecoder.getMessage();
assertNotNull(pubMsg);
res = m_msgdec.decode(null, doubleMessageBuf, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
m_buff.flip();
}
private void initHeader(IoBuffer buff) throws IllegalAccessException {
IoBuffer tmp = IoBuffer.allocate(4).setAutoExpand(true).put(Utils.encodeString("Fake Topic")).flip();
buff.clear().put((byte) (AbstractMessage.PUBLISH << 4)).put(Utils.encodeRemainingLength(tmp.remaining()));
//topic name
buff.put(tmp);
}
private void initHeaderWithMessageID(IoBuffer buff, int messageID) throws IllegalAccessException {
IoBuffer tmp = IoBuffer.allocate(4).setAutoExpand(true).put(Utils.encodeString("Fake Topic"));
Utils.writeWord(tmp, messageID);
tmp.flip();
buff.clear().put((byte) (AbstractMessage.PUBLISH << 4 | 0x02)) //set Qos to 1
.put(Utils.encodeRemainingLength(tmp.remaining()));
//topic name
buff.put(tmp);
}
private void initHeaderWithMessageID_Payload(IoBuffer buff, int messageID, byte[] payload) throws IllegalAccessException {
IoBuffer tmp = IoBuffer.allocate(4).setAutoExpand(true).put(Utils.encodeString("Fake Topic"));
Utils.writeWord(tmp, messageID);
tmp.put(payload);
tmp.flip();
buff.clear().put((byte) (AbstractMessage.PUBLISH << 4 | 0x02)) //set Qos to 1
.put(Utils.encodeRemainingLength(tmp.remaining()));
//topic name
buff.put(tmp);
}
private IoBuffer generatePublishQoS0(IoBuffer payload) throws IllegalAccessException {
int size = payload.capacity();
IoBuffer messageBody = IoBuffer.allocate(size).setAutoExpand(true);
messageBody.put(Utils.encodeString("/topic"));
//ONLY for QoS > 1 Utils.writeWord(messageBody, messageID);
messageBody.put(payload).flip();
IoBuffer completeMsg = IoBuffer.allocate(size).setAutoExpand(true);
completeMsg.clear().put((byte) (AbstractMessage.PUBLISH << 4 | 0x00)) //set Qos to 0
.put(Utils.encodeRemainingLength(messageBody.remaining()));
completeMsg.put(messageBody).flip();
return completeMsg;
}
}
@@ -1,166 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.dna.mqtt.moquette.proto.TestUtils.*;
/**
*
* @author andrea
*/
public class PublishEncoderTest {
PublishEncoder m_encoder;
TestUtils.MockProtocolEncoderOutput m_mockProtoEncoder;
@Before
public void setUp() {
m_encoder = new PublishEncoder();
m_mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
}
@Test
public void testEncodeWithQos_0_noMessageID() throws Exception {
String topic = "/photos";
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.MOST_ONE);
msg.setTopicName(topic);
//variable part
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
msg.setPayload(payload);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals(0x30, m_mockProtoEncoder.getBuffer().get()); //1 byte
//(2+7) topic + 3 payload
assertEquals(12, m_mockProtoEncoder.getBuffer().get()); //remaining length
//Variable part
verifyString(topic, m_mockProtoEncoder.getBuffer());
verifyBuff(payload.length, payload, m_mockProtoEncoder.getBuffer());
}
@Test
public void testEncodeWithQos_1_MessageID() throws Exception {
String topic = "/photos";
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.LEAST_ONE);
msg.setMessageID(1);
msg.setTopicName(topic);
//variable part
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
msg.setPayload(payload);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals(0x32, m_mockProtoEncoder.getBuffer().get()); //1 byte
//(2+7) topic + 2 messageID + 3 payload
assertEquals(14, m_mockProtoEncoder.getBuffer().get()); //remaining length
//Variable part
verifyString(topic, m_mockProtoEncoder.getBuffer());
assertEquals(0, m_mockProtoEncoder.getBuffer().get()); //MessageID MSB
assertEquals(1, m_mockProtoEncoder.getBuffer().get()); //MessageID LSB
verifyBuff(payload.length, payload, m_mockProtoEncoder.getBuffer());
}
@Test(expected = IllegalArgumentException.class)
public void testEncodeWithQos_1_noMessageID_fail() throws Exception {
String topic = "pictures/photos";
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.LEAST_ONE);
msg.setTopicName(topic);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_empty_topic() throws Exception {
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.LEAST_ONE);
msg.setMessageID(1);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_null_topic() throws Exception {
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.LEAST_ONE);
msg.setMessageID(1);
msg.setTopicName(null);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_qos_reserved() throws Exception {
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.RESERVED);
msg.setMessageID(1);
msg.setTopicName(null);
//variable part
byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
msg.setPayload(payload);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
@Test
public void testBugMissedMessageIDEncoding() throws Exception{
String topic = "/topic";
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.MOST_ONE);
msg.setTopicName(topic);
//variable part
byte[] payload = "Test my payload".getBytes();
msg.setPayload(payload);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
//2 byte header + (2+6) topic name + [2 message ID if QoQ <> 0]+ payload
int size = m_mockProtoEncoder.getBuffer().remaining();
assertEquals(10+payload.length, size);
assertEquals(0x30, m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(23, m_mockProtoEncoder.getBuffer().get()); //1 byte the length
}
@Test
public void testEncodeBigMessage() throws Exception {
byte[] payload = new byte[256];
TestUtils.generateRandomPayload(256).get(payload);
String topic = "/topic";
PublishMessage msg = new PublishMessage();
msg.setQos(QOSType.MOST_ONE);
msg.setTopicName(topic);
//variable part
msg.setPayload(payload);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
int size = m_mockProtoEncoder.getBuffer().remaining();
assertEquals(11+payload.length, size);
assertEquals(0x30, m_mockProtoEncoder.getBuffer().get()); //1 byte
}
}
@@ -1,81 +0,0 @@
package org.dna.mqtt.moquette.proto;
import java.util.List;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class SubAckDecoderTest {
IoBuffer m_buff;
SubAckDecoder m_msgdec;
MockProtocolDecoderOutput<SubAckMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(7);
m_msgdec = new SubAckDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<SubAckMessage>();
}
@Test
public void testBadQos() throws Exception {
initHeaderQos(m_buff, 0xAABB, QOSType.LEAST_ONE, QOSType.MOST_ONE, QOSType.MOST_ONE);
m_buff.flip();
//Excercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
assertEquals(MessageDecoderResult.OK, res);
assertEquals(0xAABB, m_mockProtoDecoder.getMessage().getMessageID().intValue());
List<QOSType> qoses = m_mockProtoDecoder.getMessage().types();
assertEquals(3, qoses.size());
assertEquals(QOSType.LEAST_ONE, qoses.get(0));
assertEquals(QOSType.MOST_ONE, qoses.get(1));
assertEquals(QOSType.MOST_ONE, qoses.get(2));
assertEquals(AbstractMessage.SUBACK, m_mockProtoDecoder.getMessage().getMessageType());
}
@Test
public void testBugBadRemainingCalculation() throws Exception {
byte[] overallMessage = new byte[] {(byte)0x90, 0x03, //fixed header
0x00, 0x0A, //MSG ID
0x01}; //QoS array
m_buff = IoBuffer.allocate(overallMessage.length).setAutoExpand(true);
m_buff.put(overallMessage);
m_buff.flip();
//Exercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
assertEquals(MessageDecoder.OK, res);
SubAckMessage message = (SubAckMessage) m_mockProtoDecoder.getMessage();
assertEquals(0x0A, message.getMessageID().intValue());
assertEquals(1, message.types().size());
assertEquals(AbstractMessage.QOSType.LEAST_ONE, message.types().get(0));
}
private void initHeaderQos(IoBuffer buff, int messageID, QOSType... qoss) throws IllegalAccessException {
buff.clear().put((byte) (AbstractMessage.SUBACK << 4)).
put(Utils.encodeRemainingLength(2 + qoss.length));
Utils.writeWord(buff, messageID);
for (QOSType qos : qoss) {
buff.put((byte)qos.ordinal());
}
}
}
@@ -1,57 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author andrea
*/
public class SubAckEncoderTest {
SubAckEncoder m_encoder;
TestUtils.MockProtocolEncoderOutput m_mockProtoEncoder;
@Before
public void setUp() {
m_encoder = new SubAckEncoder();
m_mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
}
@Test(expected = IllegalArgumentException.class)
public void testEncodeWithNoQoss() throws Exception {
SubAckMessage msg = new SubAckMessage();
msg.setMessageID(123);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
@Test
public void testEncodeWithMultipleQos() throws Exception {
SubAckMessage msg = new SubAckMessage();
int messageID = 0xAABB;
msg.setMessageID(messageID);
msg.addType(QOSType.MOST_ONE);
msg.addType(QOSType.LEAST_ONE);
msg.addType(QOSType.EXACTLY_ONCE);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals((byte) (AbstractMessage.SUBACK << 4 ), m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(5, m_mockProtoEncoder.getBuffer().get()); //remaining length
//Variable part
assertEquals((byte)0xAA, m_mockProtoEncoder.getBuffer().get()); //MessageID MSB
assertEquals((byte)0xBB, m_mockProtoEncoder.getBuffer().get()); //MessageID LSB
assertEquals((byte)QOSType.MOST_ONE.ordinal(), m_mockProtoEncoder.getBuffer().get());
assertEquals((byte)QOSType.LEAST_ONE.ordinal(), m_mockProtoEncoder.getBuffer().get());
assertEquals((byte)QOSType.EXACTLY_ONCE.ordinal(), m_mockProtoEncoder.getBuffer().get());
}
}
@@ -1,78 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage.Couple;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class SubscribeDecoderTest {
IoBuffer m_buff;
SubscribeDecoder m_msgdec;
MockProtocolDecoderOutput<SubscribeMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(4);
m_msgdec = new SubscribeDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<SubscribeMessage>();
}
@Test
public void testBadQos() throws Exception {
m_buff = IoBuffer.allocate(2);
initHeaderBadQos(m_buff);
m_buff.flip();
//Excercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
assertEquals(MessageDecoderResult.NOT_OK, res);
}
@Test
public void testMultiTopic() throws Exception {
m_buff = IoBuffer.allocate(4).setAutoExpand(true);
Couple c1 = new Couple((byte)2, "a/b");
Couple c2 = new Couple((byte)1, "c/d/e");
initMultiTopic(m_buff, 123, c1, c2);
m_buff.flip();
//Excercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
assertEquals(MessageDecoderResult.OK, res);
assertEquals(2, m_mockProtoDecoder.getMessage().subscriptions().size());
assertEquals(AbstractMessage.SUBSCRIBE, m_mockProtoDecoder.getMessage().getMessageType());
}
private void initHeaderBadQos(IoBuffer buff) {
buff.clear().put((byte)(AbstractMessage.SUBSCRIBE << 4)).put((byte)0);
}
private void initMultiTopic(IoBuffer buff, int messageID, Couple... topics) throws IllegalAccessException {
IoBuffer topicBuffer = IoBuffer.allocate(4).setAutoExpand(true);
Utils.writeWord(topicBuffer, messageID);
for (Couple couple : topics) {
topicBuffer.put(Utils.encodeString(couple.getTopic()));
topicBuffer.put((byte)couple.getQos());
}
topicBuffer.flip();
buff.clear().put((byte)(AbstractMessage.SUBSCRIBE << 4 | (byte)0x02))
.put(Utils.encodeRemainingLength(topicBuffer.remaining()));
buff.put(topicBuffer);
}
}
@@ -1,76 +0,0 @@
package org.dna.mqtt.moquette.proto;
import static org.dna.mqtt.moquette.proto.TestUtils.*;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage;
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage.Couple;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class SubscribeEncoderTest {
SubscribeEncoder m_encoder;
TestUtils.MockProtocolEncoderOutput m_mockProtoEncoder;
@Before
public void setUp() {
m_encoder = new SubscribeEncoder();
m_mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
}
@Test
public void testEncodeWithMultiTopic() throws Exception {
SubscribeMessage msg = new SubscribeMessage();
msg.setQos(QOSType.LEAST_ONE);
msg.setMessageID(0xAABB);
//variable part
Couple c1 = new Couple((byte)1, "a/b");
Couple c2 = new Couple((byte)0, "a/b/c");
msg.addSubscription(c1);
msg.addSubscription(c2);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
//Verify
assertEquals((byte)0x82, (byte)m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(16, m_mockProtoEncoder.getBuffer().get()); //remaining length
//verify M1ssageID
assertEquals((byte)0xAA, m_mockProtoEncoder.getBuffer().get());
assertEquals((byte)0xBB, m_mockProtoEncoder.getBuffer().get());
//Variable part
verifyString(c1.getTopic(), m_mockProtoEncoder.getBuffer());
assertEquals(c1.getQos(), m_mockProtoEncoder.getBuffer().get());
verifyString(c2.getTopic(), m_mockProtoEncoder.getBuffer());
assertEquals(c2.getQos(), m_mockProtoEncoder.getBuffer().get());
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_empty_subscription() throws Exception {
SubscribeMessage msg = new SubscribeMessage();
msg.setQos(QOSType.LEAST_ONE);
msg.setMessageID(0xAABB);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_badQos() throws Exception {
SubscribeMessage msg = new SubscribeMessage();
msg.setQos(QOSType.EXACTLY_ONCE);
msg.setMessageID(0xAABB);
//Exercise
m_encoder.encode(null, msg, m_mockProtoEncoder);
}
}
@@ -1,124 +0,0 @@
package org.dna.mqtt.moquette.proto;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.IoFilter.NextFilter;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import static org.junit.Assert.*;
/**
*
* @author andrea
*/
public class TestUtils {
static final class MockProtocolDecoderOutput<T extends AbstractMessage> implements ProtocolDecoderOutput {
protected T m_connMessage;
public T getMessage() {
return m_connMessage;
}
public void write(Object message) {
m_connMessage = (T) message;
}
public void flush(NextFilter nextFilter, IoSession session) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
static final class MockProtocolEncoderOutput implements ProtocolEncoderOutput {
protected IoBuffer m_buffer;
public IoBuffer getBuffer() {
return m_buffer;
}
public void write(Object buffer) {
m_buffer = (IoBuffer) buffer;
}
public void mergeAll() {
throw new UnsupportedOperationException("Not supported yet.");
}
public WriteFuture flush() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
/**
* Verify the presence of the given string starting from the current position
* inside the buffer.
*/
static void verifyString(String str, IoBuffer buff) throws UnsupportedEncodingException {
IoBuffer tmpBuff = IoBuffer.allocate(2).setAutoExpand(true);
byte[] raw = str.getBytes("UTF-8");
Utils.writeWord(tmpBuff, raw.length);
tmpBuff.put(raw).flip();
verifyIoBuffer(tmpBuff, buff);
}
static void verifyIoBuffer(IoBuffer expected, IoBuffer found) {
while(expected.hasRemaining()) {
assertEquals(expected.get(), found.get());
}
}
/**
* Verify that the given bytes buffer of the given numBytes length is present
* in the buff starting from the current position.
*/
static void verifyBuff(int numBytes, byte[] bytes, IoBuffer buff) {
assertTrue(numBytes <= buff.remaining());
byte[] toCheck = new byte[numBytes];
buff.get(toCheck);
for (int i = 0; i < numBytes; i++) {
assertEquals(bytes[i], toCheck[i]);
}
}
static void verifyEquals(byte[] expected, byte[] found) {
assertEquals(expected.length, found.length);
for (int i = 0; i < expected.length; i++) {
assertEquals(expected[i], found[i]);
}
}
public static IoBuffer generateRandomPayload(int size) {
IoBuffer payloadBuffer = IoBuffer.allocate(size);
for (int i = 0; i < size; i++) {
payloadBuffer.put((byte) (Math.random() * 255));
}
payloadBuffer.flip();
return payloadBuffer;
}
public static IoBuffer loadFile(String path) throws FileNotFoundException, IOException {
File f = new File(path);
long size = f.length();
byte[] payload = new byte[(int) size];
FileInputStream fr = new FileInputStream(f);
fr.read(payload);
IoBuffer payloadBuffer = IoBuffer.allocate((int) size);
payloadBuffer.put(payload).flip();
return payloadBuffer;
}
}
@@ -1,119 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.dna.mqtt.moquette.proto.TestUtils.MockProtocolDecoderOutput;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.UnsubscribeMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author andrea
*/
public class UnsubscribeDecoderTest {
IoBuffer m_buff;
UnsubscribeDecoder m_msgdec;
MockProtocolDecoderOutput<UnsubscribeMessage> m_mockProtoDecoder;
@Before
public void setUp() {
m_buff = IoBuffer.allocate(4);
m_msgdec = new UnsubscribeDecoder();
m_mockProtoDecoder = new MockProtocolDecoderOutput<UnsubscribeMessage>();
}
@Test
public void testBadQos() throws Exception {
m_buff = IoBuffer.allocate(2);
initHeaderBadQos(m_buff);
m_buff.flip();
//Excercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
assertEquals(MessageDecoderResult.NOT_OK, res);
}
@Test
public void testMultiTopic() throws Exception {
m_buff = IoBuffer.allocate(4).setAutoExpand(true);
String topic1 = "a/b";
String topic2 = "c/d/e";
initMultiTopic(m_buff, 123, topic1, topic2);
m_buff.flip();
//Excercise
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//Verify
assertEquals(MessageDecoderResult.OK, res);
assertEquals(2, m_mockProtoDecoder.getMessage().topics().size());
assertEquals(topic1, m_mockProtoDecoder.getMessage().topics().get(0));
assertEquals(topic2, m_mockProtoDecoder.getMessage().topics().get(1));
assertEquals(AbstractMessage.UNSUBSCRIBE, m_mockProtoDecoder.getMessage().getMessageType());
}
@Test
public void testDecodeSingleTopic_bug() throws Exception {
//A2 0C 00 01 00 06 2F 74 6F 70 69 63 //12 byte
byte[] overallMessage = new byte[] {(byte)0xA2, 0x0A, //fixed header
0x00, 0x01, //MSG ID
0x00, 0x06, 0x2F, 0x74, 0x6F, 0x70, 0x69, 0x63}; //"/topic" string
m_buff = IoBuffer.allocate(overallMessage.length).setAutoExpand(true);
m_buff.put(overallMessage);
m_buff.flip();
MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
assertNotNull(m_mockProtoDecoder.getMessage());
UnsubscribeMessage message = (UnsubscribeMessage) m_mockProtoDecoder.getMessage();
// assertEquals(0x0A, message.getMessageID());
// assertEquals(1, message.types().size());
// assertEquals(AbstractMessage.QOSType.LEAST_ONE, message.types().get(0));
}
// @Test
// public void testDecodeSingleTopic_BadFormat() throws Exception {
// //A2 0C 00 01 00 06 2F 74 6F 70 69 63 //10 byte of content, but lenght says 12!!
// byte[] overallMessage = new byte[] {(byte)0xA2, 0x0C, //fixed header
// 0x00, 0x01, //MSG ID
// 0x00, 0x06, 0x2F, 0x74, 0x6F, 0x70, 0x69, 0x63}; //"/topic" string
// m_buff = IoBuffer.allocate(overallMessage.length).setAutoExpand(true);
// m_buff.put(overallMessage);
// m_buff.flip();
//
// MessageDecoderResult res = m_msgdec.decode(null, m_buff, m_mockProtoDecoder);
//
// assertNotNull(m_mockProtoDecoder.getMessage());
// UnsubscribeMessage message = (UnsubscribeMessage) m_mockProtoDecoder.getMessage();
//// assertEquals(0x0A, message.getMessageID());
//// assertEquals(1, message.types().size());
//// assertEquals(AbstractMessage.QOSType.LEAST_ONE, message.types().get(0));
//
// }
private void initHeaderBadQos(IoBuffer buff) {
buff.clear().put((byte)(AbstractMessage.UNSUBSCRIBE << 4)).put((byte)0);
}
private void initMultiTopic(IoBuffer buff, int messageID, String... topics) throws IllegalAccessException {
IoBuffer topicBuffer = IoBuffer.allocate(4).setAutoExpand(true);
Utils.writeWord(topicBuffer, messageID);
for (String topic : topics) {
topicBuffer.put(Utils.encodeString(topic));
}
topicBuffer.flip();
buff.clear().put((byte)(AbstractMessage.UNSUBSCRIBE << 4 | (byte)0x02))
.put(Utils.encodeRemainingLength(topicBuffer.remaining()));
buff.put(topicBuffer);
}
}
@@ -1,94 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.UnsubscribeMessage;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.dna.mqtt.moquette.proto.TestUtils.*;
/**
*
* @author andrea
*/
public class UnsubscribeEncoderTest {
UnsubscribeMessage m_msg;
UnsubscribeEncoder m_encoder;
TestUtils.MockProtocolEncoderOutput m_mockProtoEncoder;
@Before
public void setUp() {
m_encoder = new UnsubscribeEncoder();
m_mockProtoEncoder = new TestUtils.MockProtocolEncoderOutput();
m_msg = new UnsubscribeMessage();
m_msg.setMessageID(0xAABB);
}
@Test
public void testEncodeWithSingleTopic() throws Exception {
m_msg.setQos(QOSType.LEAST_ONE);
//variable part
String topic1 = "/topic";
m_msg.addTopic(topic1);
//Exercise
m_encoder.encode(null, m_msg, m_mockProtoEncoder);
//Verify
assertEquals((byte)0xA2, (byte)m_mockProtoEncoder.getBuffer().get()); //1 byte
//2 messageID + 2 length + 6 chars = 10
assertEquals(10, m_mockProtoEncoder.getBuffer().get()); //remaining length
//verify M1ssageID
assertEquals((byte)0xAA, m_mockProtoEncoder.getBuffer().get());
assertEquals((byte)0xBB, m_mockProtoEncoder.getBuffer().get());
//Variable part
verifyString(topic1, m_mockProtoEncoder.getBuffer());
}
@Test
public void testEncodeWithMultiTopic() throws Exception {
m_msg.setQos(QOSType.LEAST_ONE);
//variable part
String topic1 = "a/b";
String topic2 = "a/b/c";
m_msg.addTopic(topic1);
m_msg.addTopic(topic2);
//Exercise
m_encoder.encode(null, m_msg, m_mockProtoEncoder);
//Verify
assertEquals((byte)0xA2, (byte)m_mockProtoEncoder.getBuffer().get()); //1 byte
assertEquals(14, m_mockProtoEncoder.getBuffer().get()); //remaining length
//verify M1ssageID
assertEquals((byte)0xAA, m_mockProtoEncoder.getBuffer().get());
assertEquals((byte)0xBB, m_mockProtoEncoder.getBuffer().get());
//Variable part
verifyString(topic1, m_mockProtoEncoder.getBuffer());
verifyString(topic2, m_mockProtoEncoder.getBuffer());
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_empty_topics() throws Exception {
m_msg.setQos(QOSType.LEAST_ONE);
//Exercise
m_encoder.encode(null, m_msg, m_mockProtoEncoder);
}
@Test(expected = IllegalArgumentException.class)
public void testEncode_badQos() throws Exception {
m_msg.setQos(QOSType.EXACTLY_ONCE);
//Exercise
m_encoder.encode(null, m_msg, m_mockProtoEncoder);
}
}
@@ -1,25 +0,0 @@
package org.dna.mqtt.moquette.proto;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
import org.dna.mqtt.moquette.proto.messages.UnsubscribeMessage;
import static org.junit.Assert.*;
import org.junit.Test;
/**
*
* @author andrea
*/
public class UtilsTests {
@Test
public void testEncodeFlags() {
UnsubscribeMessage msg = new UnsubscribeMessage();
msg.setRetainFlag(true);
msg.setQos(AbstractMessage.QOSType.MOST_ONE);
//Exercise
assertEquals(1, Utils.encodeFlags(msg));
}
}
@@ -1,19 +0,0 @@
# Set root logger level to DEBUG and its only appender to A1.
#log4j.rootLogger=ERROR, A1
log4j.rootLogger=INFO, A1
#log4j.rootLogger=WARN, A1
#log4j.logger.org.dna.mqtt.moquette.client=WARN
#log4j.logger.org.mina=WARN
#log4j.logger.org.dna.mqtt.moquette.server=DEBUG
#log4j.logger.org.dna.mqtt.moquette.messaging=DEBUG
#log4j.logger.org.dna.mqtt.moquette.proto.MQTTLoggingFilter=DEBUG
#log4j.logger.org.dna.mqtt.moquette.proto.PublishDecoder=DEBUG
log4j.logger.org.dna.mqtt.bechnmark=INFO
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c{1} %x - %m%n