Removed dependency on Mina IO framework
This commit is contained in:
@@ -1,69 +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-benchmark</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.1</version>
|
||||
<name>Moquette - Benchmarking tool</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dna.mqtt</groupId>
|
||||
<artifactId>moquette-mina-parser</artifactId>
|
||||
<version>0.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.fusesource.mqtt-client</groupId>
|
||||
<artifactId>mqtt-client</artifactId>
|
||||
<version>1.3</version>
|
||||
</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>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.dna.mqtt.bechnmark.mina.MQTTDropServer</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,78 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark;
|
||||
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ConsumerBlocking implements Runnable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConsumerBlocking.class);
|
||||
|
||||
private String m_clientID;
|
||||
|
||||
public ConsumerBlocking(String clientID) {
|
||||
m_clientID = clientID;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
MQTT mqtt = new MQTT();
|
||||
try {
|
||||
// mqtt.setHost("test.mosquitto.org", 1883);
|
||||
mqtt.setHost("localhost", 1883);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.error(null, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
mqtt.setClientId(m_clientID);
|
||||
BlockingConnection connection = mqtt.blockingConnection();
|
||||
try {
|
||||
connection.connect();
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't CONNECT to the server", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Topic[] topics = {new Topic("/topic", QoS.AT_MOST_ONCE)};
|
||||
byte[] qoses = connection.subscribe(topics);
|
||||
LOG.info("Subscribed to topic");
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't PUSBLISH to the server", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
Message message = null;
|
||||
for (int i = 0; i < Producer.PUB_LOOP; i++) {
|
||||
try {
|
||||
message = connection.receive();
|
||||
} catch (Exception ex) {
|
||||
LOG.error(null, ex);
|
||||
return;
|
||||
}
|
||||
byte[] payload = message.getPayload();
|
||||
StringBuffer sb = new StringBuffer().append("Topic: ").append(message.getTopic())
|
||||
.append(", payload: ").append(new String(payload));
|
||||
LOG.info(sb.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
LOG.info("Disconneting");
|
||||
connection.disconnect();
|
||||
LOG.info("Disconnected");
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't DISCONNECT to the server", ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.fusesource.mqtt.client.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ConsumerFuture implements Runnable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConsumerFuture.class);
|
||||
|
||||
private String m_clientID;
|
||||
private static final String BENCHMARK_FILE = "consumer_bechmark.txt";
|
||||
private PrintWriter m_benchMarkOut;
|
||||
private ByteArrayOutputStream m_baos = new ByteArrayOutputStream(1024 * 1024);
|
||||
|
||||
public ConsumerFuture(String clientID) {
|
||||
m_clientID = clientID;
|
||||
m_benchMarkOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(m_baos)));
|
||||
m_benchMarkOut.println("msg ID, ns");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
MQTT mqtt = new MQTT();
|
||||
try {
|
||||
// mqtt.setHost("test.mosquitto.org", 1883);
|
||||
mqtt.setHost("localhost", 1883);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.error(null, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
mqtt.setClientId(m_clientID);
|
||||
FutureConnection connection = mqtt.futureConnection();
|
||||
Future<Void> futConn = connection.connect();
|
||||
|
||||
try {
|
||||
futConn.await();
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't CONNECT to the server", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Topic[] topics = {new Topic("/topic", QoS.AT_MOST_ONCE)};
|
||||
Future<byte[]> futSub = connection.subscribe(topics);
|
||||
try {
|
||||
byte[] qoses = futSub.await();
|
||||
LOG.info("Subscribed to topic");
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't PUSBLISH to the server", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
Pattern p = Pattern.compile(".*!!(\\d+)");
|
||||
Message message = null;
|
||||
long startMillis = System.currentTimeMillis();
|
||||
for (int i = 0; i < Producer.PUB_LOOP; i++) {
|
||||
Future<Message> futReceive = connection.receive();
|
||||
try {
|
||||
message = futReceive.await();
|
||||
String content = new String(message.getPayload());
|
||||
|
||||
//metrics part
|
||||
Matcher matcher = p.matcher(content);
|
||||
matcher.matches();
|
||||
String numMsg = matcher.group(1);
|
||||
m_benchMarkOut.println(String.format("%s, %d", numMsg, System.nanoTime()));
|
||||
} catch (Exception ex) {
|
||||
LOG.error(null, ex);
|
||||
return;
|
||||
}
|
||||
byte[] payload = message.getPayload();
|
||||
StringBuffer sb = new StringBuffer().append("Topic: ").append(message.getTopic())
|
||||
.append(", payload: ").append(new String(payload));
|
||||
LOG.debug(sb.toString());
|
||||
}
|
||||
|
||||
long time = System.currentTimeMillis() - startMillis;
|
||||
LOG.info(String.format("Consumer %s received %d messages in %d ms", Thread.currentThread().getName(), Producer.PUB_LOOP, time));
|
||||
|
||||
Future<Void> f4 = connection.disconnect();
|
||||
try {
|
||||
LOG.info("Disconneting");
|
||||
f4.await();
|
||||
LOG.info("Disconnected");
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't DISCONNECT to the server", ex);
|
||||
}
|
||||
|
||||
m_benchMarkOut.close();
|
||||
|
||||
try {
|
||||
FileOutputStream fw = new FileOutputStream(BENCHMARK_FILE);
|
||||
fw.write(m_baos.toByteArray());
|
||||
fw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
*
|
||||
* Benchmark tool entry point.
|
||||
*
|
||||
* You could set the number of producers and consumers
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class Main {
|
||||
private static final int PUBLISHER_POOL_SIZE = 2;
|
||||
private static final int NUM_CONCURRENT_PRODS = 2;
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
ExecutorService consumerPool = Executors.newFixedThreadPool(PUBLISHER_POOL_SIZE);
|
||||
ExecutorService producerPool = Executors.newFixedThreadPool(PUBLISHER_POOL_SIZE);
|
||||
|
||||
consumerPool.submit(new ConsumerFuture("Cons1"));
|
||||
|
||||
//force wait to let the consumer be registered before the producer
|
||||
Thread.sleep(1000);
|
||||
int len = Producer.PUB_LOOP / NUM_CONCURRENT_PRODS;
|
||||
for (int i = 0; i < NUM_CONCURRENT_PRODS; i++) {
|
||||
producerPool.submit(new Producer("Prod " + i, i * len, len));
|
||||
}
|
||||
|
||||
consumerPool.shutdown();
|
||||
producerPool.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import org.fusesource.mqtt.client.BlockingConnection;
|
||||
import org.fusesource.mqtt.client.MQTT;
|
||||
import org.fusesource.mqtt.client.QoS;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class only publish MQTT messages to a define topic with a certain frequency.
|
||||
*
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class Producer implements Runnable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Producer.class);
|
||||
|
||||
private String m_clientID;
|
||||
|
||||
public static final int PUB_LOOP = 100000;
|
||||
|
||||
private int m_starIndex;
|
||||
private int m_len;
|
||||
private long m_startMillis;
|
||||
private static final String BENCHMARK_FILE = "producer_bechmark_%s.txt";
|
||||
private PrintWriter m_benchMarkOut;
|
||||
private ByteArrayOutputStream m_baos = new ByteArrayOutputStream(1024 * 1024 * 2);
|
||||
|
||||
public Producer(String clientID, int start, int len) {
|
||||
m_clientID = clientID;
|
||||
m_starIndex = start;
|
||||
m_len = len;
|
||||
m_benchMarkOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(m_baos)));
|
||||
m_benchMarkOut.println("msg ID, ns");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
m_startMillis = System.currentTimeMillis();
|
||||
MQTT mqtt = new MQTT();
|
||||
try {
|
||||
// mqtt.setHost("test.mosquitto.org", 1883);
|
||||
mqtt.setHost("localhost", 1883);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.error(null, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
mqtt.setClientId(m_clientID);
|
||||
BlockingConnection connection = mqtt.blockingConnection();
|
||||
try {
|
||||
connection.connect();
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't CONNECT to the server", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
long time = System.currentTimeMillis() - m_startMillis;
|
||||
LOG.info(String.format("Producer %s connected in %d ms", Thread.currentThread().getName(), time));
|
||||
|
||||
LOG.info("Starting from index " + m_starIndex + " up to " + (m_starIndex + m_len));
|
||||
m_startMillis = System.currentTimeMillis();
|
||||
for (int i = m_starIndex; i < m_starIndex + m_len; i++) {
|
||||
try {
|
||||
// LOG.info("Publishing");
|
||||
String payload = "Hello world MQTT!!" + i;
|
||||
connection.publish("/topic", payload.getBytes(), QoS.AT_MOST_ONCE, false);
|
||||
m_benchMarkOut.println(String.format("%d, %d", i, System.nanoTime()));
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't PUBLISH to the server", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
time = System.currentTimeMillis() - m_startMillis;
|
||||
LOG.info(String.format("Producer %s published %d messages in %d ms", Thread.currentThread().getName(), m_len, time));
|
||||
|
||||
m_startMillis = System.currentTimeMillis();
|
||||
try {
|
||||
LOG.info("Disconneting");
|
||||
connection.disconnect();
|
||||
LOG.info("Disconnected");
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Cant't DISCONNECT to the server", ex);
|
||||
}
|
||||
|
||||
time = System.currentTimeMillis() - m_startMillis;
|
||||
LOG.info(String.format("Producer %s disconnected in %d ms", Thread.currentThread().getName(), time));
|
||||
|
||||
m_benchMarkOut.flush();
|
||||
m_benchMarkOut.close();
|
||||
|
||||
try {
|
||||
FileOutputStream fw = new FileOutputStream(String.format(BENCHMARK_FILE, m_clientID));
|
||||
fw.write(m_baos.toByteArray());
|
||||
fw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark.mina;
|
||||
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class DummyClientHandler extends IoHandlerAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DummyClientHandler.class);
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session, Object message) throws Exception {
|
||||
AbstractMessage msg = (AbstractMessage) message;
|
||||
LOG.debug("Received a message of type " + msg.getMessageType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark.mina;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.apache.mina.core.RuntimeIoException;
|
||||
import org.apache.mina.core.future.ConnectFuture;
|
||||
import org.apache.mina.core.future.WriteFuture;
|
||||
import org.apache.mina.core.service.IoConnector;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.codec.demux.DemuxingProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.demux.DemuxingProtocolEncoder;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketConnector;
|
||||
import org.dna.mqtt.commons.Constants;
|
||||
import org.dna.mqtt.moquette.MQTTException;
|
||||
import org.dna.mqtt.moquette.PublishException;
|
||||
import org.dna.mqtt.moquette.proto.*;
|
||||
import org.dna.mqtt.moquette.proto.messages.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class MQTTBulkClient {
|
||||
public int NUM_MESSAGES = 10000;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MQTTBulkClient.class);
|
||||
|
||||
private String m_hostname;
|
||||
private int m_port = 1883;
|
||||
//internal management used for conversation with the server
|
||||
private IoConnector m_connector;
|
||||
private IoSession m_session;
|
||||
boolean m_withWaitWriteFuture = false;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
MQTTBulkClient client = new MQTTBulkClient();
|
||||
if (args.length > 0) {
|
||||
client.m_hostname = args[0];
|
||||
client.m_withWaitWriteFuture = Boolean.parseBoolean(args[1]);
|
||||
client.NUM_MESSAGES = Integer.parseInt(args[2]);
|
||||
} else {
|
||||
client.m_hostname = "localhost";
|
||||
}
|
||||
client.init();
|
||||
client.connect();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < client.NUM_MESSAGES; i++) {
|
||||
client.publish("/topic", "Hello world".getBytes(), AbstractMessage.QOSType.MOST_ONE, false);
|
||||
}
|
||||
long stop = System.currentTimeMillis();
|
||||
LOG.info("Client sent " + client.NUM_MESSAGES + " in " + (stop - start) + " ms");
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
DemuxingProtocolDecoder decoder = new DemuxingProtocolDecoder();
|
||||
decoder.addMessageDecoder(new ConnAckDecoder());
|
||||
decoder.addMessageDecoder(new SubAckDecoder());
|
||||
decoder.addMessageDecoder(new UnsubAckDecoder());
|
||||
decoder.addMessageDecoder(new PublishDecoder());
|
||||
decoder.addMessageDecoder(new PubAckDecoder());
|
||||
decoder.addMessageDecoder(new PingRespDecoder());
|
||||
|
||||
DemuxingProtocolEncoder encoder = new DemuxingProtocolEncoder();
|
||||
encoder.addMessageEncoder(ConnectMessage.class, new ConnectEncoder());
|
||||
encoder.addMessageEncoder(PublishMessage.class, new PublishEncoder());
|
||||
encoder.addMessageEncoder(SubscribeMessage.class, new SubscribeEncoder());
|
||||
encoder.addMessageEncoder(UnsubscribeMessage.class, new UnsubscribeEncoder());
|
||||
encoder.addMessageEncoder(DisconnectMessage.class, new DisconnectEncoder());
|
||||
encoder.addMessageEncoder(PingReqMessage.class, new PingReqEncoder());
|
||||
|
||||
m_connector = new NioSocketConnector();
|
||||
|
||||
// m_connector.getFilterChain().addLast("logger", new LoggingFilter());
|
||||
m_connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(encoder, decoder));
|
||||
|
||||
m_connector.setHandler(new DummyClientHandler());
|
||||
m_connector.getSessionConfig().setReadBufferSize(2048);
|
||||
m_connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, Constants.DEFAULT_CONNECT_TIMEOUT);
|
||||
}
|
||||
|
||||
public void connect() throws MQTTException {
|
||||
try {
|
||||
ConnectFuture future = m_connector.connect(new InetSocketAddress(m_hostname, m_port));
|
||||
LOG.debug("Client waiting to connect to server");
|
||||
future.awaitUninterruptibly();
|
||||
m_session = future.getSession();
|
||||
} catch (RuntimeIoException e) {
|
||||
LOG.debug("Failed to connect", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void publish(String topic, byte[] payload, AbstractMessage.QOSType qos, boolean retain) throws PublishException {
|
||||
PublishMessage msg = new PublishMessage();
|
||||
msg.setRetainFlag(retain);
|
||||
msg.setTopicName(topic);
|
||||
msg.setPayload(payload);
|
||||
|
||||
//QoS 0 case
|
||||
msg.setQos(AbstractMessage.QOSType.MOST_ONE);
|
||||
WriteFuture wf = m_session.write(msg);
|
||||
|
||||
if (m_withWaitWriteFuture) {
|
||||
try {
|
||||
wf.await();
|
||||
} catch (InterruptedException ex) {
|
||||
LOG.debug(null, ex);
|
||||
throw new PublishException(ex);
|
||||
}
|
||||
|
||||
Throwable ex = wf.getException();
|
||||
if (ex != null) {
|
||||
throw new PublishException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
m_connector.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark.mina;
|
||||
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.dna.mqtt.moquette.proto.messages.AbstractMessage.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class MQTTDropHandler extends IoHandlerAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MQTTDropHandler.class);
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session, Object message) throws Exception {
|
||||
AbstractMessage msg = (AbstractMessage) message;
|
||||
|
||||
try {
|
||||
switch (msg.getMessageType()) {
|
||||
case CONNECT:
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
case PUBLISH:
|
||||
case PINGREQ:
|
||||
case DISCONNECT:
|
||||
LOG.debug("Received a message of type " + msg.getMessageType());
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Bad error in processing the message", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionIdle(IoSession session, IdleStatus status) {
|
||||
session.close(false);
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package org.dna.mqtt.bechnmark.mina;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.apache.mina.core.service.IoAcceptor;
|
||||
import org.apache.mina.core.service.IoServiceStatistics;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.codec.demux.DemuxingProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.demux.DemuxingProtocolEncoder;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
||||
import org.dna.mqtt.moquette.proto.*;
|
||||
import org.dna.mqtt.moquette.proto.messages.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class MQTTDropServer {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MQTTDropServer.class);
|
||||
|
||||
public static final int PORT = 1883;
|
||||
public static final int DEFAULT_CONNECT_TIMEOUT = 10;
|
||||
private IoAcceptor m_acceptor;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new MQTTDropServer().startServer();
|
||||
}
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
DemuxingProtocolDecoder decoder = new DemuxingProtocolDecoder();
|
||||
decoder.addMessageDecoder(new ConnectDecoder());
|
||||
decoder.addMessageDecoder(new PublishDecoder());
|
||||
decoder.addMessageDecoder(new SubscribeDecoder());
|
||||
decoder.addMessageDecoder(new UnsubscribeDecoder());
|
||||
decoder.addMessageDecoder(new DisconnectDecoder());
|
||||
decoder.addMessageDecoder(new PingReqDecoder());
|
||||
|
||||
DemuxingProtocolEncoder encoder = new DemuxingProtocolEncoder();
|
||||
// encoder.addMessageEncoder(ConnectMessage.class, new ConnectEncoder());
|
||||
encoder.addMessageEncoder(ConnAckMessage.class, new ConnAckEncoder());
|
||||
encoder.addMessageEncoder(SubAckMessage.class, new SubAckEncoder());
|
||||
encoder.addMessageEncoder(UnsubAckMessage.class, new UnsubAckEncoder());
|
||||
encoder.addMessageEncoder(PubAckMessage.class, new PubAckEncoder());
|
||||
encoder.addMessageEncoder(PublishMessage.class, new PublishEncoder());
|
||||
encoder.addMessageEncoder(PingRespMessage.class, new PingRespEncoder());
|
||||
|
||||
m_acceptor = new NioSocketAcceptor();
|
||||
|
||||
m_acceptor.getFilterChain().addLast( "logger", new MQTTLoggingFilter("SERVER LOG") );
|
||||
m_acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(encoder, decoder));
|
||||
|
||||
MQTTDropHandler handler = new MQTTDropHandler();
|
||||
|
||||
m_acceptor.setHandler(handler);
|
||||
((NioSocketAcceptor)m_acceptor).setReuseAddress(true);
|
||||
((NioSocketAcceptor)m_acceptor).getSessionConfig().setReuseAddress(true);
|
||||
m_acceptor.getSessionConfig().setReadBufferSize( 2048 );
|
||||
m_acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, DEFAULT_CONNECT_TIMEOUT );
|
||||
m_acceptor.getStatistics().setThroughputCalculationInterval(10);
|
||||
m_acceptor.getStatistics().updateThroughput(System.currentTimeMillis());
|
||||
m_acceptor.bind( new InetSocketAddress(PORT) );
|
||||
LOG.info("Server binded");
|
||||
|
||||
//Bind a shutdown hook
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
stopServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void stopServer() {
|
||||
LOG.info("Server stopping...");
|
||||
|
||||
//log statistics
|
||||
IoServiceStatistics statistics = m_acceptor.getStatistics();
|
||||
statistics.updateThroughput(System.currentTimeMillis());
|
||||
System.out.println(String.format("Total read bytes: %d, read throughtput: %f (b/s)", statistics.getReadBytes(), statistics.getReadBytesThroughput()));
|
||||
System.out.println(String.format("Total read msgs: %d, read msg throughtput: %f (msg/s)", statistics.getReadMessages(), statistics.getReadMessagesThroughput()));
|
||||
|
||||
for(IoSession session: m_acceptor.getManagedSessions().values()) {
|
||||
if(session.isConnected() && !session.isClosing()){
|
||||
session.close(false);
|
||||
}
|
||||
}
|
||||
|
||||
m_acceptor.unbind();
|
||||
m_acceptor.dispose();
|
||||
LOG.info("Server stopped");
|
||||
}
|
||||
}
|
||||
+1
-7
@@ -22,7 +22,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.dna.mqtt</groupId>
|
||||
<artifactId>moquette-mina-parser</artifactId>
|
||||
<artifactId>moquette-parser-commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -31,12 +31,6 @@
|
||||
<artifactId>moquette-netty-parser</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>${mina-version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.googlecode.disruptor</groupId>
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.dna.mqtt.moquette.server;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.dna.mqtt.moquette.messaging.spi.impl.SimpleMessaging;
|
||||
import org.dna.mqtt.moquette.server.mina.MinaAcceptor;
|
||||
//import org.dna.mqtt.moquette.server.mina.MinaAcceptor;
|
||||
import org.dna.mqtt.moquette.server.netty.NettyAcceptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -17,27 +17,14 @@ public class Server {
|
||||
|
||||
public static final String STORAGE_FILE_PATH = System.getProperty("user.home") +
|
||||
File.separator + "moquette_store.hawtdb";
|
||||
public static String NETTY_NIO_FRAMEWORK = "netty";
|
||||
public static String MINA_NIO_FRAMEWORK = "mina";
|
||||
public static String DEFAULT_NIO_FRAMEWORK = NETTY_NIO_FRAMEWORK;
|
||||
|
||||
private ServerAcceptor m_acceptor;
|
||||
SimpleMessaging messaging;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
String nioFrameworkType = DEFAULT_NIO_FRAMEWORK;
|
||||
if (args.length > 0) {
|
||||
//TODO check the typing and in case print usge message
|
||||
nioFrameworkType = args[1];
|
||||
if (!(nioFrameworkType.equals(DEFAULT_NIO_FRAMEWORK) ||
|
||||
nioFrameworkType.equals(DEFAULT_NIO_FRAMEWORK))) {
|
||||
printUsage(nioFrameworkType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Server server = new Server();
|
||||
server.startServer(nioFrameworkType);
|
||||
server.startServer();
|
||||
//Bind a shutdown hook
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
@@ -49,19 +36,10 @@ public class Server {
|
||||
}
|
||||
|
||||
public void startServer() throws IOException {
|
||||
startServer(DEFAULT_NIO_FRAMEWORK);
|
||||
}
|
||||
|
||||
public void startServer(String nioFrameworkType) throws IOException {
|
||||
System.out.println("Starting server with " + nioFrameworkType + " connectors");
|
||||
messaging = SimpleMessaging.getInstance();
|
||||
messaging.init();
|
||||
|
||||
if (nioFrameworkType.equals(MINA_NIO_FRAMEWORK)) {
|
||||
m_acceptor = new MinaAcceptor();
|
||||
} else if (nioFrameworkType.equals(NETTY_NIO_FRAMEWORK)) {
|
||||
m_acceptor = new NettyAcceptor();
|
||||
}
|
||||
m_acceptor = new NettyAcceptor();
|
||||
m_acceptor.initialize(messaging);
|
||||
}
|
||||
|
||||
@@ -71,12 +49,4 @@ public class Server {
|
||||
m_acceptor.close();
|
||||
System.out.println("Server stopped");
|
||||
}
|
||||
|
||||
|
||||
private static void printUsage(String nioFrameworkType) {
|
||||
System.out.println("The broker should be invoked with the following command line: \n");
|
||||
System.out.println("> java -jar <broker.jar> [mina|netty]\n");
|
||||
System.out.println("while was invoked with type: " + nioFrameworkType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
package org.dna.mqtt.moquette.server.mina;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.apache.mina.core.service.IoAcceptor;
|
||||
import org.apache.mina.core.service.IoServiceStatistics;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.codec.demux.DemuxingProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.demux.DemuxingProtocolEncoder;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
||||
import org.dna.mqtt.commons.Constants;
|
||||
import org.dna.mqtt.moquette.messaging.spi.IMessaging;
|
||||
import org.dna.mqtt.moquette.proto.ConnAckEncoder;
|
||||
import org.dna.mqtt.moquette.proto.ConnectDecoder;
|
||||
import org.dna.mqtt.moquette.proto.DisconnectDecoder;
|
||||
import org.dna.mqtt.moquette.proto.MQTTLoggingFilter;
|
||||
import org.dna.mqtt.moquette.proto.PingReqDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PingRespEncoder;
|
||||
import org.dna.mqtt.moquette.proto.PubAckDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PubAckEncoder;
|
||||
import org.dna.mqtt.moquette.proto.PubCompDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PubCompEncoder;
|
||||
import org.dna.mqtt.moquette.proto.PubRecDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PubRecEncoder;
|
||||
import org.dna.mqtt.moquette.proto.PubRelDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PubRelEncoder;
|
||||
import org.dna.mqtt.moquette.proto.PublishDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PublishEncoder;
|
||||
import org.dna.mqtt.moquette.proto.SubAckEncoder;
|
||||
import org.dna.mqtt.moquette.proto.SubscribeDecoder;
|
||||
import org.dna.mqtt.moquette.proto.UnsubAckEncoder;
|
||||
import org.dna.mqtt.moquette.proto.UnsubscribeDecoder;
|
||||
import org.dna.mqtt.moquette.proto.messages.ConnAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PingRespMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PubAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PubCompMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PubRecMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PubRelMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.UnsubAckMessage;
|
||||
import org.dna.mqtt.moquette.server.ServerAcceptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class MinaAcceptor implements ServerAcceptor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MinaAcceptor.class);
|
||||
|
||||
private IoAcceptor m_acceptor;
|
||||
|
||||
public void initialize(IMessaging messaging) throws IOException {
|
||||
DemuxingProtocolDecoder decoder = new DemuxingProtocolDecoder();
|
||||
decoder.addMessageDecoder(new ConnectDecoder());
|
||||
decoder.addMessageDecoder(new PublishDecoder());
|
||||
decoder.addMessageDecoder(new PubAckDecoder());
|
||||
decoder.addMessageDecoder(new PubRelDecoder());
|
||||
decoder.addMessageDecoder(new PubRecDecoder());
|
||||
decoder.addMessageDecoder(new PubCompDecoder());
|
||||
decoder.addMessageDecoder(new SubscribeDecoder());
|
||||
decoder.addMessageDecoder(new UnsubscribeDecoder());
|
||||
decoder.addMessageDecoder(new DisconnectDecoder());
|
||||
decoder.addMessageDecoder(new PingReqDecoder());
|
||||
|
||||
DemuxingProtocolEncoder encoder = new DemuxingProtocolEncoder();
|
||||
// encoder.addMessageEncoder(ConnectMessage.class, new ConnectEncoder());
|
||||
encoder.addMessageEncoder(ConnAckMessage.class, new ConnAckEncoder());
|
||||
encoder.addMessageEncoder(SubAckMessage.class, new SubAckEncoder());
|
||||
encoder.addMessageEncoder(UnsubAckMessage.class, new UnsubAckEncoder());
|
||||
encoder.addMessageEncoder(PubAckMessage.class, new PubAckEncoder());
|
||||
encoder.addMessageEncoder(PubRecMessage.class, new PubRecEncoder());
|
||||
encoder.addMessageEncoder(PubCompMessage.class, new PubCompEncoder());
|
||||
encoder.addMessageEncoder(PubRelMessage.class, new PubRelEncoder());
|
||||
encoder.addMessageEncoder(PublishMessage.class, new PublishEncoder());
|
||||
encoder.addMessageEncoder(PingRespMessage.class, new PingRespEncoder());
|
||||
|
||||
m_acceptor = new NioSocketAcceptor();
|
||||
|
||||
m_acceptor.getFilterChain().addLast( "logger", new MQTTLoggingFilter("SERVER LOG") );
|
||||
m_acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(encoder, decoder));
|
||||
|
||||
MinaMQTTHandler handler = new MinaMQTTHandler();
|
||||
|
||||
handler.setMessaging(messaging);
|
||||
|
||||
m_acceptor.setHandler(handler);
|
||||
((NioSocketAcceptor)m_acceptor).setReuseAddress(true);
|
||||
((NioSocketAcceptor)m_acceptor).getSessionConfig().setReuseAddress(true);
|
||||
m_acceptor.getSessionConfig().setReadBufferSize( 2048 );
|
||||
m_acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, Constants.DEFAULT_CONNECT_TIMEOUT );
|
||||
m_acceptor.getStatistics().setThroughputCalculationInterval(10);
|
||||
m_acceptor.getStatistics().updateThroughput(System.currentTimeMillis());
|
||||
m_acceptor.bind( new InetSocketAddress(Constants.PORT) );
|
||||
LOG.info("Server binded");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
//log statistics
|
||||
IoServiceStatistics statistics = m_acceptor.getStatistics();
|
||||
statistics.updateThroughput(System.currentTimeMillis());
|
||||
System.out.println(String.format("Total read bytes: %d, read throughtput: %f (b/s)", statistics.getReadBytes(), statistics.getReadBytesThroughput()));
|
||||
System.out.println(String.format("Total read msgs: %d, read msg throughtput: %f (msg/s)", statistics.getReadMessages(), statistics.getReadMessagesThroughput()));
|
||||
|
||||
for(IoSession session: m_acceptor.getManagedSessions().values()) {
|
||||
if(session.isConnected() && !session.isClosing()){
|
||||
session.close(false);
|
||||
}
|
||||
}
|
||||
|
||||
m_acceptor.unbind();
|
||||
m_acceptor.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.dna.mqtt.moquette.server.mina;
|
||||
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.dna.mqtt.moquette.server.ServerChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class MinaChannel implements ServerChannel {
|
||||
|
||||
private IoSession m_session;
|
||||
|
||||
public MinaChannel(IoSession session) {
|
||||
m_session = session;
|
||||
}
|
||||
|
||||
public Object getAttribute(Object key) {
|
||||
return m_session.getAttribute(key);
|
||||
}
|
||||
|
||||
public void setAttribute(Object key, Object value) {
|
||||
m_session.setAttribute(key, value);
|
||||
}
|
||||
|
||||
public void close(boolean immediately) {
|
||||
m_session.close(immediately);
|
||||
}
|
||||
|
||||
public void write(Object value) {
|
||||
m_session.write(value);
|
||||
}
|
||||
|
||||
public void setIdleTime(int idleTime) {
|
||||
m_session.getConfig().setIdleTime(IdleStatus.READER_IDLE, idleTime);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package org.dna.mqtt.moquette.server.mina;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.dna.mqtt.moquette.messaging.spi.IMessaging;
|
||||
import org.dna.mqtt.moquette.proto.Utils;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
import static org.dna.mqtt.moquette.proto.messages.AbstractMessage.*;
|
||||
import org.dna.mqtt.moquette.proto.messages.PingRespMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* MINA MQTT Handler used to route messages to protocol logic
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class MinaMQTTHandler extends IoHandlerAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MinaMQTTHandler.class);
|
||||
private IMessaging m_messaging;
|
||||
private Map<IoSession, MinaChannel> m_channelMapper = new HashMap<IoSession, MinaChannel>();
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session, Object message) throws Exception {
|
||||
AbstractMessage msg = (AbstractMessage) message;
|
||||
LOG.info(String.format("Received a message of type %s", Utils.msgType2String(msg.getMessageType())));
|
||||
try {
|
||||
switch (msg.getMessageType()) {
|
||||
case CONNECT:
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
case PUBLISH:
|
||||
case PUBREC:
|
||||
case PUBCOMP:
|
||||
case PUBREL:
|
||||
case DISCONNECT:
|
||||
MinaChannel channel;
|
||||
synchronized(m_channelMapper) {
|
||||
if (!m_channelMapper.containsKey(session)) {
|
||||
m_channelMapper.put(session, new MinaChannel(session));
|
||||
}
|
||||
channel = m_channelMapper.get(session);
|
||||
}
|
||||
|
||||
m_messaging.handleProtocolMessage(channel, msg);
|
||||
break;
|
||||
case PINGREQ:
|
||||
PingRespMessage pingResp = new PingRespMessage();
|
||||
session.write(pingResp);
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Bad error in processing the message", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionIdle(IoSession session, IdleStatus status) {
|
||||
if (status == IdleStatus.READER_IDLE) {
|
||||
session.close(false);
|
||||
m_channelMapper.remove(session);
|
||||
//TODO send a notification to messaging part to remove the bining clientID-ConnConfig
|
||||
}
|
||||
}
|
||||
|
||||
public void setMessaging(IMessaging messaging) {
|
||||
m_messaging = messaging;
|
||||
}
|
||||
|
||||
}
|
||||
+232
-235
@@ -1,14 +1,12 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.mina.core.filterchain.IoFilter;
|
||||
import org.apache.mina.core.filterchain.IoFilterAdapter;
|
||||
import org.apache.mina.core.session.DummySession;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.core.write.WriteRequest;
|
||||
//import org.apache.mina.core.filterchain.IoFilter;
|
||||
//import org.apache.mina.core.filterchain.IoFilterAdapter;
|
||||
//import org.apache.mina.core.session.DummySession;
|
||||
//import org.apache.mina.core.session.IoSession;
|
||||
//import org.apache.mina.core.write.WriteRequest;
|
||||
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.subscriptions.Subscription;
|
||||
@@ -20,9 +18,8 @@ import org.dna.mqtt.moquette.proto.messages.ConnectMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage;
|
||||
import org.dna.mqtt.moquette.server.ConnectionDescriptor;
|
||||
import org.dna.mqtt.moquette.server.ServerChannel;
|
||||
import org.dna.mqtt.moquette.server.mina.MinaChannel;
|
||||
//import org.dna.mqtt.moquette.server.mina.MinaChannel;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -34,231 +31,231 @@ import org.junit.Test;
|
||||
* @author andrea
|
||||
*/
|
||||
public class ProtocolProcessorTest {
|
||||
final static String FAKE_CLIENT_ID = "FAKE_123";
|
||||
final static String FAKE_TOPIC = "/news";
|
||||
|
||||
ServerChannel m_session;
|
||||
byte m_returnCode;
|
||||
ConnectMessage connMsg;
|
||||
ProtocolProcessor m_processor;
|
||||
|
||||
IStorageService m_storageService;
|
||||
SubscriptionsStore subscriptions;
|
||||
AbstractMessage m_receivedMessage;
|
||||
|
||||
IoSession m_minaSession;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws InterruptedException {
|
||||
connMsg = new ConnectMessage();
|
||||
connMsg.setProcotolVersion((byte) 0x03);
|
||||
|
||||
m_minaSession = new DummySession();
|
||||
|
||||
m_session = new MinaChannel(m_minaSession);
|
||||
|
||||
m_minaSession.getFilterChain().addFirst("MessageCatcher", new IoFilterAdapter() {
|
||||
|
||||
@Override
|
||||
public void filterWrite(IoFilter.NextFilter nextFilter, IoSession session,
|
||||
WriteRequest writeRequest) throws Exception {
|
||||
try {
|
||||
m_receivedMessage = (AbstractMessage) writeRequest.getMessage();
|
||||
if (m_receivedMessage instanceof ConnAckMessage) {
|
||||
ConnAckMessage buf = (ConnAckMessage) m_receivedMessage;
|
||||
m_returnCode = buf.getReturnCode();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new AssertionError("Wrong return code");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//sleep to let the messaging batch processor to process the initEvent
|
||||
Thread.sleep(300);
|
||||
|
||||
m_storageService = new MemoryStorageService();
|
||||
//m_storageService.initStore();
|
||||
|
||||
subscriptions = new SubscriptionsStore();
|
||||
subscriptions.init(m_storageService);
|
||||
m_processor = new ProtocolProcessor();
|
||||
m_processor.init(subscriptions, m_storageService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleConnect_BadProtocol() {
|
||||
connMsg.setProcotolVersion((byte) 0x02);
|
||||
|
||||
//Exercise
|
||||
m_processor.processConnect(m_session, connMsg);
|
||||
|
||||
//Verify
|
||||
assertEquals(ConnAckMessage.UNNACEPTABLE_PROTOCOL_VERSION, m_returnCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnect_badClientID() {
|
||||
connMsg.setClientID("extremely_long_clientID_greater_than_23");
|
||||
|
||||
//Exercise
|
||||
m_processor.processConnect(m_session, connMsg);
|
||||
|
||||
//Verify
|
||||
assertEquals(ConnAckMessage.IDENTIFIER_REJECTED, m_returnCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWill() {
|
||||
connMsg.setClientID("123");
|
||||
connMsg.setWillFlag(true);
|
||||
connMsg.setWillTopic("topic");
|
||||
connMsg.setWillMessage("Topic message");
|
||||
|
||||
|
||||
//Exercise
|
||||
//m_handler.setMessaging(mockedMessaging);
|
||||
m_processor.processConnect(m_session, connMsg);
|
||||
|
||||
//Verify
|
||||
assertEquals(ConnAckMessage.CONNECTION_ACCEPTED, m_returnCode);
|
||||
//TODO verify the call
|
||||
/*verify(mockedMessaging).publish(eq("topic"), eq("Topic message".getBytes()),
|
||||
any(AbstractMessage.QOSType.class), anyBoolean(), eq("123"), any(IoSession.class));*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublish() throws InterruptedException {
|
||||
final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
|
||||
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, true);
|
||||
|
||||
//subscriptions.matches(topic) redefine the method to return true
|
||||
SubscriptionsStore subs = new SubscriptionsStore() {
|
||||
@Override
|
||||
public List<Subscription> matches(String topic) {
|
||||
if (topic.equals(FAKE_TOPIC)) {
|
||||
return Arrays.asList(subscription);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
//simulate a connect that register a clientID to an IoSession
|
||||
subs.init(m_storageService);
|
||||
m_processor.init(subs, m_storageService);
|
||||
ConnectMessage connectMessage = new ConnectMessage();
|
||||
connectMessage.setProcotolVersion((byte)3);
|
||||
connectMessage.setClientID(FAKE_CLIENT_ID);
|
||||
connectMessage.setCleanSession(subscription.isCleanSession());
|
||||
m_processor.processConnect(m_session, connectMessage);
|
||||
|
||||
|
||||
//Exercise
|
||||
PublishEvent pubEvt = new PublishEvent(FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, "Hello".getBytes(), false, "FakeCLI", null);
|
||||
m_processor.processPublish(pubEvt);
|
||||
|
||||
//Verify
|
||||
assertNotNull(m_receivedMessage);
|
||||
//TODO check received message attributes
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribe() {
|
||||
//Exercise
|
||||
SubscribeMessage msg = new SubscribeMessage();
|
||||
msg.addSubscription(new SubscribeMessage.Couple((byte)AbstractMessage.QOSType.MOST_ONE.ordinal(), FAKE_TOPIC));
|
||||
m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
|
||||
//Verify
|
||||
assertTrue(m_receivedMessage instanceof SubAckMessage);
|
||||
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, false);
|
||||
assertTrue(subscriptions.contains(expectedSubscription));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleSubscribe() {
|
||||
SubscribeMessage msg = new SubscribeMessage();
|
||||
msg.addSubscription(new SubscribeMessage.Couple((byte)AbstractMessage.QOSType.MOST_ONE.ordinal(), FAKE_TOPIC));
|
||||
|
||||
subscriptions.clearAllSubscriptions();
|
||||
assertEquals(0, subscriptions.size());
|
||||
|
||||
m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
|
||||
//Exercise
|
||||
m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
|
||||
//Verify
|
||||
assertEquals(1, subscriptions.size());
|
||||
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, false);
|
||||
assertTrue(subscriptions.contains(expectedSubscription));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
|
||||
m_minaSession.getFilterChain().remove("MessageCatcher");
|
||||
m_minaSession.getFilterChain().addFirst("MessageCatcher", new IoFilterAdapter() {
|
||||
|
||||
@Override
|
||||
public void filterWrite(IoFilter.NextFilter nextFilter, IoSession session,
|
||||
WriteRequest writeRequest) throws Exception {
|
||||
try {
|
||||
System.out.println("filterReceived class " + writeRequest.getMessage().getClass().getName());
|
||||
if (writeRequest.getMessage() instanceof PublishMessage) {
|
||||
m_receivedMessage = (AbstractMessage) writeRequest.getMessage();
|
||||
}
|
||||
|
||||
if (m_receivedMessage instanceof ConnAckMessage) {
|
||||
ConnAckMessage buf = (ConnAckMessage) m_receivedMessage;
|
||||
m_returnCode = buf.getReturnCode();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new AssertionError("Wrong return code");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// final static String FAKE_CLIENT_ID = "FAKE_123";
|
||||
// final static String FAKE_TOPIC = "/news";
|
||||
//
|
||||
// ServerChannel m_session;
|
||||
// byte m_returnCode;
|
||||
// ConnectMessage connMsg;
|
||||
// ProtocolProcessor m_processor;
|
||||
//
|
||||
// IStorageService m_storageService;
|
||||
// SubscriptionsStore subscriptions;
|
||||
// AbstractMessage m_receivedMessage;
|
||||
//
|
||||
// IoSession m_minaSession;
|
||||
//
|
||||
//
|
||||
// @Before
|
||||
// public void setUp() throws InterruptedException {
|
||||
// connMsg = new ConnectMessage();
|
||||
// connMsg.setProcotolVersion((byte) 0x03);
|
||||
//
|
||||
// m_minaSession = new DummySession();
|
||||
//
|
||||
// m_session = new MinaChannel(m_minaSession);
|
||||
//
|
||||
// m_minaSession.getFilterChain().addFirst("MessageCatcher", new IoFilterAdapter() {
|
||||
//
|
||||
// @Override
|
||||
// public void filterWrite(IoFilter.NextFilter nextFilter, IoSession session,
|
||||
// WriteRequest writeRequest) throws Exception {
|
||||
// try {
|
||||
// m_receivedMessage = (AbstractMessage) writeRequest.getMessage();
|
||||
// if (m_receivedMessage instanceof ConnAckMessage) {
|
||||
// ConnAckMessage buf = (ConnAckMessage) m_receivedMessage;
|
||||
// m_returnCode = buf.getReturnCode();
|
||||
// }
|
||||
// } catch (Exception ex) {
|
||||
// throw new AssertionError("Wrong return code");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// //sleep to let the messaging batch processor to process the initEvent
|
||||
// Thread.sleep(300);
|
||||
//
|
||||
// m_storageService = new MemoryStorageService();
|
||||
// //m_storageService.initStore();
|
||||
//
|
||||
// subscriptions = new SubscriptionsStore();
|
||||
// subscriptions.init(m_storageService);
|
||||
// m_processor = new ProtocolProcessor();
|
||||
// m_processor.init(subscriptions, m_storageService);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testHandleConnect_BadProtocol() {
|
||||
// connMsg.setProcotolVersion((byte) 0x02);
|
||||
//
|
||||
// //Exercise
|
||||
// m_processor.processConnect(m_session, connMsg);
|
||||
//
|
||||
// //Verify
|
||||
// assertEquals(ConnAckMessage.UNNACEPTABLE_PROTOCOL_VERSION, m_returnCode);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testConnect_badClientID() {
|
||||
// connMsg.setClientID("extremely_long_clientID_greater_than_23");
|
||||
//
|
||||
// //Exercise
|
||||
// m_processor.processConnect(m_session, connMsg);
|
||||
//
|
||||
// //Verify
|
||||
// assertEquals(ConnAckMessage.IDENTIFIER_REJECTED, m_returnCode);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testWill() {
|
||||
// connMsg.setClientID("123");
|
||||
// connMsg.setWillFlag(true);
|
||||
// connMsg.setWillTopic("topic");
|
||||
// connMsg.setWillMessage("Topic message");
|
||||
//
|
||||
//
|
||||
// //Exercise
|
||||
// //m_handler.setMessaging(mockedMessaging);
|
||||
// m_processor.processConnect(m_session, connMsg);
|
||||
//
|
||||
// //Verify
|
||||
// assertEquals(ConnAckMessage.CONNECTION_ACCEPTED, m_returnCode);
|
||||
// //TODO verify the call
|
||||
// /*verify(mockedMessaging).publish(eq("topic"), eq("Topic message".getBytes()),
|
||||
// any(AbstractMessage.QOSType.class), anyBoolean(), eq("123"), any(IoSession.class));*/
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testPublish() throws InterruptedException {
|
||||
// final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
|
||||
// FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, true);
|
||||
//
|
||||
// //subscriptions.matches(topic) redefine the method to return true
|
||||
// SubscriptionsStore subs = new SubscriptionsStore() {
|
||||
// @Override
|
||||
// public List<Subscription> matches(String topic) {
|
||||
// if (topic.equals(FAKE_TOPIC)) {
|
||||
// return Arrays.asList(subscription);
|
||||
// } else {
|
||||
// throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// };
|
||||
//
|
||||
// //simulate a connect that register a clientID to an IoSession
|
||||
final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
|
||||
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, true);
|
||||
|
||||
//subscriptions.matches(topic) redefine the method to return true
|
||||
SubscriptionsStore subs = new SubscriptionsStore() {
|
||||
@Override
|
||||
public List<Subscription> matches(String topic) {
|
||||
if (topic.equals(FAKE_TOPIC)) {
|
||||
return Arrays.asList(subscription);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
||||
}
|
||||
}
|
||||
};
|
||||
subs.init(new MemoryStorageService());
|
||||
|
||||
//simulate a connect that register a clientID to an IoSession
|
||||
m_processor.init(subs, m_storageService);
|
||||
ConnectMessage connectMessage = new ConnectMessage();
|
||||
connectMessage.setClientID(FAKE_CLIENT_ID);
|
||||
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);
|
||||
m_processor.processPublish(pubEvt);
|
||||
|
||||
//Exercise
|
||||
SubscribeMessage msg = new SubscribeMessage();
|
||||
msg.addSubscription(new SubscribeMessage.Couple((byte)QOSType.MOST_ONE.ordinal(), "#"));
|
||||
m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
|
||||
//Verify
|
||||
assertNotNull(m_receivedMessage);
|
||||
assertTrue(m_receivedMessage instanceof PublishMessage);
|
||||
PublishMessage pubMessage = (PublishMessage) m_receivedMessage;
|
||||
assertEquals(FAKE_TOPIC, pubMessage.getTopicName());
|
||||
}
|
||||
// subs.init(m_storageService);
|
||||
// m_processor.init(subs, m_storageService);
|
||||
// ConnectMessage connectMessage = new ConnectMessage();
|
||||
// connectMessage.setProcotolVersion((byte)3);
|
||||
// connectMessage.setClientID(FAKE_CLIENT_ID);
|
||||
// connectMessage.setCleanSession(subscription.isCleanSession());
|
||||
// m_processor.processConnect(m_session, connectMessage);
|
||||
//
|
||||
//
|
||||
// //Exercise
|
||||
// PublishEvent pubEvt = new PublishEvent(FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, "Hello".getBytes(), false, "FakeCLI", null);
|
||||
// m_processor.processPublish(pubEvt);
|
||||
//
|
||||
// //Verify
|
||||
// assertNotNull(m_receivedMessage);
|
||||
// //TODO check received message attributes
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testSubscribe() {
|
||||
// //Exercise
|
||||
// SubscribeMessage msg = new SubscribeMessage();
|
||||
// msg.addSubscription(new SubscribeMessage.Couple((byte)AbstractMessage.QOSType.MOST_ONE.ordinal(), FAKE_TOPIC));
|
||||
// m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
//
|
||||
// //Verify
|
||||
// assertTrue(m_receivedMessage instanceof SubAckMessage);
|
||||
// Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, false);
|
||||
// assertTrue(subscriptions.contains(expectedSubscription));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testDoubleSubscribe() {
|
||||
// SubscribeMessage msg = new SubscribeMessage();
|
||||
// msg.addSubscription(new SubscribeMessage.Couple((byte)AbstractMessage.QOSType.MOST_ONE.ordinal(), FAKE_TOPIC));
|
||||
//
|
||||
// subscriptions.clearAllSubscriptions();
|
||||
// assertEquals(0, subscriptions.size());
|
||||
//
|
||||
// m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
//
|
||||
// //Exercise
|
||||
// m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
//
|
||||
// //Verify
|
||||
// assertEquals(1, subscriptions.size());
|
||||
// Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, false);
|
||||
// assertTrue(subscriptions.contains(expectedSubscription));
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Test
|
||||
// public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
|
||||
// m_minaSession.getFilterChain().remove("MessageCatcher");
|
||||
// m_minaSession.getFilterChain().addFirst("MessageCatcher", new IoFilterAdapter() {
|
||||
//
|
||||
// @Override
|
||||
// public void filterWrite(IoFilter.NextFilter nextFilter, IoSession session,
|
||||
// WriteRequest writeRequest) throws Exception {
|
||||
// try {
|
||||
// System.out.println("filterReceived class " + writeRequest.getMessage().getClass().getName());
|
||||
// if (writeRequest.getMessage() instanceof PublishMessage) {
|
||||
// m_receivedMessage = (AbstractMessage) writeRequest.getMessage();
|
||||
// }
|
||||
//
|
||||
// if (m_receivedMessage instanceof ConnAckMessage) {
|
||||
// ConnAckMessage buf = (ConnAckMessage) m_receivedMessage;
|
||||
// m_returnCode = buf.getReturnCode();
|
||||
// }
|
||||
// } catch (Exception ex) {
|
||||
// throw new AssertionError("Wrong return code");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
//// //simulate a connect that register a clientID to an IoSession
|
||||
// final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
|
||||
// FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE, true);
|
||||
//
|
||||
// //subscriptions.matches(topic) redefine the method to return true
|
||||
// SubscriptionsStore subs = new SubscriptionsStore() {
|
||||
// @Override
|
||||
// public List<Subscription> matches(String topic) {
|
||||
// if (topic.equals(FAKE_TOPIC)) {
|
||||
// return Arrays.asList(subscription);
|
||||
// } else {
|
||||
// throw new IllegalArgumentException("Expected " + FAKE_TOPIC + " buf found " + topic);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// subs.init(new MemoryStorageService());
|
||||
//
|
||||
// //simulate a connect that register a clientID to an IoSession
|
||||
// m_processor.init(subs, m_storageService);
|
||||
// ConnectMessage connectMessage = new ConnectMessage();
|
||||
// connectMessage.setClientID(FAKE_CLIENT_ID);
|
||||
// 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);
|
||||
// m_processor.processPublish(pubEvt);
|
||||
//
|
||||
// //Exercise
|
||||
// SubscribeMessage msg = new SubscribeMessage();
|
||||
// msg.addSubscription(new SubscribeMessage.Couple((byte)QOSType.MOST_ONE.ordinal(), "#"));
|
||||
// m_processor.processSubscribe(m_session, msg, FAKE_CLIENT_ID, false);
|
||||
//
|
||||
// //Verify
|
||||
// assertNotNull(m_receivedMessage);
|
||||
// assertTrue(m_receivedMessage instanceof PublishMessage);
|
||||
// PublishMessage pubMessage = (PublishMessage) m_receivedMessage;
|
||||
// assertEquals(FAKE_TOPIC, pubMessage.getTopicName());
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,191 +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.MessageDecoderResult;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Common utils methodd used in codecs.
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
public static final int MAX_LENGTH_LIMIT = 268435455;
|
||||
|
||||
/**
|
||||
* Read 2 bytes from in buffer first MSB, and then LSB returning as int.
|
||||
*/
|
||||
static int readWord(IoBuffer in) {
|
||||
int msb = in.get() & 0x00FF; //remove sign extension due to casting
|
||||
int lsb = in.get() & 0x00FF;
|
||||
msb = (msb << 8) | lsb ;
|
||||
return msb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes as 2 bytes the int value into buffer first MSB, and then LSB.
|
||||
*/
|
||||
static void writeWord(IoBuffer out, int value) {
|
||||
out.put((byte) ((value & 0xFF00) >> 8)); //msb
|
||||
out.put((byte) (value & 0x00FF)); //lsb
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the variable remaining lenght as defined in MQTT v3.1 specification
|
||||
* (section 2.1).
|
||||
*
|
||||
* @return the decoded length or -1 if needed more data to decode the length field.
|
||||
*/
|
||||
static int decodeRemainingLenght(IoBuffer in) {
|
||||
int multiplier = 1;
|
||||
int value = 0;
|
||||
byte digit;
|
||||
do {
|
||||
if (in.remaining() < 1) {
|
||||
return -1;
|
||||
}
|
||||
digit = in.get();
|
||||
value += (digit & 0x7F) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((digit & 0x80) != 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes to encode the gicen remaining length value
|
||||
*/
|
||||
static int numBytesToEncode(int len) {
|
||||
if (0 <= len && len <= 127) return 1;
|
||||
if (128 <= len && len <= 16383) return 2;
|
||||
if (16384 <= len && len <= 2097151) return 3;
|
||||
if (2097152 <= len && len <= 268435455) return 4;
|
||||
throw new IllegalArgumentException("value shoul be in the range [0..268435455]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the value in the format defined in specification as variable length
|
||||
* array.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not in the specification bounds
|
||||
* [0..268435455].
|
||||
*/
|
||||
static IoBuffer encodeRemainingLength(int value) throws IllegalAccessException {
|
||||
if (value > MAX_LENGTH_LIMIT || value < 0) {
|
||||
throw new IllegalAccessException("Value should in range 0.." + MAX_LENGTH_LIMIT + " found " + value);
|
||||
}
|
||||
|
||||
IoBuffer encoded = IoBuffer.allocate(4);
|
||||
byte digit;
|
||||
do {
|
||||
digit = (byte) (value % 128);
|
||||
value = value / 128;
|
||||
// if there are more digits to encode, set the top bit of this digit
|
||||
if (value > 0) {
|
||||
digit = (byte) (digit | 0x80);
|
||||
}
|
||||
encoded.put(digit);
|
||||
} while (value > 0);
|
||||
encoded.flip();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
static MessageDecoderResult checkDecodable(byte type, IoBuffer in) {
|
||||
if (in.remaining() < 1) {
|
||||
return MessageDecoderResult.NEED_DATA;
|
||||
}
|
||||
byte h1 = in.get();
|
||||
byte messageType = (byte) ((h1 & 0x00F0) >> 4);
|
||||
|
||||
int remainingLength = Utils.decodeRemainingLenght(in);
|
||||
if (remainingLength == -1) {
|
||||
return MessageDecoderResult.NEED_DATA;
|
||||
}
|
||||
|
||||
//check remaining length
|
||||
if (in.remaining() < remainingLength) {
|
||||
return MessageDecoderResult.NEED_DATA;
|
||||
}
|
||||
|
||||
return messageType == type ? MessageDecoderResult.OK : MessageDecoderResult.NOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IoBuffer with string encoded as MSB, LSB and UTF-8 encoded
|
||||
* string content.
|
||||
*/
|
||||
static IoBuffer encodeString(String str) {
|
||||
IoBuffer out = IoBuffer.allocate(2).setAutoExpand(true);
|
||||
byte[] raw;
|
||||
try {
|
||||
raw = str.getBytes("UTF-8");
|
||||
//NB every Java platform has got UTF-8 encoding by default, so this
|
||||
//exception are never raised.
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
LoggerFactory.getLogger(ConnectEncoder.class).error(null, ex);
|
||||
return null;
|
||||
}
|
||||
Utils.writeWord(out, raw.length);
|
||||
out.put(raw).flip();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a string from the given buffer, reading first the two bytes of len
|
||||
* and then the UTF-8 bytes of the string.
|
||||
*
|
||||
* @return the decoded string or null if NEED_DATA
|
||||
*/
|
||||
static String decodeString(IoBuffer in) throws UnsupportedEncodingException {
|
||||
if (in.remaining() < 2) {
|
||||
return null;
|
||||
}
|
||||
int strLen = Utils.readWord(in);
|
||||
if (in.remaining() < strLen) {
|
||||
return null;
|
||||
}
|
||||
byte[] strRaw = new byte[strLen];
|
||||
in.get(strRaw);
|
||||
|
||||
return new String(strRaw, "UTF-8");
|
||||
}
|
||||
|
||||
static byte encodeFlags(AbstractMessage message) {
|
||||
byte flags = 0;
|
||||
if (message.isDupFlag()) {
|
||||
flags |= 0x08;
|
||||
}
|
||||
if (message.isRetainFlag()) {
|
||||
flags |= 0x01;
|
||||
}
|
||||
|
||||
flags |= ((message.getQos().ordinal() & 0x03) << 1);
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts MQTT message type to a textual description.
|
||||
* */
|
||||
public static String msgType2String(int type) {
|
||||
switch (type) {
|
||||
case AbstractMessage.CONNECT: return "CONNECT";
|
||||
case AbstractMessage.CONNACK: return "CONNACK";
|
||||
case AbstractMessage.PUBLISH: return "PUBLISH";
|
||||
case AbstractMessage.PUBACK: return "PUBACK";
|
||||
case AbstractMessage.PUBREC: return "PUBREC";
|
||||
case AbstractMessage.PUBREL: return "PUBREL";
|
||||
case AbstractMessage.PUBCOMP: return "PUBCOMP";
|
||||
case AbstractMessage.SUBSCRIBE: return "SUBSCRIBE";
|
||||
case AbstractMessage.SUBACK: return "SUBACK";
|
||||
case AbstractMessage.UNSUBSCRIBE: return "UNSUBSCRIBE";
|
||||
case AbstractMessage.UNSUBACK: return "UNSUBACK";
|
||||
case AbstractMessage.PINGREQ: return "PINGREQ";
|
||||
case AbstractMessage.PINGRESP: return "PINGRESP";
|
||||
case AbstractMessage.DISCONNECT: return "DISCONNECT";
|
||||
default: throw new RuntimeException("Can't decode message type " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package org.dna.mqtt.commons;
|
||||
|
||||
/**
|
||||
* Contains some usefull constants.
|
||||
* Contains some useful constants.
|
||||
*/
|
||||
public class Constants {
|
||||
public static final int PORT = 1883;
|
||||
@@ -0,0 +1,191 @@
|
||||
package org.dna.mqtt.moquette.proto;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
//import org.apache.mina.core.buffer.IoBuffer;
|
||||
//import org.apache.mina.filter.codec.demux.MessageDecoderResult;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Common utils methodd used in codecs.
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
public static final int MAX_LENGTH_LIMIT = 268435455;
|
||||
|
||||
// /**
|
||||
// * Read 2 bytes from in buffer first MSB, and then LSB returning as int.
|
||||
// */
|
||||
// static int readWord(IoBuffer in) {
|
||||
// int msb = in.get() & 0x00FF; //remove sign extension due to casting
|
||||
// int lsb = in.get() & 0x00FF;
|
||||
// msb = (msb << 8) | lsb ;
|
||||
// return msb;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Writes as 2 bytes the int value into buffer first MSB, and then LSB.
|
||||
// */
|
||||
// static void writeWord(IoBuffer out, int value) {
|
||||
// out.put((byte) ((value & 0xFF00) >> 8)); //msb
|
||||
// out.put((byte) (value & 0x00FF)); //lsb
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Decode the variable remaining lenght as defined in MQTT v3.1 specification
|
||||
// * (section 2.1).
|
||||
// *
|
||||
// * @return the decoded length or -1 if needed more data to decode the length field.
|
||||
// */
|
||||
// static int decodeRemainingLenght(IoBuffer in) {
|
||||
// int multiplier = 1;
|
||||
// int value = 0;
|
||||
// byte digit;
|
||||
// do {
|
||||
// if (in.remaining() < 1) {
|
||||
// return -1;
|
||||
// }
|
||||
// digit = in.get();
|
||||
// value += (digit & 0x7F) * multiplier;
|
||||
// multiplier *= 128;
|
||||
// } while ((digit & 0x80) != 0);
|
||||
// return value;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Return the number of bytes to encode the gicen remaining length value
|
||||
*/
|
||||
static int numBytesToEncode(int len) {
|
||||
if (0 <= len && len <= 127) return 1;
|
||||
if (128 <= len && len <= 16383) return 2;
|
||||
if (16384 <= len && len <= 2097151) return 3;
|
||||
if (2097152 <= len && len <= 268435455) return 4;
|
||||
throw new IllegalArgumentException("value shoul be in the range [0..268435455]");
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Encode the value in the format defined in specification as variable length
|
||||
// * array.
|
||||
// *
|
||||
// * @throws IllegalArgumentException if the value is not in the specification bounds
|
||||
// * [0..268435455].
|
||||
// */
|
||||
// static IoBuffer encodeRemainingLength(int value) throws IllegalAccessException {
|
||||
// if (value > MAX_LENGTH_LIMIT || value < 0) {
|
||||
// throw new IllegalAccessException("Value should in range 0.." + MAX_LENGTH_LIMIT + " found " + value);
|
||||
// }
|
||||
//
|
||||
// IoBuffer encoded = IoBuffer.allocate(4);
|
||||
// byte digit;
|
||||
// do {
|
||||
// digit = (byte) (value % 128);
|
||||
// value = value / 128;
|
||||
// // if there are more digits to encode, set the top bit of this digit
|
||||
// if (value > 0) {
|
||||
// digit = (byte) (digit | 0x80);
|
||||
// }
|
||||
// encoded.put(digit);
|
||||
// } while (value > 0);
|
||||
// encoded.flip();
|
||||
// return encoded;
|
||||
// }
|
||||
//
|
||||
// static MessageDecoderResult checkDecodable(byte type, IoBuffer in) {
|
||||
// if (in.remaining() < 1) {
|
||||
// return MessageDecoderResult.NEED_DATA;
|
||||
// }
|
||||
// byte h1 = in.get();
|
||||
// byte messageType = (byte) ((h1 & 0x00F0) >> 4);
|
||||
//
|
||||
// int remainingLength = Utils.decodeRemainingLenght(in);
|
||||
// if (remainingLength == -1) {
|
||||
// return MessageDecoderResult.NEED_DATA;
|
||||
// }
|
||||
//
|
||||
// //check remaining length
|
||||
// if (in.remaining() < remainingLength) {
|
||||
// return MessageDecoderResult.NEED_DATA;
|
||||
// }
|
||||
//
|
||||
// return messageType == type ? MessageDecoderResult.OK : MessageDecoderResult.NOT_OK;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Return the IoBuffer with string encoded as MSB, LSB and UTF-8 encoded
|
||||
// * string content.
|
||||
// */
|
||||
// static IoBuffer encodeString(String str) {
|
||||
// IoBuffer out = IoBuffer.allocate(2).setAutoExpand(true);
|
||||
// byte[] raw;
|
||||
// try {
|
||||
// raw = str.getBytes("UTF-8");
|
||||
// //NB every Java platform has got UTF-8 encoding by default, so this
|
||||
// //exception are never raised.
|
||||
// } catch (UnsupportedEncodingException ex) {
|
||||
// LoggerFactory.getLogger(ConnectEncoder.class).error(null, ex);
|
||||
// return null;
|
||||
// }
|
||||
// Utils.writeWord(out, raw.length);
|
||||
// out.put(raw).flip();
|
||||
// return out;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * Load a string from the given buffer, reading first the two bytes of len
|
||||
// * and then the UTF-8 bytes of the string.
|
||||
// *
|
||||
// * @return the decoded string or null if NEED_DATA
|
||||
// */
|
||||
// static String decodeString(IoBuffer in) throws UnsupportedEncodingException {
|
||||
// if (in.remaining() < 2) {
|
||||
// return null;
|
||||
// }
|
||||
// int strLen = Utils.readWord(in);
|
||||
// if (in.remaining() < strLen) {
|
||||
// return null;
|
||||
// }
|
||||
// byte[] strRaw = new byte[strLen];
|
||||
// in.get(strRaw);
|
||||
//
|
||||
// return new String(strRaw, "UTF-8");
|
||||
// }
|
||||
|
||||
static byte encodeFlags(AbstractMessage message) {
|
||||
byte flags = 0;
|
||||
if (message.isDupFlag()) {
|
||||
flags |= 0x08;
|
||||
}
|
||||
if (message.isRetainFlag()) {
|
||||
flags |= 0x01;
|
||||
}
|
||||
|
||||
flags |= ((message.getQos().ordinal() & 0x03) << 1);
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts MQTT message type to a textual description.
|
||||
* */
|
||||
public static String msgType2String(int type) {
|
||||
switch (type) {
|
||||
case AbstractMessage.CONNECT: return "CONNECT";
|
||||
case AbstractMessage.CONNACK: return "CONNACK";
|
||||
case AbstractMessage.PUBLISH: return "PUBLISH";
|
||||
case AbstractMessage.PUBACK: return "PUBACK";
|
||||
case AbstractMessage.PUBREC: return "PUBREC";
|
||||
case AbstractMessage.PUBREL: return "PUBREL";
|
||||
case AbstractMessage.PUBCOMP: return "PUBCOMP";
|
||||
case AbstractMessage.SUBSCRIBE: return "SUBSCRIBE";
|
||||
case AbstractMessage.SUBACK: return "SUBACK";
|
||||
case AbstractMessage.UNSUBSCRIBE: return "UNSUBSCRIBE";
|
||||
case AbstractMessage.UNSUBACK: return "UNSUBACK";
|
||||
case AbstractMessage.PINGREQ: return "PINGREQ";
|
||||
case AbstractMessage.PINGRESP: return "PINGRESP";
|
||||
case AbstractMessage.DISCONNECT: return "DISCONNECT";
|
||||
default: throw new RuntimeException("Can't decode message type " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user